Use _strnicmp on Windows
[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.4 2004-01-06 20:21:37 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 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                         while(1)
164                         {
165                             int chunk_len = 0;
166                             i += 2;
167 #if 0
168 /* debugging */
169                             if (i <len-2)
170                             {
171                                 printf ("\n>>>");
172                                 for (j = i; j <= i+4; j++)
173                                     printf ("%c", buf[j]);
174                                 printf ("<<<\n");
175                             }
176 #endif
177                             while (1)
178                                 if (i >= len-2) {
179 #if 0
180 /* debugging */                                    
181                                     printf ("XXXXXXXX not there yet 1\n");
182                                     printf ("i=%d len=%d\n", i, len);
183 #endif
184                                     return 0;
185                                 } else if (isdigit(buf[i]))
186                                     chunk_len = chunk_len * 16 + 
187                                         (buf[i++] - '0');
188                                 else if (isupper(buf[i]))
189                                     chunk_len = chunk_len * 16 + 
190                                         (buf[i++] - ('A'-10));
191                                 else if (islower(buf[i]))
192                                     chunk_len = chunk_len * 16 + 
193                                         (buf[i++] - ('a'-10));
194                                 else
195                                     break;
196                             if (buf[i] != '\r' || buf[i+1] != '\n' ||
197                                 chunk_len < 0)
198                                 return i+2;    /* bad. stop now */
199                             if (chunk_len == 0)
200                             {
201                                 /* consider trailing headers .. */
202                                 while(i <= len-4)
203                                 {
204                                     if (buf[i] == '\r' &&  buf[i+1] == '\n' &&
205                                         buf[i+2] == '\r' && buf[i+3] == '\n')
206                                         if (len >= i+4)
207                                             return i+4;
208                                     i++;
209                                 }
210 #if 0
211 /* debugging */
212                                 printf ("XXXXXXXXX not there yet 2\n");
213                                 printf ("i=%d len=%d\n", i, len);
214 #endif
215                                 return 0;
216                             }
217                             i += chunk_len+2;
218                         }
219                     }
220                     else
221                     {   /* not chunked ; inside body */
222                         /* i += 2 seems not to work with GCC -O2 .. 
223                            so i+2 is used instead .. */
224                         if (len >= (i+2)+ content_len)
225                             return (i+2)+ content_len;
226                     }
227                     break;
228                 }
229                 else if (i < len - 20 && 
230                          !strncasecmp(buf+i, "Transfer-Encoding:", 18))
231                 {
232                     i+=18;
233                     while (buf[i] == ' ')
234                         i++;
235                     if (i < len - 8)
236                         if (!strncasecmp(buf+i, "chunked", 7))
237                             chunked = 1;
238                 }
239                 else if (i < len - 17 &&
240                          !strncasecmp(buf+i, "Content-Length:", 15))
241                 {
242                     i+= 15;
243                     while (buf[i] == ' ')
244                         i++;
245                     content_len = 0;
246                     while (i <= len-4 && isdigit(buf[i]))
247                         content_len = content_len*10 + (buf[i++] - '0');
248                     if (content_len < 0) /* prevent negative offsets */
249                         content_len = 0;
250                 }
251                 else
252                     i++;
253             }
254             else
255                 i++;
256         }
257         return 0;
258     }
259     return completeBER(buf, len);
260 }