Added odr_set_stream which is is a more generic to odr_setprint.
[yaz-moved-to-github.git] / src / zgdu.c
index a37a96e..fcd7be9 100644 (file)
@@ -1,18 +1,26 @@
 /*
- * Copyright (c) 2002-2003, Index Data.
+ * Copyright (c) 2002-2004, Index Data.
  * See the file LICENSE for details.
  *
- * $Id: zgdu.c,v 1.1 2003-10-27 12:21:36 adam Exp $
+ * $Id: zgdu.c,v 1.10 2004-08-11 12:15:38 adam Exp $
  */
 
+#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')
@@ -51,6 +59,10 @@ static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
         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;
@@ -62,22 +74,75 @@ 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;
-    }
-    else if (i == o->size)
-    {
-        *content_buf = 0;
-        *content_len = 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 
+    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';
+       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';
+       }
     }
     return 1;
 }
@@ -96,7 +161,7 @@ void z_HTTP_header_add(ODR o, Z_HTTP_Header **hp, const char *n,
 const char *z_HTTP_header_lookup(Z_HTTP_Header *hp, const char *n)
 {
     for (; hp; hp = hp->next)
-        if (!strcmp(hp->name, n))
+        if (!yaz_matchstr(hp->name, n))
             return hp->value;
     return 0;
 }
@@ -187,6 +252,9 @@ int z_GDU (ODR o, Z_GDU **p, int opt, const char *name)
 
             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++;
@@ -293,11 +361,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)
             {
@@ -313,9 +380,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:
@@ -332,11 +399,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)
             {
@@ -352,7 +418,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: