Added one type cast from char to unsigned char
[yaz-moved-to-github.git] / src / zgdu.c
index fa92153..0dfdbaf 100644 (file)
@@ -1,19 +1,31 @@
 /*
- * Copyright (c) 2002-2003, Index Data.
+ * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: zgdu.c,v 1.3 2003-12-30 00:29:53 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')
@@ -25,8 +37,8 @@ static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
             o->error = OHTTP;
             return 0;
         }
-       i++;
-       if (o->buf[i] == '\r')
+        i++;
+        if (o->buf[i] == '\r')
             break;
         for (po = i; ; i++)
         {
@@ -46,12 +58,16 @@ static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
         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;
@@ -63,24 +79,93 @@ static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
     }
     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,
@@ -184,10 +269,13 @@ int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
         {
             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++;
@@ -221,7 +309,7 @@ int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
             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));
 
@@ -274,7 +362,7 @@ int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
         }
         else
         {
-           (*p)->which = Z_GDU_Z3950;
+            (*p)->which = Z_GDU_Z3950;
             return z_APDU(o, &(*p)->u.z3950, opt, 0);
         }
     }
@@ -294,11 +382,10 @@ int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
             if (!z_HTTP_header_lookup((*p)->u.HTTP_Response->headers,
                                       "Content-Length"))
             {
-                char lstr[20];
-                sprintf(lstr, "%d", (*p)->u.HTTP_Response->content_len);
-                z_HTTP_header_add(o,
-                                  &(*p)->u.HTTP_Response->headers,
-                                  "Content-Length", lstr);
+                char lstr[60];
+                sprintf(lstr, "Content-Length: %d\r\n",
+                        (*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)
             {
@@ -314,9 +401,9 @@ int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
                           (*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:
@@ -333,11 +420,10 @@ int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
                 !z_HTTP_header_lookup((*p)->u.HTTP_Request->headers,
                                       "Content-Length"))
             {
-                char lstr[20];
-                sprintf(lstr, "%d", (*p)->u.HTTP_Request->content_len);
-                z_HTTP_header_add(o,
-                                  &(*p)->u.HTTP_Request->headers,
-                                  "Content-Length", lstr);
+                char lstr[60];
+                sprintf(lstr, "Content-Length: %d\r\n",
+                        (*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)
             {
@@ -353,7 +439,9 @@ int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
                           (*p)->u.HTTP_Request->content_len);
             if (o->direction == ODR_PRINT)
             {
-                fprintf(o->print, "-- HTTP request:\n%.*s\n", o->top, o->buf);
+                odr_printf(o, "-- HTTP request:\n%.*s\n", o->top - top0,
+                        o->buf + top0);
+                odr_printf(o, "-- \n");
             }
             break;
         case Z_GDU_Z3950:
@@ -363,3 +451,11 @@ int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
     return 1;
 }
 
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+