/*
- * Copyright (c) 2002-2003, Index Data.
+ * Copyright (C) 1995-2005, Index Data ApS
* See the file LICENSE for details.
*
- * $Id: zgdu.c,v 1.5 2003-12-31 00:14:01 adam Exp $
+ * $Id: zgdu.c,v 1.14 2006-03-01 23:24:25 adam Exp $
*/
+/**
+ * \file zgdu.c
+ * \brief Implements HTTP and Z39.50 encoding and decoding.
+ */
+
+#include <ctype.h>
#include <yaz/odr.h>
#include <yaz/yaz-version.h>
#include <yaz/yaz-iconv.h>
#include <yaz/zgdu.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)
{
int i = off;
+ int chunked = 0;
*headers = 0;
while (i < o->size-1 && o->buf[i] == '\r')
o->error = OHTTP;
return 0;
}
- i++;
- if (o->buf[i] == '\r')
+ i++;
+ if (o->buf[i] == '\r')
break;
for (po = i; ; i++)
{
while (i < o->size-1 && o->buf[i] == ' ')
i++;
for (po = i; i < o->size-1 && o->buf[i] != '\r' ; i++)
- ;
+ ;
(*headers)->value = (char*) odr_malloc(o, i - po + 1);
memcpy ((*headers)->value, o->buf + po, i - po);
(*headers)->value[i - po] = '\0';
+ if (!strcasecmp((*headers)->name, "Transfer-Encoding")
+ &&
+ !strcasecmp((*headers)->value, "chunked"))
+ chunked = 1;
headers = &(*headers)->next;
}
*headers = 0;
}
i++;
- if (i > o->size)
+ if (chunked)
{
- o->error = OHTTP;
- return 0;
+ int off = 0;
+
+ /* we know buffer will be smaller than o->size - i*/
+ *content_buf = (char*) odr_malloc(o, o->size - i);
+
+ while (1)
+ {
+ /* chunk length .. */
+ int chunk_len = 0;
+ for (; i < o->size-2; i++)
+ if (isdigit(o->buf[i]))
+ chunk_len = chunk_len * 16 +
+ (o->buf[i] - '0');
+ else if (isupper(o->buf[i]))
+ chunk_len = chunk_len * 16 +
+ (o->buf[i] - ('A'-10));
+ else if (islower(o->buf[i]))
+ chunk_len = chunk_len * 16 +
+ (o->buf[i] - ('a'-10));
+ else
+ break;
+ /* chunk extension ... */
+ while (o->buf[i] != '\r' && o->buf[i+1] != '\n')
+ {
+ if (i >= o->size-2)
+ {
+ o->error = OHTTP;
+ return 0;
+ }
+ i++;
+ }
+ i += 2; /* skip CRLF */
+ if (chunk_len == 0)
+ break;
+ if (chunk_len < 0 || off + chunk_len > o->size)
+ {
+ o->error = OHTTP;
+ return 0;
+ }
+ /* copy chunk .. */
+ memcpy (*content_buf + off, o->buf + i, chunk_len);
+ i += chunk_len + 2; /* skip chunk+CRLF */
+ off += chunk_len;
+ }
+ if (!off)
+ *content_buf = 0;
+ *content_len = off;
}
- else if (i == o->size)
+ else
{
- *content_buf = 0;
- *content_len = 0;
+ if (i > o->size)
+ {
+ o->error = OHTTP;
+ return 0;
+ }
+ else if (i == o->size)
+ {
+ *content_buf = 0;
+ *content_len = 0;
+ }
+ else
+ {
+ *content_len = o->size - i;
+ *content_buf = (char*) odr_malloc(o, *content_len + 1);
+ memcpy(*content_buf, o->buf + i, *content_len);
+ (*content_buf)[*content_len] = '\0';
+ }
}
- else
+ return 1;
+}
+
+void z_HTTP_header_add_content_type(ODR o, Z_HTTP_Header **hp,
+ const char *content_type,
+ const char *charset)
+{
+ const char *l = "Content-Type";
+ if (charset)
{
- *content_len = o->size - i;
- *content_buf = (char*) odr_malloc(o, *content_len + 1);
- memcpy(*content_buf, o->buf + i, *content_len);
- (*content_buf)[*content_len] = '\0';
+ char *ctype = odr_malloc(o, strlen(content_type)+strlen(charset) + 15);
+ sprintf(ctype, "%s; charset=%s", content_type, charset);
+ z_HTTP_header_add(o, hp, l, ctype);
}
- return 1;
+ else
+ z_HTTP_header_add(o, hp, l, content_type);
+
}
void z_HTTP_header_add(ODR o, Z_HTTP_Header **hp, const char *n,
{
int i, po;
Z_HTTP_Response *hr;
- (*p)->which = Z_GDU_HTTP_Response;
+ (*p)->which = Z_GDU_HTTP_Response;
hr = (*p)->u.HTTP_Response = (Z_HTTP_Response *)
odr_malloc(o, sizeof(*hr));
+ hr->content_buf = 0;
+ hr->content_len = 0;
+
po = i = 5;
while (i < o->size-2 && o->buf[i] != ' ' && o->buf[i] != '\r')
i++;
int i, po;
Z_HTTP_Request *hr;
- (*p)->which = Z_GDU_HTTP_Request;
+ (*p)->which = Z_GDU_HTTP_Request;
hr = (*p)->u.HTTP_Request =
(Z_HTTP_Request *) odr_malloc(o, sizeof(*hr));
}
else
{
- (*p)->which = Z_GDU_Z3950;
+ (*p)->which = Z_GDU_Z3950;
return z_APDU(o, &(*p)->u.z3950, opt, 0);
}
}
{
char lstr[60];
sprintf(lstr, "Content-Length: %d\r\n",
- (*p)->u.HTTP_Response->content_len);
+ (*p)->u.HTTP_Response->content_len);
odr_write(o, (unsigned char *) lstr, strlen(lstr));
}
for (h = (*p)->u.HTTP_Response->headers; h; h = h->next)
(*p)->u.HTTP_Response->content_len);
if (o->direction == ODR_PRINT)
{
- fprintf(o->print, "-- HTTP response:\n%.*s\n", o->top - top0,
- o->buf + top0);
- fprintf(o->print, "-- \n");
+ odr_printf(o, "-- HTTP response:\n%.*s\n", o->top - top0,
+ o->buf + top0);
+ odr_printf(o, "-- \n");
}
break;
case Z_GDU_HTTP_Request:
{
char lstr[60];
sprintf(lstr, "Content-Length: %d\r\n",
- (*p)->u.HTTP_Request->content_len);
+ (*p)->u.HTTP_Request->content_len);
odr_write(o, (unsigned char *) lstr, strlen(lstr));
}
for (h = (*p)->u.HTTP_Request->headers; h; h = h->next)
(*p)->u.HTTP_Request->content_len);
if (o->direction == ODR_PRINT)
{
- fprintf(o->print, "-- HTTP request:\n%.*s\n", o->top - top0,
+ odr_printf(o, "-- HTTP request:\n%.*s\n", o->top - top0,
o->buf + top0);
- fprintf(o->print, "-- \n");
+ odr_printf(o, "-- \n");
}
break;
case Z_GDU_Z3950:
return 1;
}
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+