1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
7 * \brief Implements Generic COMSTACK functions
16 #include <yaz/yaz-iconv.h>
18 #include <yaz/comstack.h>
19 #include <yaz/tcpip.h>
22 #include <yaz/matchstr.h>
24 static const char *cs_errlist[] =
26 "No error or unspecified error",
27 "System (lower-layer) error",
28 "Operation out of state",
29 "No data (operation would block)",
30 "New data while half of old buffer is on the line (flow control)",
33 "Too large incoming buffer"
36 const char *cs_errmsg(int n)
38 if (n < CSNONE || n > CSLASTERROR)
43 const char *cs_strerror(COMSTACK h)
45 return cs_errmsg(h->cerrno);
48 void cs_get_host_args(const char *type_and_host, const char **args)
51 if (!strncmp(type_and_host, "unix:", 5))
53 const char *cp = strchr(type_and_host + 5, ':');
55 type_and_host = cp + 1;
57 type_and_host += strlen(type_and_host); /* empty string */
61 const char *cp = strchr(type_and_host, '/');
64 if (cp > type_and_host && !memcmp(cp - 1, "://", 3))
65 cp = strchr(cp + 2, '/');
72 int cs_parse_host(const char *uri, const char **host,
73 CS_TYPE *t, enum oid_proto *proto,
79 if (strncmp(uri, "connect:", 8) == 0)
81 const char *cp = strchr(uri, ',');
88 *connect_host = (char *) xmalloc(len + 1);
89 memcpy(*connect_host, uri, len);
90 (*connect_host)[len] = '\0';
94 else if (strncmp(uri, "unix:", 5) == 0)
99 cp = strchr(uri, ':');
102 size_t len = cp - uri;
103 *connect_host = (char *) xmalloc(len + 1);
104 memcpy(*connect_host, uri, len);
105 (*connect_host)[len] = '\0';
109 xfree(*connect_host);
117 if (strncmp (uri, "tcp:", 4) == 0)
120 *proto = PROTO_Z3950;
122 else if (strncmp (uri, "ssl:", 4) == 0)
127 *proto = PROTO_Z3950;
129 xfree(*connect_host);
134 else if (strncmp(uri, "http:", 5) == 0)
137 while (**host == '/')
141 else if (strncmp(uri, "https:", 6) == 0)
146 while (**host == '/')
150 xfree(*connect_host);
158 *proto = PROTO_Z3950;
163 COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
165 return cs_create_host_proxy(vhost, blocking, vp, 0);
168 COMSTACK cs_create_host_proxy(const char *vhost, int blocking, void **vp,
169 const char *proxy_host)
172 return cs_create_host2(vhost, blocking, vp, proxy_host, &proxy_mode);
175 COMSTACK cs_create_host2(const char *vhost, int blocking, void **vp,
176 const char *proxy_host, int *proxy_mode)
178 enum oid_proto proto = PROTO_Z3950;
179 const char *host = 0;
182 char *connect_host = 0;
184 const char *bind_host = strchr(vhost, ' ');
185 if (bind_host && bind_host[1])
191 if (!cs_parse_host(vhost, &host, &t, &proto, &connect_host))
194 /* vhost proxy proxy method proxy-flag */
195 /* TCP+Z3950 TCP+Z3950 TCP+Z3950 1 */
196 /* TCP+Z3950 TCP+HTTP CONNECT 0 */
197 /* TCP+HTTP TCP+Z3950 TCP+HTTP 1 */
198 /* TCP+HTTP TCP+HTTP TCP+HTTP 1 */
199 /* SSL+* TCP+* CONNECT 0 */
202 if (proxy_host && !connect_host)
204 enum oid_proto proto1;
206 const char *host1 = 0;
208 if (!cs_parse_host(proxy_host, &host1, &t1, &proto1, &connect_host))
215 if (t1 != tcpip_type)
218 if (t == ssl_type || (proto == PROTO_Z3950 && proto1 == PROTO_HTTP))
219 connect_host = xstrdup(host1);
229 cs = yaz_tcpip_create3(-1, blocking, proto, connect_host ? host : 0,
230 0 /* user:pass */, bind_host);
232 else if (t == ssl_type)
234 cs = yaz_ssl_create(-1, blocking, proto, connect_host ? host : 0,
235 0 /* user:pass */, bind_host);
239 cs = cs_create(t, blocking, proto);
243 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
253 int cs_look (COMSTACK cs)
258 static int skip_crlf(const char *buf, int len, int *i)
262 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
267 else if (buf[*i] == '\n')
276 #define CHUNK_DEBUG 0
278 static int cs_read_chunk(const char *buf, int i, int len)
280 /* inside chunked body .. */
289 for (j = i; j <= i+3; j++)
290 printf ("%c", buf[j]);
294 /* read chunk length */
298 printf ("returning incomplete read at 1\n");
299 printf ("i=%d len=%d\n", i, len);
302 } else if (yaz_isdigit(buf[i]))
303 chunk_len = chunk_len * 16 +
305 else if (yaz_isupper(buf[i]))
306 chunk_len = chunk_len * 16 +
307 (buf[i++] - ('A'-10));
308 else if (yaz_islower(buf[i]))
309 chunk_len = chunk_len * 16 +
310 (buf[i++] - ('a'-10));
322 if (skip_crlf(buf, len, &i))
328 printf ("chunk_len=%d\n", chunk_len);
333 if (!skip_crlf(buf, len, &i))
336 /* consider trailing headers .. */
339 if (skip_crlf(buf, len, &i))
341 if (skip_crlf(buf, len, &i))
348 printf ("returning incomplete read at 2\n");
349 printf ("i=%d len=%d\n", i, len);
354 static int cs_complete_http(const char *buf, int len, int head_only)
356 /* deal with HTTP request/response */
357 int i, content_len = 0, chunked = 0;
359 /* need at least one line followed by \n or \r .. */
362 return 0; /* incomplete */
363 else if (buf[i] == '\n' || buf[i] == '\r')
366 /* check to see if it's a response with content */
367 if (!head_only && !memcmp(buf, "HTTP/", 5))
370 for (j = 5; j < i; j++)
374 if (buf[j] == '1') /* 1XX */
376 else if (!memcmp(buf + j, "204", 3))
378 else if (!memcmp(buf + j, "304", 3))
386 printf("len = %d\n", len);
387 fwrite (buf, 1, len, stdout);
388 printf("----------\n");
390 for (i = 2; i <= len-2; )
394 return i; /* do not allow more than 8K HTTP header */
396 if (skip_crlf(buf, len, &i))
398 if (skip_crlf(buf, len, &i))
402 return cs_read_chunk(buf, i, len);
404 { /* not chunked ; inside body */
405 if (content_len == -1)
406 return 0; /* no content length */
407 else if (len >= i + content_len)
409 return i + content_len;
414 else if (i < len - 20 &&
415 !yaz_strncasecmp((const char *) buf+i,
416 "Transfer-Encoding:", 18))
419 while (buf[i] == ' ')
422 if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7))
425 else if (i < len - 17 &&
426 !yaz_strncasecmp((const char *)buf+i,
427 "Content-Length:", 15))
430 while (buf[i] == ' ')
433 while (i <= len-4 && yaz_isdigit(buf[i]))
434 content_len = content_len*10 + (buf[i++] - '0');
435 if (content_len < 0) /* prevent negative offsets */
447 static int cs_complete_auto_x(const char *buf, int len, int head_only)
449 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
450 && buf[1] >= 0x20 && buf[1] < 0x7f
451 && buf[2] >= 0x20 && buf[2] < 0x7f)
453 int r = cs_complete_http(buf, len, head_only);
456 return completeBER(buf, len);
460 int cs_complete_auto(const char *buf, int len)
462 return cs_complete_auto_x(buf, len, 0);
465 int cs_complete_auto_head(const char *buf, int len)
467 return cs_complete_auto_x(buf, len, 1);
470 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
472 cs->max_recv_bytes = max_recv_bytes;
478 * c-file-style: "Stroustrup"
479 * indent-tabs-mode: nil
481 * vim: shiftwidth=4 tabstop=8 expandtab