/* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2012 Index Data
+ * Copyright (C) 1995-2013 Index Data
* See the file LICENSE for details.
*/
/**
#include <yaz/zgdu.h>
#include <yaz/base64.h>
-#ifdef WIN32
-#define strncasecmp _strnicmp
-#define strcasecmp _stricmp
-#endif
-
static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
char **content_buf, int *content_len)
{
memcpy ((*headers)->value, o->buf + po, i - po);
(*headers)->value[i - po] = '\0';
- if (!strcasecmp((*headers)->name, "Transfer-Encoding")
+ if (!yaz_strcasecmp((*headers)->name, "Transfer-Encoding")
&&
- !strcasecmp((*headers)->value, "chunked"))
+ !yaz_strcasecmp((*headers)->value, "chunked"))
chunked = 1;
headers = &(*headers)->next;
if (i < o->size-1 && o->buf[i] == '\r')
buf = (char *) odr_malloc(o, (len+1) * 8/6 + 12);
strcpy(buf, "Basic ");
yaz_base64encode(tmp, &buf[strlen(buf)]);
- z_HTTP_header_add(o, hp, "Authorization", buf);
+ z_HTTP_header_set(o, hp, "Authorization", buf);
}
(*hp)->next = 0;
}
+void z_HTTP_header_set(ODR o, Z_HTTP_Header **hp, const char *n,
+ const char *v)
+{
+ while (*hp)
+ {
+ if (!yaz_strcasecmp((*hp)->name, n))
+ {
+ (*hp)->value = odr_strdup(o, v);
+ return;
+ }
+ hp = &(*hp)->next;
+ }
+ *hp = (Z_HTTP_Header *) odr_malloc(o, sizeof(**hp));
+ (*hp)->name = odr_strdup(o, n);
+ (*hp)->value = odr_strdup(o, v);
+ (*hp)->next = 0;
+}
+
+const char *z_HTTP_header_remove(Z_HTTP_Header **hp, const char *n)
+{
+ while (*hp)
+ {
+ if (!yaz_strcasecmp((*hp)->name, n))
+ {
+ const char *v = (*hp)->value;
+ *hp = (*hp)->next;
+ return v;
+ }
+ hp = &(*hp)->next;
+ }
+ return 0;
+}
+
const char *z_HTTP_header_lookup(const Z_HTTP_Header *hp, const char *n)
{
for (; hp; hp = hp->next)
- if (!yaz_matchstr(hp->name, n))
+ if (!yaz_strcasecmp(hp->name, n))
return hp->value;
return 0;
}
return p;
}
-Z_GDU *z_get_HTTP_Response(ODR o, int code)
+Z_GDU *z_get_HTTP_Response_details(ODR o, int code, const char *details)
{
Z_GDU *p = (Z_GDU *) odr_malloc(o, sizeof(*p));
Z_HTTP_Response *hres;
"YAZ/" YAZ_VERSION);
if (code != 200)
{
- hres->content_buf = (char*) odr_malloc(o, 400);
+ const char *http_err = z_HTTP_errmsg(code);
+ size_t sz = 400 + strlen(http_err) + (details ?
+ strlen(details) : 0);
+ hres->content_buf = (char*) odr_malloc(o, sz);
sprintf(hres->content_buf,
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""
" \"http://www.w3.org/TR/html4/strict.dtd\">\n"
" <P><A HREF=\"http://www.indexdata.com/yaz/\">YAZ</A> "
YAZ_VERSION "</P>\n"
" <P>Error: %d</P>\n"
- " <P>Description: %.50s</P>\n"
+ " <P>Description: %s</P>\n", code, http_err);
+ if (details)
+ {
+ sprintf(hres->content_buf + strlen(hres->content_buf),
+ "<P>Details: %s</P>\n", details);
+ }
+ sprintf(hres->content_buf + strlen(hres->content_buf),
" </BODY>\n"
- "</HTML>\n",
- code, z_HTTP_errmsg(code));
+ "</HTML>\n");
hres->content_len = strlen(hres->content_buf);
z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
}
return p;
}
+Z_GDU *z_get_HTTP_Response(ODR o, int code)
+{
+ return z_get_HTTP_Response_details(o, code, 0);
+}
+
const char *z_HTTP_errmsg(int code)
{
- if (code == 200)
+ switch (code)
+ {
+ case 100:
+ return "Continue";
+ case 101:
+ return "Switching Protocols";
+ case 200:
return "OK";
- else if (code == 400)
+ case 201:
+ return "Created";
+ case 202:
+ return "Accepted";
+ case 203:
+ return "Non-Authoritative Information";
+ case 204:
+ return "No Content";
+ case 205:
+ return "Reset Content";
+ case 206:
+ return "Partial Content";
+ case 300:
+ return "Multiple Choices";
+ case 301:
+ return "Moved Permenently";
+ case 302:
+ return "Found";
+ case 303:
+ return "See Other";
+ case 304:
+ return "Not Modified";
+ case 305:
+ return "Use Proxy";
+ case 307:
+ return "Temporary Redirect";
+ case 400:
return "Bad Request";
- else if (code == 404)
+ case 404:
return "Not Found";
- else if (code == 405)
+ case 405:
return "Method Not Allowed";
- else if (code == 500)
+ case 406:
+ return "Not Acceptable";
+ case 407:
+ return "Proxy Authentication Required";
+ case 408:
+ return "Request Timeout";
+ case 409:
+ return "Conflict";
+ case 410:
+ return "Gone";
+ case 411:
+ return "Length Required";
+ case 412:
+ return "Precondition Failed";
+ case 413:
+ return "Request Entity Too Large";
+ case 414:
+ return "Request-URI Too Long";
+ case 415:
+ return "Unsupported Media Type";
+ case 416:
+ return "Requested Range Not Satisfiable";
+ case 417:
+ return "Expectation Failed";
+ case 500:
return "Internal Error";
- else
+ case 501:
+ return "Not Implemented";
+ case 502:
+ return "Bad Gateway";
+ case 503:
+ return "Service Unavailable";
+ case 504:
+ return "Gateway Timeout";
+ case 505:
+ return "HTTP Version Not Supported";
+ default:
return "Unknown Error";
+ }
}
int yaz_decode_http_response(ODR o, Z_HTTP_Response **hr_p)
&hr->content_buf, &hr->content_len);
}
+static void dump_http_package(ODR o, const char *buf, size_t len)
+{
+ int i;
+ for (i = 0; ; i++)
+ {
+ if (i == len)
+ {
+ odr_printf(o, "%.*s\n", i, buf);
+ break;
+ }
+ else if (i > 8192)
+ {
+ odr_printf(o, "%.*s\n", i, buf);
+ odr_printf(o, "(truncated\n", (long) len);
+ break;
+ }
+ else if (buf[i] == 0)
+ {
+ odr_printf(o, "%.*s\n", i, buf);
+ odr_printf(o, "(binary data)\n", (long) len);
+ break;
+ }
+ }
+}
+
int yaz_encode_http_response(ODR o, Z_HTTP_Response *hr)
{
char sbuf[80];
sprintf(sbuf, "HTTP/%s %d %s\r\n", hr->version,
hr->code,
z_HTTP_errmsg(hr->code));
- odr_write(o, (unsigned char *) sbuf, strlen(sbuf));
- /* apply Content-Length if not already applied */
- if (!z_HTTP_header_lookup(hr->headers,
- "Content-Length"))
- {
- char lstr[60];
- sprintf(lstr, "Content-Length: %d\r\n",
- hr->content_len);
- odr_write(o, (unsigned char *) lstr, strlen(lstr));
- }
+ odr_write2(o, sbuf, strlen(sbuf));
+ /* use content_len for Content-Length */
+ sprintf(sbuf, "Content-Length: %d\r\n", hr->content_len);
+ odr_write2(o, sbuf, strlen(sbuf));
for (h = hr->headers; h; h = h->next)
{
- odr_write(o, (unsigned char *) h->name, strlen(h->name));
- odr_write(o, (unsigned char *) ": ", 2);
- odr_write(o, (unsigned char *) h->value, strlen(h->value));
- odr_write(o, (unsigned char *) "\r\n", 2);
+ if (yaz_strcasecmp(h->name, "Content-Length")
+ && yaz_strcasecmp(h->name, "Transfer-Encoding"))
+ { /* skip Content-Length if given. content_len rules */
+ odr_write2(o, h->name, strlen(h->name));
+ odr_write2(o, ": ", 2);
+ odr_write2(o, h->value, strlen(h->value));
+ odr_write2(o, "\r\n", 2);
+ }
}
odr_write(o, (unsigned char *) "\r\n", 2);
if (hr->content_buf)
- odr_write(o, (unsigned char *)
- hr->content_buf,
- hr->content_len);
+ odr_write2(o, hr->content_buf, hr->content_len);
if (o->direction == ODR_PRINT)
{
- odr_printf(o, "-- HTTP response:\n%.*s\n", o->top - top0,
- o->buf + top0);
- odr_printf(o, "-- \n");
+ odr_printf(o, "-- HTTP response:\n");
+ dump_http_package(o, (const char *) o->buf + top0, o->top - top0);
+ odr_printf(o, "--\n");
}
return 1;
}
Z_HTTP_Header *h;
int top0 = o->top;
- odr_write(o, (unsigned char *) hr->method,
- strlen(hr->method));
- odr_write(o, (unsigned char *) " ", 1);
- odr_write(o, (unsigned char *) hr->path,
- strlen(hr->path));
- odr_write(o, (unsigned char *) " HTTP/", 6);
- odr_write(o, (unsigned char *) hr->version,
- strlen(hr->version));
- odr_write(o, (unsigned char *) "\r\n", 2);
+ odr_write2(o, hr->method, strlen(hr->method));
+ odr_write2(o, " ", 1);
+ odr_write2(o, hr->path, strlen(hr->path));
+ odr_write2(o, " HTTP/", 6);
+ odr_write2(o, hr->version, strlen(hr->version));
+ odr_write2(o, "\r\n", 2);
if (hr->content_len &&
!z_HTTP_header_lookup(hr->headers,
"Content-Length"))
char lstr[60];
sprintf(lstr, "Content-Length: %d\r\n",
hr->content_len);
- odr_write(o, (unsigned char *) lstr, strlen(lstr));
+ odr_write2(o, lstr, strlen(lstr));
}
for (h = hr->headers; h; h = h->next)
{
- odr_write(o, (unsigned char *) h->name, strlen(h->name));
- odr_write(o, (unsigned char *) ": ", 2);
- odr_write(o, (unsigned char *) h->value, strlen(h->value));
- odr_write(o, (unsigned char *) "\r\n", 2);
+ odr_write2(o, h->name, strlen(h->name));
+ odr_write2(o, ": ", 2);
+ odr_write2(o, h->value, strlen(h->value));
+ odr_write2(o, "\r\n", 2);
}
- odr_write(o, (unsigned char *) "\r\n", 2);
+ odr_write2(o, "\r\n", 2);
if (hr->content_buf)
- odr_write(o, (unsigned char *)
- hr->content_buf,
- hr->content_len);
+ odr_write2(o, hr->content_buf, hr->content_len);
if (o->direction == ODR_PRINT)
{
- odr_printf(o, "-- HTTP request:\n%.*s\n", o->top - top0,
- o->buf + top0);
- odr_printf(o, "-- \n");
+ odr_printf(o, "-- HTTP request:\n");
+ dump_http_package(o, (const char *) o->buf + top0, o->top - top0);
+ odr_printf(o, "--\n");
}
return 1;
}