1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2011 Index Data
3 * See the file LICENSE for details.
7 * \brief Implements HTTP decoding
14 #include <yaz/yaz-version.h>
15 #include <yaz/yaz-iconv.h>
16 #include <yaz/matchstr.h>
20 #define strncasecmp _strnicmp
21 #define strcasecmp _stricmp
26 * This function's counterpart, yaz_base64decode(), is in srwutil.c.
27 * I feel bad that they're not together, but each function is only
28 * needed in one place, and those places are not together. Maybe one
29 * day we'll move them into a new httputil.c, and declare them in a
30 * corresponding httputil.h
32 static void yaz_base64encode(const char *in, char *out)
34 static char encoding[] =
35 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
52 /* Treat three eight-bit numbers as on 24-bit number */
53 n = (buf[0] << 16) + (buf[1] << 8) + buf[2];
55 /* Write the six-bit chunks out as four encoded characters */
56 *out++ = encoding[(n >> 18) & 63];
57 *out++ = encoding[(n >> 12) & 63];
59 *out++ = encoding[(n >> 6) & 63];
60 if (in[1] != 0 && in[2] != 0)
61 *out++ = encoding[n & 63];
75 static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
76 char **content_buf, int *content_len)
82 while (i < o->size-1 && o->buf[i] == '\n')
86 if (o->buf[i] == '\r' && i < o->size-1 && o->buf[i+1] == '\n')
91 if (o->buf[i] == '\n')
100 else if (o->buf[i] == ':')
103 *headers = (Z_HTTP_Header *) odr_malloc(o, sizeof(**headers));
104 (*headers)->name = (char*) odr_malloc(o, i - po + 1);
105 memcpy ((*headers)->name, o->buf + po, i - po);
106 (*headers)->name[i - po] = '\0';
108 while (i < o->size-1 && o->buf[i] == ' ')
110 for (po = i; i < o->size-1 && !strchr("\r\n", o->buf[i]); i++)
113 (*headers)->value = (char*) odr_malloc(o, i - po + 1);
114 memcpy ((*headers)->value, o->buf + po, i - po);
115 (*headers)->value[i - po] = '\0';
117 if (!strcasecmp((*headers)->name, "Transfer-Encoding")
119 !strcasecmp((*headers)->value, "chunked"))
121 headers = &(*headers)->next;
122 if (i < o->size-1 && o->buf[i] == '\r')
126 if (o->buf[i] != '\n')
137 /* we know buffer will be smaller than o->size - i*/
138 *content_buf = (char*) odr_malloc(o, o->size - i);
142 /* chunk length .. */
144 for (; i < o->size-2; i++)
145 if (yaz_isdigit(o->buf[i]))
146 chunk_len = chunk_len * 16 +
148 else if (yaz_isupper(o->buf[i]))
149 chunk_len = chunk_len * 16 +
150 (o->buf[i] - ('A'-10));
151 else if (yaz_islower(o->buf[i]))
152 chunk_len = chunk_len * 16 +
153 (o->buf[i] - ('a'-10));
156 /* chunk extension ... */
157 while (o->buf[i] != '\r' && o->buf[i+1] != '\n')
166 i += 2; /* skip CRLF */
169 if (chunk_len < 0 || off + chunk_len > o->size)
175 memcpy (*content_buf + off, o->buf + i, chunk_len);
176 i += chunk_len + 2; /* skip chunk+CRLF */
190 else if (i == o->size)
197 *content_len = o->size - i;
198 *content_buf = (char*) odr_malloc(o, *content_len + 1);
199 memcpy(*content_buf, o->buf + i, *content_len);
200 (*content_buf)[*content_len] = '\0';
206 void z_HTTP_header_add_content_type(ODR o, Z_HTTP_Header **hp,
207 const char *content_type,
210 const char *l = "Content-Type";
213 char *ctype = (char *)
214 odr_malloc(o, strlen(content_type)+strlen(charset) + 15);
215 sprintf(ctype, "%s; charset=%s", content_type, charset);
216 z_HTTP_header_add(o, hp, l, ctype);
219 z_HTTP_header_add(o, hp, l, content_type);
224 * HTTP Basic authentication is described at:
225 * http://tools.ietf.org/html/rfc1945#section-11.1
227 void z_HTTP_header_add_basic_auth(ODR o, Z_HTTP_Header **hp,
228 const char *username, const char *password)
238 len = strlen(username) + strlen(password);
239 tmp = (char *) odr_malloc(o, len+2);
240 sprintf(tmp, "%s:%s", username, password);
241 buf = (char *) odr_malloc(o, (len+1) * 8/6 + 12);
242 strcpy(buf, "Basic ");
243 yaz_base64encode(tmp, &buf[strlen(buf)]);
244 z_HTTP_header_add(o, hp, "Authorization", buf);
248 void z_HTTP_header_add(ODR o, Z_HTTP_Header **hp, const char *n,
253 *hp = (Z_HTTP_Header *) odr_malloc(o, sizeof(**hp));
254 (*hp)->name = odr_strdup(o, n);
255 (*hp)->value = odr_strdup(o, v);
259 const char *z_HTTP_header_lookup(const Z_HTTP_Header *hp, const char *n)
261 for (; hp; hp = hp->next)
262 if (!yaz_matchstr(hp->name, n))
268 Z_GDU *z_get_HTTP_Request(ODR o)
270 Z_GDU *p = (Z_GDU *) odr_malloc(o, sizeof(*p));
271 Z_HTTP_Request *hreq;
273 p->which = Z_GDU_HTTP_Request;
274 p->u.HTTP_Request = (Z_HTTP_Request *) odr_malloc(o, sizeof(*hreq));
275 hreq = p->u.HTTP_Request;
277 hreq->content_len = 0;
278 hreq->content_buf = 0;
279 hreq->version = "1.1";
280 hreq->method = "POST";
282 z_HTTP_header_add(o, &hreq->headers, "User-Agent", "YAZ/" YAZ_VERSION);
287 Z_GDU *z_get_HTTP_Request_host_path(ODR odr,
291 Z_GDU *p = z_get_HTTP_Request(odr);
293 p->u.HTTP_Request->path = odr_strdup(odr, path);
297 const char *cp0 = strstr(host, "://");
304 cp1 = strchr(cp0, '/');
306 cp1 = cp0+strlen(cp0);
310 char *h = (char*) odr_malloc(odr, cp1 - cp0 + 1);
311 memcpy (h, cp0, cp1 - cp0);
313 z_HTTP_header_add(odr, &p->u.HTTP_Request->headers,
321 Z_GDU *z_get_HTTP_Response(ODR o, int code)
323 Z_GDU *p = (Z_GDU *) odr_malloc(o, sizeof(*p));
324 Z_HTTP_Response *hres;
326 p->which = Z_GDU_HTTP_Response;
327 p->u.HTTP_Response = (Z_HTTP_Response *) odr_malloc(o, sizeof(*hres));
328 hres = p->u.HTTP_Response;
330 hres->content_len = 0;
331 hres->content_buf = 0;
333 hres->version = "1.1";
334 z_HTTP_header_add(o, &hres->headers, "Server",
338 hres->content_buf = (char*) odr_malloc(o, 400);
339 sprintf(hres->content_buf,
340 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""
341 " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
344 " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
347 " <P><A HREF=\"http://www.indexdata.com/yaz/\">YAZ</A> "
349 " <P>Error: %d</P>\n"
350 " <P>Description: %.50s</P>\n"
353 code, z_HTTP_errmsg(code));
354 hres->content_len = strlen(hres->content_buf);
355 z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
360 const char *z_HTTP_errmsg(int code)
364 else if (code == 400)
365 return "Bad Request";
366 else if (code == 404)
368 else if (code == 405)
369 return "Method Not Allowed";
370 else if (code == 500)
371 return "Internal Error";
373 return "Unknown Error";
376 int yaz_decode_http_response(ODR o, Z_HTTP_Response **hr_p)
379 Z_HTTP_Response *hr = (Z_HTTP_Response *) odr_malloc(o, sizeof(*hr));
386 while (i < o->size-2 && !strchr(" \r\n", o->buf[i]))
388 hr->version = (char *) odr_malloc(o, i - po + 1);
390 memcpy(hr->version, o->buf + po, i - po);
391 hr->version[i-po] = 0;
392 if (o->buf[i] != ' ')
399 while (i < o->size-2 && o->buf[i] >= '0' && o->buf[i] <= '9')
401 hr->code = hr->code*10 + (o->buf[i] - '0');
404 while (i < o->size-1 && o->buf[i] != '\n')
406 return decode_headers_content(o, i, &hr->headers,
407 &hr->content_buf, &hr->content_len);
410 int yaz_decode_http_request(ODR o, Z_HTTP_Request **hr_p)
413 Z_HTTP_Request *hr = (Z_HTTP_Request *) odr_malloc(o, sizeof(*hr));
418 for (i = 0; o->buf[i] != ' '; i++)
419 if (i >= o->size-5 || i > 30)
424 hr->method = (char *) odr_malloc(o, i+1);
425 memcpy (hr->method, o->buf, i);
426 hr->method[i] = '\0';
429 for (i = po; o->buf[i] != ' '; i++)
435 hr->path = (char *) odr_malloc(o, i - po + 1);
436 memcpy (hr->path, o->buf+po, i - po);
437 hr->path[i - po] = '\0';
440 if (i > o->size-5 || memcmp(o->buf+i, "HTTP/", 5))
447 while (i < o->size && !strchr("\r\n", o->buf[i]))
449 hr->version = (char *) odr_malloc(o, i - po + 1);
450 memcpy(hr->version, o->buf + po, i - po);
451 hr->version[i - po] = '\0';
453 if (i < o->size-1 && o->buf[i] == '\r')
455 if (o->buf[i] != '\n')
460 return decode_headers_content(o, i, &hr->headers,
461 &hr->content_buf, &hr->content_len);
464 int yaz_encode_http_response(ODR o, Z_HTTP_Response *hr)
470 sprintf(sbuf, "HTTP/%s %d %s\r\n", hr->version,
472 z_HTTP_errmsg(hr->code));
473 odr_write(o, (unsigned char *) sbuf, strlen(sbuf));
474 /* apply Content-Length if not already applied */
475 if (!z_HTTP_header_lookup(hr->headers,
479 sprintf(lstr, "Content-Length: %d\r\n",
481 odr_write(o, (unsigned char *) lstr, strlen(lstr));
483 for (h = hr->headers; h; h = h->next)
485 odr_write(o, (unsigned char *) h->name, strlen(h->name));
486 odr_write(o, (unsigned char *) ": ", 2);
487 odr_write(o, (unsigned char *) h->value, strlen(h->value));
488 odr_write(o, (unsigned char *) "\r\n", 2);
490 odr_write(o, (unsigned char *) "\r\n", 2);
492 odr_write(o, (unsigned char *)
495 if (o->direction == ODR_PRINT)
497 odr_printf(o, "-- HTTP response:\n%.*s\n", o->top - top0,
499 odr_printf(o, "-- \n");
504 int yaz_encode_http_request(ODR o, Z_HTTP_Request *hr)
509 odr_write(o, (unsigned char *) hr->method,
511 odr_write(o, (unsigned char *) " ", 1);
512 odr_write(o, (unsigned char *) hr->path,
514 odr_write(o, (unsigned char *) " HTTP/", 6);
515 odr_write(o, (unsigned char *) hr->version,
516 strlen(hr->version));
517 odr_write(o, (unsigned char *) "\r\n", 2);
518 if (hr->content_len &&
519 !z_HTTP_header_lookup(hr->headers,
523 sprintf(lstr, "Content-Length: %d\r\n",
525 odr_write(o, (unsigned char *) lstr, strlen(lstr));
527 for (h = hr->headers; h; h = h->next)
529 odr_write(o, (unsigned char *) h->name, strlen(h->name));
530 odr_write(o, (unsigned char *) ": ", 2);
531 odr_write(o, (unsigned char *) h->value, strlen(h->value));
532 odr_write(o, (unsigned char *) "\r\n", 2);
534 odr_write(o, (unsigned char *) "\r\n", 2);
536 odr_write(o, (unsigned char *)
539 if (o->direction == ODR_PRINT)
541 odr_printf(o, "-- HTTP request:\n%.*s\n", o->top - top0,
543 odr_printf(o, "-- \n");
551 * c-file-style: "Stroustrup"
552 * indent-tabs-mode: nil
554 * vim: shiftwidth=4 tabstop=8 expandtab