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