Define for CHUNK_DEBUG
[yaz-moved-to-github.git] / src / comstack.c
1 /*
2  * Copyright (c) 1995-2004, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: comstack.c,v 1.5 2004-02-19 23:20:44 adam Exp $
6  */
7
8 #include <string.h>
9 #include <ctype.h>
10 #include <errno.h>
11
12 #include <yaz/comstack.h>
13 #include <yaz/tcpip.h>
14 #include <yaz/unix.h>
15 #include <yaz/odr.h>
16
17 #ifdef WIN32
18 #define strncasecmp _strnicmp
19 #endif
20
21 static const char *cs_errlist[] =
22 {
23     "No error or unspecified error",
24     "System (lower-layer) error",
25     "Operation out of state",
26     "No data (operation would block)",
27     "New data while half of old buffer is on the line (flow control)",
28     "Permission denied",
29     "SSL error"
30 };
31
32 const char *cs_errmsg(int n)
33 {
34     static char buf[250];
35
36     if (n < CSNONE || n > CSLASTERROR) {
37         sprintf(buf, "unknown comstack error %d", n);
38         return buf;
39     }
40     if (n == CSYSERR) {
41         sprintf(buf, "%s: %s", cs_errlist[n], strerror(errno));
42         return buf;
43     }
44     return cs_errlist[n];
45 }
46
47 const char *cs_strerror(COMSTACK h)
48 {
49     return cs_errmsg(h->cerrno);
50 }
51
52 void cs_get_host_args(const char *type_and_host, const char **args)
53 {
54     
55     *args = "";
56     if (*type_and_host && strncmp(type_and_host, "unix:", 5))
57     {
58         const char *cp;
59         cp = strstr(type_and_host, "://");
60         if (cp)
61             cp = cp+3;
62         else
63             cp = type_and_host;
64         cp = strchr(cp, '/');
65         if (cp)
66             *args = cp+1;
67     }
68 }
69
70 COMSTACK cs_create_host(const char *type_and_host, int blocking, void **vp)
71 {
72     enum oid_proto proto = PROTO_Z3950;
73     const char *host = 0;
74     COMSTACK cs;
75     CS_TYPE t;
76
77     if (strncmp (type_and_host, "tcp:", 4) == 0)
78     {
79         t = tcpip_type;
80         host = type_and_host + 4;
81     }
82     else if (strncmp (type_and_host, "ssl:", 4) == 0)
83     {
84 #if HAVE_OPENSSL_SSL_H
85         t = ssl_type;
86         host = type_and_host + 4;
87 #else
88         return 0;
89 #endif
90     }
91     else if (strncmp (type_and_host, "unix:", 5) == 0)
92     {
93 #ifndef WIN32
94         t = unix_type;
95         host = type_and_host + 5;
96 #else
97         return 0;
98 #endif
99     }
100     else if (strncmp(type_and_host, "http:", 5) == 0)
101     {
102         t = tcpip_type;
103         host = type_and_host + 5;
104         if (host[0] == '/' && host[1] == '/')
105             host = host + 2;
106         proto = PROTO_HTTP;
107     }
108     else if (strncmp(type_and_host, "https:", 6) == 0)
109     {
110 #if HAVE_OPENSSL_SSL_H
111         t = ssl_type;
112         host = type_and_host + 6;
113         if (host[0] == '/' && host[1] == '/')
114             host = host + 2;
115         proto = PROTO_HTTP;
116 #else
117         return 0;
118 #endif
119     }
120     else
121     {
122         t = tcpip_type;
123         host = type_and_host;
124         
125     }
126     cs = cs_create (t, blocking, proto);
127     if (!cs)
128         return 0;
129
130     if (!(*vp = cs_straddr(cs, host)))
131     {
132         cs_close (cs);
133         return 0;
134     }    
135     return cs;
136 }
137
138 int cs_look (COMSTACK cs)
139 {
140     return cs->event;
141 }
142
143 #define CHUNK_DEBUG 0
144 int cs_complete_auto(const unsigned char *buf, int len)
145 {
146     if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
147                 && buf[1] >= 0x20 && buf[1] < 0x7f
148                 && buf[2] >= 0x20 && buf[2] < 0x7f)
149     {
150         /* deal with HTTP request/response */
151         int i = 2, content_len = 0, chunked = 0;
152
153         while (i <= len-4)
154         {
155             if (i > 8192)
156                 return i;  /* do not allow more than 8K HTTP header */
157             if (buf[i] == '\r' && buf[i+1] == '\n')
158             {
159                 i += 2;
160                 if (buf[i] == '\r' && buf[i+1] == '\n')
161                 {
162                     if (chunked)
163                     { 
164                         /* inside chunked body .. */
165                         while(1)
166                         {
167                             int chunk_len = 0;
168                             i += 2;
169 #if CHUNK_DEBUG
170 /* debugging */
171                             if (i <len-2)
172                             {
173                                 printf ("\n<<<");
174                                 int j;
175                                 for (j = i; j <= i+4; j++)
176                                     printf ("%c", buf[j]);
177                                 printf (">>>\n");
178                             }
179 #endif
180                             while (1)
181                                 if (i >= len-2) {
182 #if CHUNK_DEBUG
183 /* debugging */                                    
184                                     printf ("XXXXXXXX not there yet 1\n");
185                                     printf ("i=%d len=%d\n", i, len);
186 #endif
187                                     return 0;
188                                 } else if (isdigit(buf[i]))
189                                     chunk_len = chunk_len * 16 + 
190                                         (buf[i++] - '0');
191                                 else if (isupper(buf[i]))
192                                     chunk_len = chunk_len * 16 + 
193                                         (buf[i++] - ('A'-10));
194                                 else if (islower(buf[i]))
195                                     chunk_len = chunk_len * 16 + 
196                                         (buf[i++] - ('a'-10));
197                                 else
198                                     break;
199                             if (buf[i] != '\r' || buf[i+1] != '\n' ||
200                                 chunk_len < 0)
201                                 return i+2;    /* bad. stop now */
202 #if CHUNK_DEBUG
203                             printf ("XXXXXX chunk_len=%d\n", chunk_len);
204 #endif                      
205                             if (chunk_len == 0)
206                             {
207                                 /* consider trailing headers .. */
208                                 while(i <= len-4)
209                                 {
210                                     if (buf[i] == '\r' &&  buf[i+1] == '\n' &&
211                                         buf[i+2] == '\r' && buf[i+3] == '\n')
212                                         if (len >= i+4)
213                                             return i+4;
214                                     i++;
215                                 }
216 #if CHUNK_DEBUG
217 /* debugging */
218                                 printf ("XXXXXXXXX not there yet 2\n");
219                                 printf ("i=%d len=%d\n", i, len);
220 #endif
221                                 return 0;
222                             }
223                             i += chunk_len+2;
224                         }
225                     }
226                     else
227                     {   /* not chunked ; inside body */
228                         /* i += 2 seems not to work with GCC -O2 .. 
229                            so i+2 is used instead .. */
230                         if (len >= (i+2)+ content_len)
231                             return (i+2)+ content_len;
232                     }
233                     break;
234                 }
235                 else if (i < len - 20 && 
236                          !strncasecmp(buf+i, "Transfer-Encoding:", 18))
237                 {
238                     i+=18;
239                     while (buf[i] == ' ')
240                         i++;
241                     if (i < len - 8)
242                         if (!strncasecmp(buf+i, "chunked", 7))
243                             chunked = 1;
244                 }
245                 else if (i < len - 17 &&
246                          !strncasecmp(buf+i, "Content-Length:", 15))
247                 {
248                     i+= 15;
249                     while (buf[i] == ' ')
250                         i++;
251                     content_len = 0;
252                     while (i <= len-4 && isdigit(buf[i]))
253                         content_len = content_len*10 + (buf[i++] - '0');
254                     if (content_len < 0) /* prevent negative offsets */
255                         content_len = 0;
256                 }
257                 else
258                     i++;
259             }
260             else
261                 i++;
262         }
263         return 0;
264     }
265     return completeBER(buf, len);
266 }