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