Added skeleton for query charset conversion. Bug #977.
[yaz-moved-to-github.git] / src / comstack.c
index 68aeb67..db3b002 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 1995-2005, Index Data ApS
+ * Copyright (C) 1995-2007, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: comstack.c,v 1.15 2005-06-25 15:46:03 adam Exp $
+ * $Id: comstack.c,v 1.18 2007-01-11 10:30:41 adam Exp $
  */
 
 /** 
@@ -14,6 +14,7 @@
 #include <ctype.h>
 #include <errno.h>
 
+#include <yaz/log.h>
 #include <yaz/comstack.h>
 #include <yaz/tcpip.h>
 #include <yaz/unix.h>
@@ -31,7 +32,8 @@ static const char *cs_errlist[] =
     "No data (operation would block)",
     "New data while half of old buffer is on the line (flow control)",
     "Permission denied",
-    "SSL error"
+    "SSL error",
+    "Too large incoming buffer"
 };
 
 const char *cs_errmsg(int n)
@@ -144,151 +146,189 @@ int cs_look (COMSTACK cs)
     return cs->event;
 }
 
-#define CHUNK_DEBUG 0
-int cs_complete_auto(const unsigned char *buf, int len)
+static int skip_crlf(const char *buf, int len, int *i)
 {
-    if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
-                && buf[1] >= 0x20 && buf[1] < 0x7f
-                && buf[2] >= 0x20 && buf[2] < 0x7f)
+    if (*i < len)
     {
-        /* deal with HTTP request/response */
-        int i = 2, content_len = 0, chunked = 0;
-        
-        /* if dealing with HTTP responses - then default
-           content length is unlimited (socket close) */
-        if (!memcmp(buf, "HTTP/", 5))
-            content_len = -1; 
+        if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
+        {
+            (*i) += 2;
+            return 1;
+        }
+        else if (buf[*i] == '\n')
+        {
+            (*i)++;
+            return 1;
+        }
+    }
+    return 0;
+}
+
+#define CHUNK_DEBUG 0
+
+int cs_complete_http(const char *buf, int len)
+{
+    /* deal with HTTP request/response */
+    int i = 2, content_len = 0, chunked = 0;
 
-        while (i <= len-4)
+    if (len < 6)
+        return 0;
+
+    /* if dealing with HTTP responses - then default
+       content length is unlimited (socket close) */
+    if (!memcmp(buf, "HTTP/", 5))
+        content_len = -1; 
+
+#if 0
+    printf("len = %d\n", len);
+    fwrite (buf, 1, len, stdout);
+    printf("----------\n");
+#endif
+    while (i <= len-2)
+    {
+        if (i > 8192)
         {
-            if (i > 8192)
-            {
-                return i;  /* do not allow more than 8K HTTP header */
-            }
-            if (buf[i] == '\r' && buf[i+1] == '\n')
+            return i;  /* do not allow more than 8K HTTP header */
+        }
+        if (skip_crlf(buf, len, &i))
+        {
+            if (skip_crlf(buf, len, &i))
             {
-                i += 2;
-                if (buf[i] == '\r' && buf[i+1] == '\n')
-                {
-                    if (chunked)
-                    { 
-                        /* inside chunked body .. */
-                        while(1)
-                        {
-                            int j, chunk_len = 0;
-                            i += 2;
+                /* inside content */
+                if (chunked)
+                { 
+                    /* inside chunked body .. */
+                    while(1)
+                    {
+                        int chunk_len = 0;
 #if CHUNK_DEBUG
-/* debugging */
-                            if (i <len-2)
-                            {
-                                printf ("\n<<<");
-                                int j;
-                                for (j = i; j <= i+4; j++)
-                                    printf ("%c", buf[j]);
-                                printf (">>>\n");
-                            }
+                        if (i < len-2)
+                        {
+                            printf ("\n<<<");
+                            int j;
+                            for (j = i; j <= i+3; j++)
+                                printf ("%c", buf[j]);
+                            printf (">>>\n");
+                        }
 #endif
-                            /* read chunk length */
-                            while (1)
-                                if (i >= len-2) {
+                        /* read chunk length */
+                        while (1)
+                            if (i >= len-2) {
 #if CHUNK_DEBUG
-/* debugging */                                    
-                                    printf ("XXXXXXXX not there yet 1\n");
-                                    printf ("i=%d len=%d\n", i, len);
+                                printf ("returning incomplete read at 1\n");
+                                printf ("i=%d len=%d\n", i, len);
 #endif
-                                    return 0;
-                                } else if (isdigit(buf[i]))
-                                    chunk_len = chunk_len * 16 + 
-                                        (buf[i++] - '0');
-                                else if (isupper(buf[i]))
-                                    chunk_len = chunk_len * 16 + 
-                                        (buf[i++] - ('A'-10));
-                                else if (islower(buf[i]))
-                                    chunk_len = chunk_len * 16 + 
-                                        (buf[i++] - ('a'-10));
-                                else
-                                    break;
-                            /* move forward until CRLF - skip chunk ext */
-                            j = 0;
-                            while (buf[i] != '\r' && buf[i+1] != '\n')
-                            {
-                                if (i >= len-2)
-                                    return 0;   /* need more buffer .. */
-                                if (++j > 1000)
-                                    return i; /* enough.. stop */
-                                i++;
-                            }
-                            /* got CRLF */
-#if CHUNK_DEBUG
-                            printf ("XXXXXX chunk_len=%d\n", chunk_len);
-#endif                      
-                            if (chunk_len < 0)
-                                return i+2;    /* bad chunk_len */
-                            if (chunk_len == 0)
+                                return 0;
+                            } else if (isdigit(buf[i]))
+                                chunk_len = chunk_len * 16 + 
+                                    (buf[i++] - '0');
+                            else if (isupper(buf[i]))
+                                chunk_len = chunk_len * 16 + 
+                                    (buf[i++] - ('A'-10));
+                            else if (islower(buf[i]))
+                                chunk_len = chunk_len * 16 + 
+                                    (buf[i++] - ('a'-10));
+                            else
                                 break;
-                            i += chunk_len+2;
-                        }
-                        /* consider trailing headers .. */
-                        while(i <= len-4)
+                        if (chunk_len == 0)
+                            break;
+                        if (chunk_len < 0)
+                            return i;
+                        
+                        while (1)
                         {
-                            if (buf[i] == '\r' &&  buf[i+1] == '\n' &&
-                                buf[i+2] == '\r' && buf[i+3] == '\n')
-                                if (len >= i+4)
-                                    return i+4;
+                            if (i >= len -1)
+                                return 0;
+                            if (skip_crlf(buf, len, &i))
+                                break;
                             i++;
                         }
+                        /* got CRLF */
 #if CHUNK_DEBUG
-/* debugging */
-                        printf ("XXXXXXXXX not there yet 2\n");
-                        printf ("i=%d len=%d\n", i, len);
-#endif
-                        return 0;
+                        printf ("chunk_len=%d\n", chunk_len);
+#endif                      
+                        i += chunk_len;
+                        if (i >= len-2)
+                            return 0;
+                        if (!skip_crlf(buf, len, &i))
+                            return 0;
                     }
-                    else
-                    {   /* not chunked ; inside body */
-                        /* i += 2 seems not to work with GCC -O2 .. 
-                           so i+2 is used instead .. */
-                        if (content_len == -1)
-                            return 0;   /* no content length */
-                        else if (len >= (i+2)+ content_len)
+                    /* consider trailing headers .. */
+                    while (i < len)
+                    {
+                        if (skip_crlf(buf, len, &i))
                         {
-                            return (i+2)+ content_len;
+                            if (skip_crlf(buf, len, &i))
+                                return i;
                         }
+                        else
+                            i++;
                     }
-                    break;
-                }
-                else if (i < len - 20 && 
-                         !strncasecmp((const char *) buf+i, "Transfer-Encoding:", 18))
-                {
-                    i+=18;
-                    while (buf[i] == ' ')
-                        i++;
-                    if (i < len - 8)
-                        if (!strncasecmp((const char *) buf+i, "chunked", 7))
-                            chunked = 1;
-                }
-                else if (i < len - 17 &&
-                         !strncasecmp((const char *)buf+i, "Content-Length:", 15))
-                {
-                    i+= 15;
-                    while (buf[i] == ' ')
-                        i++;
-                    content_len = 0;
-                    while (i <= len-4 && isdigit(buf[i]))
-                        content_len = content_len*10 + (buf[i++] - '0');
-                    if (content_len < 0) /* prevent negative offsets */
-                        content_len = 0;
+#if CHUNK_DEBUG
+                    printf ("returning incomplete read at 2\n");
+                    printf ("i=%d len=%d\n", i, len);
+#endif
+                    return 0;
                 }
                 else
+                {   /* not chunked ; inside body */
+                    if (content_len == -1)
+                        return 0;   /* no content length */
+                    else if (len >= i + content_len)
+                    {
+                        return i + content_len;
+                    }
+                }
+                break;
+            }
+            else if (i < len - 20 && 
+                     !strncasecmp((const char *) buf+i, "Transfer-Encoding:", 18))
+            {
+                i+=18;
+                while (buf[i] == ' ')
                     i++;
+                if (i < len - 8)
+                    if (!strncasecmp((const char *) buf+i, "chunked", 7))
+                        chunked = 1;
+            }
+            else if (i < len - 17 &&
+                     !strncasecmp((const char *)buf+i, "Content-Length:", 15))
+            {
+                i+= 15;
+                while (buf[i] == ' ')
+                    i++;
+                content_len = 0;
+                while (i <= len-4 && isdigit(buf[i]))
+                    content_len = content_len*10 + (buf[i++] - '0');
+                if (content_len < 0) /* prevent negative offsets */
+                    content_len = 0;
             }
             else
                 i++;
         }
-        return 0;
+        else
+            i++;
+    }
+    return 0;
+}
+
+int cs_complete_auto(const unsigned char *buf, int len)
+{
+    if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
+                && buf[1] >= 0x20 && buf[1] < 0x7f
+                && buf[2] >= 0x20 && buf[2] < 0x7f)
+    {
+        int r = cs_complete_http((const char *) buf, len);
+        return r;
     }
     return completeBER(buf, len);
 }
+
+void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
+{
+    cs->max_recv_bytes = max_recv_bytes;
+}
+
 /*
  * Local variables:
  * c-basic-offset: 4