Reinsert initialiser for __UNUSED_loglevel
[yaz-moved-to-github.git] / src / comstack.c
index 4d842f7..68aeb67 100644 (file)
@@ -1,18 +1,28 @@
 /*
- * Copyright (c) 1995-2003, Index Data
+ * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: comstack.c,v 1.1 2003-10-27 12:21:30 adam Exp $
+ * $Id: comstack.c,v 1.15 2005-06-25 15:46:03 adam Exp $
+ */
+
+/** 
+ * \file comstack.c
+ * \brief Implements Generic COMSTACK functions
  */
 
 #include <string.h>
 #include <ctype.h>
+#include <errno.h>
 
 #include <yaz/comstack.h>
 #include <yaz/tcpip.h>
 #include <yaz/unix.h>
 #include <yaz/odr.h>
 
+#ifdef WIN32
+#define strncasecmp _strnicmp
+#endif
+
 static const char *cs_errlist[] =
 {
     "No error or unspecified error",
@@ -26,8 +36,16 @@ static const char *cs_errlist[] =
 
 const char *cs_errmsg(int n)
 {
-    if (n < 0 || n > 6)
-       n = 0;
+    static char buf[250];
+
+    if (n < CSNONE || n > CSLASTERROR) {
+        sprintf(buf, "unknown comstack error %d", n);
+        return buf;
+    }
+    if (n == CSYSERR) {
+        sprintf(buf, "%s: %s", cs_errlist[n], strerror(errno));
+        return buf;
+    }
     return cs_errlist[n];
 }
 
@@ -63,61 +81,60 @@ COMSTACK cs_create_host(const char *type_and_host, int blocking, void **vp)
 
     if (strncmp (type_and_host, "tcp:", 4) == 0)
     {
-       t = tcpip_type;
+        t = tcpip_type;
         host = type_and_host + 4;
     }
     else if (strncmp (type_and_host, "ssl:", 4) == 0)
     {
 #if HAVE_OPENSSL_SSL_H
-       t = ssl_type;
+        t = ssl_type;
         host = type_and_host + 4;
 #else
-       return 0;
+        return 0;
 #endif
     }
     else if (strncmp (type_and_host, "unix:", 5) == 0)
     {
 #ifndef WIN32
-       t = unix_type;
+        t = unix_type;
         host = type_and_host + 5;
 #else
-       return 0;
+        return 0;
 #endif
     }
     else if (strncmp(type_and_host, "http:", 5) == 0)
     {
-       t = tcpip_type;
+        t = tcpip_type;
         host = type_and_host + 5;
-        if (host[0] == '/' && host[1] == '/')
-            host = host + 2;
+        while (host[0] == '/')
+            host++;
         proto = PROTO_HTTP;
     }
     else if (strncmp(type_and_host, "https:", 6) == 0)
     {
 #if HAVE_OPENSSL_SSL_H
-       t = ssl_type;
+        t = ssl_type;
         host = type_and_host + 6;
-        if (host[0] == '/' && host[1] == '/')
-            host = host + 2;
+        while (host[0] == '/')
+            host++;
         proto = PROTO_HTTP;
 #else
-       return 0;
+        return 0;
 #endif
     }
     else
     {
-       t = tcpip_type;
-       host = type_and_host;
-        
+        t = tcpip_type;
+        host = type_and_host;
     }
     cs = cs_create (t, blocking, proto);
     if (!cs)
-       return 0;
+        return 0;
 
     if (!(*vp = cs_straddr(cs, host)))
     {
-       cs_close (cs);
-       return 0;
+        cs_close (cs);
+        return 0;
     }    
     return cs;
 }
@@ -127,19 +144,27 @@ int cs_look (COMSTACK cs)
     return cs->event;
 }
 
+#define CHUNK_DEBUG 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)
+                && buf[1] >= 0x20 && buf[1] < 0x7f
+                && buf[2] >= 0x20 && buf[2] < 0x7f)
     {
         /* deal with HTTP request/response */
-       int i = 2, content_len = 0, chunked = 0;
+        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; 
 
         while (i <= len-4)
         {
-           if (i > 8192)
-               return i;  /* do not allow more than 8K HTTP header */
+            if (i > 8192)
+            {
+                return i;  /* do not allow more than 8K HTTP header */
+            }
             if (buf[i] == '\r' && buf[i+1] == '\n')
             {
                 i += 2;
@@ -147,23 +172,26 @@ int cs_complete_auto(const unsigned char *buf, int len)
                 {
                     if (chunked)
                     { 
+                        /* inside chunked body .. */
                         while(1)
                         {
-                            int chunk_len = 0;
+                            int j, chunk_len = 0;
                             i += 2;
-#if 0
+#if CHUNK_DEBUG
 /* debugging */
                             if (i <len-2)
                             {
-                                printf ("\n>>>");
+                                printf ("\n<<<");
+                                int j;
                                 for (j = i; j <= i+4; j++)
                                     printf ("%c", buf[j]);
-                                printf ("<<<\n");
+                                printf (">>>\n");
                             }
 #endif
+                            /* read chunk length */
                             while (1)
                                 if (i >= len-2) {
-#if 0
+#if CHUNK_DEBUG
 /* debugging */                                    
                                     printf ("XXXXXXXX not there yet 1\n");
                                     printf ("i=%d len=%d\n", i, len);
@@ -180,54 +208,70 @@ int cs_complete_auto(const unsigned char *buf, int len)
                                         (buf[i++] - ('a'-10));
                                 else
                                     break;
-                            if (buf[i] != '\r' || buf[i+1] != '\n' ||
-                                chunk_len < 0)
-                                return i+2;    /* bad. stop now */
-                            if (chunk_len == 0)
+                            /* move forward until CRLF - skip chunk ext */
+                            j = 0;
+                            while (buf[i] != '\r' && buf[i+1] != '\n')
                             {
-                                /* consider trailing headers .. */
-                                while(i <= len-4)
-                                {
-                                    if (buf[i] == '\r' &&  buf[i+1] == '\n' &&
-                                        buf[i+2] == '\r' && buf[i+3] == '\n')
-                                        if (len >= i+4)
-                                            return i+4;
-                                    i++;
-                                }
-#if 0
-/* debugging */
-                                printf ("XXXXXXXXX not there yet 2\n");
-                                printf ("i=%d len=%d\n", i, len);
-#endif
-                                return 0;
+                                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)
+                                break;
                             i += chunk_len+2;
                         }
+                        /* consider trailing headers .. */
+                        while(i <= len-4)
+                        {
+                            if (buf[i] == '\r' &&  buf[i+1] == '\n' &&
+                                buf[i+2] == '\r' && buf[i+3] == '\n')
+                                if (len >= i+4)
+                                    return i+4;
+                            i++;
+                        }
+#if CHUNK_DEBUG
+/* debugging */
+                        printf ("XXXXXXXXX not there yet 2\n");
+                        printf ("i=%d len=%d\n", i, len);
+#endif
+                        return 0;
                     }
                     else
                     {   /* not chunked ; inside body */
                         /* i += 2 seems not to work with GCC -O2 .. 
                            so i+2 is used instead .. */
-                        if (len >= (i+2)+ content_len)
+                        if (content_len == -1)
+                            return 0;   /* no content length */
+                        else if (len >= (i+2)+ content_len)
+                        {
                             return (i+2)+ content_len;
+                        }
                     }
                     break;
                 }
-                else if (i < len - 21 &&
-                         !memcmp(buf+i, "Transfer-Encoding: ", 18))
+                else if (i < len - 20 && 
+                         !strncasecmp((const char *) buf+i, "Transfer-Encoding:", 18))
                 {
                     i+=18;
-                    if (buf[i] == ' ')
+                    while (buf[i] == ' ')
                         i++;
                     if (i < len - 8)
-                        if (!memcmp(buf+i, "chunked", 7))
+                        if (!strncasecmp((const char *) buf+i, "chunked", 7))
                             chunked = 1;
                 }
-                else if (i < len - 18 &&
-                         !memcmp(buf+i, "Content-Length: ", 15))
+                else if (i < len - 17 &&
+                         !strncasecmp((const char *)buf+i, "Content-Length:", 15))
                 {
                     i+= 15;
-                    if (buf[i] == ' ')
+                    while (buf[i] == ' ')
                         i++;
                     content_len = 0;
                     while (i <= len-4 && isdigit(buf[i]))
@@ -245,3 +289,11 @@ int cs_complete_auto(const unsigned char *buf, int len)
     }
     return completeBER(buf, len);
 }
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+