2 * Copyright (c) 2002-2003, Index Data.
3 * See the file LICENSE for details.
5 * $Id: zgdu.c,v 1.6 2004-02-19 23:21:44 adam Exp $
9 #include <yaz/yaz-version.h>
10 #include <yaz/yaz-iconv.h>
13 static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
14 char **content_buf, int *content_len)
20 while (i < o->size-1 && o->buf[i] == '\r')
24 if (o->buf[i] != '\n')
30 if (o->buf[i] == '\r')
39 else if (o->buf[i] == ':')
42 *headers = (Z_HTTP_Header *) odr_malloc(o, sizeof(**headers));
43 (*headers)->name = (char*) odr_malloc(o, i - po + 1);
44 memcpy ((*headers)->name, o->buf + po, i - po);
45 (*headers)->name[i - po] = '\0';
47 while (i < o->size-1 && o->buf[i] == ' ')
49 for (po = i; i < o->size-1 && o->buf[i] != '\r' ; i++)
52 (*headers)->value = (char*) odr_malloc(o, i - po + 1);
53 memcpy ((*headers)->value, o->buf + po, i - po);
54 (*headers)->value[i - po] = '\0';
56 if (!strcasecmp((*headers)->name, "Transfer-Encoding")
58 !strcasecmp((*headers)->value, "chunked"))
60 headers = &(*headers)->next;
64 if (o->buf[i] != '\n')
75 /* we know buffer will be smaller than o->size - i - 2*/
76 *content_buf = (char*) odr_malloc(o, o->size - i - 2);
81 for (; i < o->size-2; i++)
82 if (isdigit(o->buf[i]))
83 chunk_len = chunk_len * 16 +
85 else if (isupper(o->buf[i]))
86 chunk_len = chunk_len * 16 +
87 (o->buf[i] - ('A'-10));
88 else if (islower(o->buf[i]))
89 chunk_len = chunk_len * 16 +
90 (o->buf[i] - ('a'-10));
95 if (o->buf[i] != '\r' || o->buf[i+1] != '\n')
96 { /* chunk length must be followed by \r\n */
103 if (chunk_len < 0 || off + chunk_len > o->size)
108 memcpy (*content_buf + off, o->buf + i, chunk_len);
123 else if (i == o->size)
130 *content_len = o->size - i;
131 *content_buf = (char*) odr_malloc(o, *content_len + 1);
132 memcpy(*content_buf, o->buf + i, *content_len);
133 (*content_buf)[*content_len] = '\0';
139 void z_HTTP_header_add(ODR o, Z_HTTP_Header **hp, const char *n,
144 *hp = (Z_HTTP_Header *) odr_malloc(o, sizeof(**hp));
145 (*hp)->name = odr_strdup(o, n);
146 (*hp)->value = odr_strdup(o, v);
150 const char *z_HTTP_header_lookup(Z_HTTP_Header *hp, const char *n)
152 for (; hp; hp = hp->next)
153 if (!yaz_matchstr(hp->name, n))
159 Z_GDU *z_get_HTTP_Request(ODR o)
161 Z_GDU *p = (Z_GDU *) odr_malloc(o, sizeof(*p));
162 Z_HTTP_Request *hreq;
164 p->which = Z_GDU_HTTP_Request;
165 p->u.HTTP_Request = (Z_HTTP_Request *) odr_malloc(o, sizeof(*hreq));
166 hreq = p->u.HTTP_Request;
168 hreq->content_len = 0;
169 hreq->content_buf = 0;
170 hreq->version = "1.1";
171 hreq->method = "POST";
173 z_HTTP_header_add(o, &hreq->headers, "User-Agent",
178 Z_GDU *z_get_HTTP_Response(ODR o, int code)
180 Z_GDU *p = (Z_GDU *) odr_malloc(o, sizeof(*p));
181 Z_HTTP_Response *hres;
183 p->which = Z_GDU_HTTP_Response;
184 p->u.HTTP_Response = (Z_HTTP_Response *) odr_malloc(o, sizeof(*hres));
185 hres = p->u.HTTP_Response;
187 hres->content_len = 0;
188 hres->content_buf = 0;
190 hres->version = "1.1";
191 z_HTTP_header_add(o, &hres->headers, "Server",
195 hres->content_buf = (char*) odr_malloc(o, 400);
196 sprintf (hres->content_buf,
197 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
200 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
203 " <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> "
205 " <P>Error: %d</P>\n"
206 " <P>Description: %.50s</P>\n"
209 code, z_HTTP_errmsg(code));
210 hres->content_len = strlen(hres->content_buf);
211 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
216 const char *z_HTTP_errmsg(int code)
220 else if (code == 400)
221 return "Bad Request";
222 else if (code == 404)
224 else if (code == 405)
225 return "Method Not Allowed";
226 else if (code == 500)
227 return "Internal Error";
229 return "Unknown Error";
232 int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
234 if (o->direction == ODR_DECODE) {
235 *p = (Z_GDU *) odr_malloc(o, sizeof(**p));
236 if (o->size > 10 && !memcmp(o->buf, "HTTP/", 5))
240 (*p)->which = Z_GDU_HTTP_Response;
242 hr = (*p)->u.HTTP_Response = (Z_HTTP_Response *)
243 odr_malloc(o, sizeof(*hr));
245 while (i < o->size-2 && o->buf[i] != ' ' && o->buf[i] != '\r')
247 hr->version = (char *) odr_malloc(o, i - po + 1);
249 memcpy(hr->version, o->buf + po, i - po);
250 hr->version[i-po] = 0;
251 if (o->buf[i] != ' ')
258 while (i < o->size-2 && o->buf[i] >= '0' && o->buf[i] <= '9')
260 hr->code = hr->code*10 + (o->buf[i] - '0');
263 while (i < o->size-1 && o->buf[i] != '\r')
265 return decode_headers_content(o, i, &hr->headers,
266 &hr->content_buf, &hr->content_len);
268 else if (o->size > 5 &&
269 o->buf[0] >= 0x20 && o->buf[0] < 0x7f
270 && o->buf[1] >= 0x20 && o->buf[1] < 0x7f
271 && o->buf[2] >= 0x20 && o->buf[2] < 0x7f
272 && o->buf[3] >= 0x20 && o->buf[3] < 0x7f)
277 (*p)->which = Z_GDU_HTTP_Request;
278 hr = (*p)->u.HTTP_Request =
279 (Z_HTTP_Request *) odr_malloc(o, sizeof(*hr));
282 for (i = 0; o->buf[i] != ' '; i++)
283 if (i >= o->size-5 || i > 30)
288 hr->method = (char *) odr_malloc(o, i+1);
289 memcpy (hr->method, o->buf, i);
290 hr->method[i] = '\0';
293 for (i = po; o->buf[i] != ' '; i++)
299 hr->path = (char *) odr_malloc(o, i - po + 1);
300 memcpy (hr->path, o->buf+po, i - po);
301 hr->path[i - po] = '\0';
304 if (i > o->size-5 || memcmp(o->buf+i, "HTTP/", 5))
311 while (o->buf[i] != '\r')
320 hr->version = (char *) odr_malloc(o, i - po + 1);
321 memcpy(hr->version, o->buf + po, i - po);
322 hr->version[i - po] = '\0';
324 return decode_headers_content(o, i, &hr->headers,
325 &hr->content_buf, &hr->content_len);
330 (*p)->which = Z_GDU_Z3950;
331 return z_APDU(o, &(*p)->u.z3950, opt, 0);
334 else /* ENCODE or PRINT */
341 case Z_GDU_HTTP_Response:
342 sprintf(sbuf, "HTTP/%s %d %s\r\n", (*p)->u.HTTP_Response->version,
343 (*p)->u.HTTP_Response->code,
344 z_HTTP_errmsg((*p)->u.HTTP_Response->code));
345 odr_write(o, (unsigned char *) sbuf, strlen(sbuf));
346 /* apply Content-Length if not already applied */
347 if (!z_HTTP_header_lookup((*p)->u.HTTP_Response->headers,
351 sprintf(lstr, "Content-Length: %d\r\n",
352 (*p)->u.HTTP_Response->content_len);
353 odr_write(o, (unsigned char *) lstr, strlen(lstr));
355 for (h = (*p)->u.HTTP_Response->headers; h; h = h->next)
357 odr_write(o, (unsigned char *) h->name, strlen(h->name));
358 odr_write(o, (unsigned char *) ": ", 2);
359 odr_write(o, (unsigned char *) h->value, strlen(h->value));
360 odr_write(o, (unsigned char *) "\r\n", 2);
362 odr_write(o, (unsigned char *) "\r\n", 2);
363 if ((*p)->u.HTTP_Response->content_buf)
364 odr_write(o, (unsigned char *)
365 (*p)->u.HTTP_Response->content_buf,
366 (*p)->u.HTTP_Response->content_len);
367 if (o->direction == ODR_PRINT)
369 fprintf(o->print, "-- HTTP response:\n%.*s\n", o->top - top0,
371 fprintf(o->print, "-- \n");
374 case Z_GDU_HTTP_Request:
375 odr_write(o, (unsigned char *) (*p)->u.HTTP_Request->method,
376 strlen((*p)->u.HTTP_Request->method));
377 odr_write(o, (unsigned char *) " ", 1);
378 odr_write(o, (unsigned char *) (*p)->u.HTTP_Request->path,
379 strlen((*p)->u.HTTP_Request->path));
380 odr_write(o, (unsigned char *) " HTTP/", 6);
381 odr_write(o, (unsigned char *) (*p)->u.HTTP_Request->version,
382 strlen((*p)->u.HTTP_Request->version));
383 odr_write(o, (unsigned char *) "\r\n", 2);
384 if ((*p)->u.HTTP_Request->content_len &&
385 !z_HTTP_header_lookup((*p)->u.HTTP_Request->headers,
389 sprintf(lstr, "Content-Length: %d\r\n",
390 (*p)->u.HTTP_Request->content_len);
391 odr_write(o, (unsigned char *) lstr, strlen(lstr));
393 for (h = (*p)->u.HTTP_Request->headers; h; h = h->next)
395 odr_write(o, (unsigned char *) h->name, strlen(h->name));
396 odr_write(o, (unsigned char *) ": ", 2);
397 odr_write(o, (unsigned char *) h->value, strlen(h->value));
398 odr_write(o, (unsigned char *) "\r\n", 2);
400 odr_write(o, (unsigned char *) "\r\n", 2);
401 if ((*p)->u.HTTP_Request->content_buf)
402 odr_write(o, (unsigned char *)
403 (*p)->u.HTTP_Request->content_buf,
404 (*p)->u.HTTP_Request->content_len);
405 if (o->direction == ODR_PRINT)
407 fprintf(o->print, "-- HTTP request:\n%.*s\n", o->top - top0,
409 fprintf(o->print, "-- \n");
413 return z_APDU(o, &(*p)->u.z3950, opt, 0);