Added a few casts
[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.10 2004-05-03 09:00:50 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         while (host[0] == '/')
105             host++;
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         while (host[0] == '/')
114             host++;
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     cs = cs_create (t, blocking, proto);
126     if (!cs)
127         return 0;
128
129     if (!(*vp = cs_straddr(cs, host)))
130     {
131         cs_close (cs);
132         return 0;
133     }    
134     return cs;
135 }
136
137 int cs_look (COMSTACK cs)
138 {
139     return cs->event;
140 }
141
142 #define CHUNK_DEBUG 0
143 int cs_complete_auto(const unsigned char *buf, int len)
144 {
145     if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
146                 && buf[1] >= 0x20 && buf[1] < 0x7f
147                 && buf[2] >= 0x20 && buf[2] < 0x7f)
148     {
149         /* deal with HTTP request/response */
150         int i = 2, content_len = 0, chunked = 0;
151
152         while (i <= len-4)
153         {
154             if (i > 8192)
155                 return i;  /* do not allow more than 8K HTTP header */
156             if (buf[i] == '\r' && buf[i+1] == '\n')
157             {
158                 i += 2;
159                 if (buf[i] == '\r' && buf[i+1] == '\n')
160                 {
161                     if (chunked)
162                     { 
163                         /* inside chunked body .. */
164                         while(1)
165                         {
166                             int j, chunk_len = 0;
167                             i += 2;
168 #if CHUNK_DEBUG
169 /* debugging */
170                             if (i <len-2)
171                             {
172                                 printf ("\n<<<");
173                                 int j;
174                                 for (j = i; j <= i+4; j++)
175                                     printf ("%c", buf[j]);
176                                 printf (">>>\n");
177                             }
178 #endif
179                             /* read chunk length */
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                             /* move forward until CRLF - skip chunk ext */
200                             j = 0;
201                             while (buf[i] != '\r' && buf[i+1] != '\n')
202                             {
203                                 if (i >= len-2)
204                                     return 0;   /* need more buffer .. */
205                                 if (++j > 1000)
206                                     return i; /* enough.. stop */
207                                 i++;
208                             }
209                             /* got CRLF */
210 #if CHUNK_DEBUG
211                             printf ("XXXXXX chunk_len=%d\n", chunk_len);
212 #endif                      
213                             if (chunk_len < 0)
214                                 return i+2;    /* bad chunk_len */
215                             if (chunk_len == 0)
216                                 break;
217                             i += chunk_len+2;
218                         }
219                         /* consider trailing headers .. */
220                         while(i <= len-4)
221                         {
222                             if (buf[i] == '\r' &&  buf[i+1] == '\n' &&
223                                 buf[i+2] == '\r' && buf[i+3] == '\n')
224                                 if (len >= i+4)
225                                     return i+4;
226                             i++;
227                         }
228 #if CHUNK_DEBUG
229 /* debugging */
230                         printf ("XXXXXXXXX not there yet 2\n");
231                         printf ("i=%d len=%d\n", i, len);
232 #endif
233                         return 0;
234                     }
235                     else
236                     {   /* not chunked ; inside body */
237                         /* i += 2 seems not to work with GCC -O2 .. 
238                            so i+2 is used instead .. */
239                         if (len >= (i+2)+ content_len)
240                             return (i+2)+ content_len;
241                     }
242                     break;
243                 }
244                 else if (i < len - 20 && 
245                          !strncasecmp((const char *) buf+i, "Transfer-Encoding:", 18))
246                 {
247                     i+=18;
248                     while (buf[i] == ' ')
249                         i++;
250                     if (i < len - 8)
251                         if (!strncasecmp((const char *) buf+i, "chunked", 7))
252                             chunked = 1;
253                 }
254                 else if (i < len - 17 &&
255                          !strncasecmp((const char *)buf+i, "Content-Length:", 15))
256                 {
257                     i+= 15;
258                     while (buf[i] == ' ')
259                         i++;
260                     content_len = 0;
261                     while (i <= len-4 && isdigit(buf[i]))
262                         content_len = content_len*10 + (buf[i++] - '0');
263                     if (content_len < 0) /* prevent negative offsets */
264                         content_len = 0;
265                 }
266                 else
267                     i++;
268             }
269             else
270                 i++;
271         }
272         return 0;
273     }
274     return completeBER(buf, len);
275 }