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