Fix several compile warnings
[yaz-moved-to-github.git] / src / zgdu.c
1 /*
2  * Copyright (c) 2002-2003, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: zgdu.c,v 1.3 2003-12-30 00:29:53 adam Exp $
6  */
7
8 #include <yaz/odr.h>
9 #include <yaz/yaz-version.h>
10 #include <yaz/yaz-iconv.h>
11 #include <yaz/zgdu.h>
12
13 static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
14                                   char **content_buf, int *content_len)
15 {
16     int i = off;
17
18     *headers = 0;
19     while (i < o->size-1 && o->buf[i] == '\r')
20     {
21         int po;
22         i++;
23         if (o->buf[i] != '\n')
24         {
25             o->error = OHTTP;
26             return 0;
27         }
28         i++;
29         if (o->buf[i] == '\r')
30             break;
31         for (po = i; ; i++)
32         {
33             if (i == o->size)
34             {
35                 o->error = OHTTP;
36                 return 0;
37             }
38             else if (o->buf[i] == ':')
39                 break;
40         }
41         *headers = (Z_HTTP_Header *) odr_malloc(o, sizeof(**headers));
42         (*headers)->name = (char*) odr_malloc(o, i - po + 1);
43         memcpy ((*headers)->name, o->buf + po, i - po);
44         (*headers)->name[i - po] = '\0';
45         i++;
46         while (i < o->size-1 && o->buf[i] == ' ')
47             i++;
48         for (po = i; i < o->size-1 && o->buf[i] != '\r' ; i++)
49             ;
50         
51         (*headers)->value = (char*) odr_malloc(o, i - po + 1);
52         memcpy ((*headers)->value, o->buf + po, i - po);
53         (*headers)->value[i - po] = '\0';
54         
55         headers = &(*headers)->next;
56     }
57     *headers = 0;
58     i++;
59     if (o->buf[i] != '\n')
60     {
61         o->error = OHTTP;
62         return 0;
63     }
64     i++;
65
66     if (i > o->size)
67     {
68         o->error = OHTTP;
69         return 0;
70     }
71     else if (i == o->size)
72     {
73         *content_buf = 0;
74         *content_len = 0;
75     }
76     else 
77     {
78         *content_len = o->size - i;
79         *content_buf = (char*) odr_malloc(o, *content_len + 1);
80         memcpy(*content_buf, o->buf + i, *content_len);
81         (*content_buf)[*content_len] = '\0';
82     }
83     return 1;
84 }
85
86 void z_HTTP_header_add(ODR o, Z_HTTP_Header **hp, const char *n,
87                        const char *v)
88 {
89     while (*hp)
90         hp = &(*hp)->next;
91     *hp = (Z_HTTP_Header *) odr_malloc(o, sizeof(**hp));
92     (*hp)->name = odr_strdup(o, n);
93     (*hp)->value = odr_strdup(o, v);
94     (*hp)->next = 0;
95 }
96
97 const char *z_HTTP_header_lookup(Z_HTTP_Header *hp, const char *n)
98 {
99     for (; hp; hp = hp->next)
100         if (!yaz_matchstr(hp->name, n))
101             return hp->value;
102     return 0;
103 }
104
105
106 Z_GDU *z_get_HTTP_Request(ODR o)
107 {
108     Z_GDU *p = (Z_GDU *) odr_malloc(o, sizeof(*p));
109     Z_HTTP_Request *hreq;
110
111     p->which = Z_GDU_HTTP_Request;
112     p->u.HTTP_Request = (Z_HTTP_Request *) odr_malloc(o, sizeof(*hreq));
113     hreq = p->u.HTTP_Request;
114     hreq->headers = 0;
115     hreq->content_len = 0;
116     hreq->content_buf = 0;
117     hreq->version = "1.1";
118     hreq->method = "POST";
119     hreq->path = "/";
120     z_HTTP_header_add(o, &hreq->headers, "User-Agent",
121                       "YAZ/" YAZ_VERSION);
122     return p;
123 }
124
125 Z_GDU *z_get_HTTP_Response(ODR o, int code)
126 {
127     Z_GDU *p = (Z_GDU *) odr_malloc(o, sizeof(*p));
128     Z_HTTP_Response *hres;
129
130     p->which = Z_GDU_HTTP_Response;
131     p->u.HTTP_Response = (Z_HTTP_Response *) odr_malloc(o, sizeof(*hres));
132     hres = p->u.HTTP_Response;
133     hres->headers = 0;
134     hres->content_len = 0;
135     hres->content_buf = 0;
136     hres->code = code;
137     hres->version = "1.1";
138     z_HTTP_header_add(o, &hres->headers, "Server",
139                       "YAZ/" YAZ_VERSION);
140     if (code != 200)
141     {
142         hres->content_buf = (char*) odr_malloc(o, 400);
143         sprintf (hres->content_buf, 
144                  "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
145                  "<HTML>\n"
146                  " <HEAD>\n"
147                  "  <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
148                  " </HEAD>\n"
149                  " <BODY>\n"
150                  "  <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> " 
151                  YAZ_VERSION "</P>\n"
152                  "  <P>Error: %d</P>\n"
153                  "  <P>Description: %.50s</P>\n"
154                  " </BODY>\n"
155                  "</HTML>\n",
156                  code, z_HTTP_errmsg(code));
157         hres->content_len = strlen(hres->content_buf);
158         z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
159     }
160     return p;
161 }
162
163 const char *z_HTTP_errmsg(int code)
164 {
165     if (code == 200)
166         return "OK";
167     else if (code == 400)
168         return "Bad Request";
169     else if (code == 404)
170         return "Not Found";
171     else if (code == 405)
172         return "Method Not Allowed";
173     else if (code == 500)
174         return "Internal Error";
175     else
176         return "Unknown Error";
177 }
178
179 int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
180 {
181     if (o->direction == ODR_DECODE) {
182         *p = (Z_GDU *) odr_malloc(o, sizeof(**p));
183         if (o->size > 10 && !memcmp(o->buf, "HTTP/", 5))
184         {
185             int i, po;
186             Z_HTTP_Response *hr;
187             (*p)->which = Z_GDU_HTTP_Response;
188
189             hr = (*p)->u.HTTP_Response = (Z_HTTP_Response *)
190                 odr_malloc(o, sizeof(*hr));
191             po = i = 5;
192             while (i < o->size-2 && o->buf[i] != ' ' && o->buf[i] != '\r')
193                 i++;
194             hr->version = (char *) odr_malloc(o, i - po + 1);
195             if (i - po)
196                 memcpy(hr->version, o->buf + po, i - po);
197             hr->version[i-po] = 0;
198             if (o->buf[i] != ' ')
199             {
200                 o->error = OHTTP;
201                 return 0;
202             }
203             i++;
204             hr->code = 0;
205             while (i < o->size-2 && o->buf[i] >= '0' && o->buf[i] <= '9')
206             {
207                 hr->code = hr->code*10 + (o->buf[i] - '0');
208                 i++;
209             }
210             while (i < o->size-1 && o->buf[i] != '\r')
211                 i++;
212             return decode_headers_content(o, i, &hr->headers,
213                                           &hr->content_buf, &hr->content_len);            
214         }
215         else if (o->size > 5 &&
216             o->buf[0] >= 0x20 && o->buf[0] < 0x7f
217             && o->buf[1] >= 0x20 && o->buf[1] < 0x7f
218             && o->buf[2] >= 0x20 && o->buf[2] < 0x7f
219             && o->buf[3] >= 0x20 && o->buf[3] < 0x7f)
220         {
221             int i, po;
222             Z_HTTP_Request *hr;
223
224             (*p)->which = Z_GDU_HTTP_Request;
225             hr = (*p)->u.HTTP_Request = 
226                 (Z_HTTP_Request *) odr_malloc(o, sizeof(*hr));
227
228             /* method .. */
229             for (i = 0; o->buf[i] != ' '; i++)
230                 if (i >= o->size-5 || i > 30)
231                 {
232                     o->error = OHTTP;
233                     return 0;
234                 }
235             hr->method = (char *) odr_malloc(o, i+1);
236             memcpy (hr->method, o->buf, i);
237             hr->method[i] = '\0';
238             /* path */
239             po = i+1;
240             for (i = po; o->buf[i] != ' '; i++)
241                 if (i >= o->size-5)
242                 {
243                     o->error = OHTTP;
244                     return 0;
245                 }
246             hr->path = (char *) odr_malloc(o, i - po + 1);
247             memcpy (hr->path, o->buf+po, i - po);
248             hr->path[i - po] = '\0';
249             /* HTTP version */
250             i++;
251             if (i > o->size-5 || memcmp(o->buf+i, "HTTP/", 5))
252             {
253                 o->error = OHTTP;
254                 return 0;
255             }
256             i+= 5;
257             po = i;
258             while (o->buf[i] != '\r')
259             {
260                 if (i >= o->size-1)
261                 {
262                     o->error = OHTTP;
263                     return 0;
264                 }
265                 i++;
266             }
267             hr->version = (char *) odr_malloc(o, i - po + 1);
268             memcpy(hr->version, o->buf + po, i - po);
269             hr->version[i - po] = '\0';
270             /* headers */
271             return decode_headers_content(o, i, &hr->headers,
272                                           &hr->content_buf, &hr->content_len);
273
274         }
275         else
276         {
277             (*p)->which = Z_GDU_Z3950;
278             return z_APDU(o, &(*p)->u.z3950, opt, 0);
279         }
280     }
281     else /* ENCODE or PRINT */
282     {
283         int top0 = o->top;
284         char sbuf[80];
285         Z_HTTP_Header *h;
286         switch((*p)->which)
287         {
288         case Z_GDU_HTTP_Response:
289             sprintf(sbuf, "HTTP/%s %d %s\r\n", (*p)->u.HTTP_Response->version,
290                     (*p)->u.HTTP_Response->code,
291                     z_HTTP_errmsg((*p)->u.HTTP_Response->code));
292             odr_write(o, (unsigned char *) sbuf, strlen(sbuf));
293             /* apply Content-Length if not already applied */
294             if (!z_HTTP_header_lookup((*p)->u.HTTP_Response->headers,
295                                       "Content-Length"))
296             {
297                 char lstr[20];
298                 sprintf(lstr, "%d", (*p)->u.HTTP_Response->content_len);
299                 z_HTTP_header_add(o,
300                                   &(*p)->u.HTTP_Response->headers,
301                                   "Content-Length", lstr);
302             }
303             for (h = (*p)->u.HTTP_Response->headers; h; h = h->next)
304             {
305                 odr_write(o, (unsigned char *) h->name, strlen(h->name));
306                 odr_write(o, (unsigned char *) ": ", 2);
307                 odr_write(o, (unsigned char *) h->value, strlen(h->value));
308                 odr_write(o, (unsigned char *) "\r\n", 2);
309             }
310             odr_write(o, (unsigned char *) "\r\n", 2);
311             if ((*p)->u.HTTP_Response->content_buf)
312                 odr_write(o, (unsigned char *) 
313                           (*p)->u.HTTP_Response->content_buf,
314                           (*p)->u.HTTP_Response->content_len);
315             if (o->direction == ODR_PRINT)
316             {
317                 fprintf(o->print, "-- HTTP response:\n%.*s\n", o->top - top0,
318                         o->buf + top0);
319                 fprintf(o->print, "-- \n");
320             }
321             break;
322         case Z_GDU_HTTP_Request:
323             odr_write(o, (unsigned char *) (*p)->u.HTTP_Request->method,
324                       strlen((*p)->u.HTTP_Request->method));
325             odr_write(o, (unsigned char *) " ", 1);
326             odr_write(o, (unsigned char *) (*p)->u.HTTP_Request->path,
327                       strlen((*p)->u.HTTP_Request->path));
328             odr_write(o, (unsigned char *) " HTTP/", 6);
329             odr_write(o, (unsigned char *) (*p)->u.HTTP_Request->version,
330                       strlen((*p)->u.HTTP_Request->version));
331             odr_write(o, (unsigned char *) "\r\n", 2);
332             if ((*p)->u.HTTP_Request->content_len &&
333                 !z_HTTP_header_lookup((*p)->u.HTTP_Request->headers,
334                                       "Content-Length"))
335             {
336                 char lstr[20];
337                 sprintf(lstr, "%d", (*p)->u.HTTP_Request->content_len);
338                 z_HTTP_header_add(o,
339                                   &(*p)->u.HTTP_Request->headers,
340                                   "Content-Length", lstr);
341             }
342             for (h = (*p)->u.HTTP_Request->headers; h; h = h->next)
343             {
344                 odr_write(o, (unsigned char *) h->name, strlen(h->name));
345                 odr_write(o, (unsigned char *) ": ", 2);
346                 odr_write(o, (unsigned char *) h->value, strlen(h->value));
347                 odr_write(o, (unsigned char *) "\r\n", 2);
348             }
349             odr_write(o, (unsigned char *) "\r\n", 2);
350             if ((*p)->u.HTTP_Request->content_buf)
351                 odr_write(o, (unsigned char *)
352                           (*p)->u.HTTP_Request->content_buf,
353                           (*p)->u.HTTP_Request->content_len);
354             if (o->direction == ODR_PRINT)
355             {
356                 fprintf(o->print, "-- HTTP request:\n%.*s\n", o->top, o->buf);
357             }
358             break;
359         case Z_GDU_Z3950:
360             return z_APDU(o, &(*p)->u.z3950, opt, 0);
361         }
362     }
363     return 1;
364 }
365