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, ':');
56 type_and_host = cp + 1;
57 if (!strchr(type_and_host, ':'))
59 *args = type_and_host; /* unix:path:args */
65 const char *cp = strchr(type_and_host, '/');
68 if (cp > type_and_host && !memcmp(cp - 1, "://", 3))
69 cp = strchr(cp + 2, '/');
76 int cs_parse_host(const char *uri, const char **host,
77 CS_TYPE *t, enum oid_proto *proto,
83 if (strncmp(uri, "connect:", 8) == 0)
85 const char *cp = strchr(uri, ',');
92 *connect_host = (char *) xmalloc(len + 1);
93 memcpy(*connect_host, uri, len);
94 (*connect_host)[len] = '\0';
98 else if (strncmp(uri, "unix:", 5) == 0)
103 cp = strchr(uri, ':');
106 size_t len = cp - uri;
107 *connect_host = (char *) xmalloc(len + 1);
108 memcpy(*connect_host, uri, len);
109 (*connect_host)[len] = '\0';
113 xfree(*connect_host);
121 if (strncmp (uri, "tcp:", 4) == 0)
124 *proto = PROTO_Z3950;
126 else if (strncmp (uri, "ssl:", 4) == 0)
131 *proto = PROTO_Z3950;
133 xfree(*connect_host);
138 else if (strncmp(uri, "http:", 5) == 0)
141 while (**host == '/')
145 else if (strncmp(uri, "https:", 6) == 0)
150 while (**host == '/')
154 xfree(*connect_host);
162 *proto = PROTO_Z3950;
167 COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
169 return cs_create_host_proxy(vhost, blocking, vp, 0);
172 COMSTACK cs_create_host_proxy(const char *vhost, int blocking, void **vp,
173 const char *proxy_host)
176 return cs_create_host2(vhost, blocking, vp, proxy_host, &proxy_mode);
179 COMSTACK cs_create_host2(const char *vhost, int blocking, void **vp,
180 const char *proxy_host, int *proxy_mode)
182 enum oid_proto proto = PROTO_Z3950;
183 const char *host = 0;
186 char *connect_host = 0;
188 const char *bind_host = strchr(vhost, ' ');
189 if (bind_host && bind_host[1])
195 if (!cs_parse_host(vhost, &host, &t, &proto, &connect_host))
198 /* vhost proxy proxy method proxy-flag */
199 /* TCP+Z3950 TCP+Z3950 TCP+Z3950 1 */
200 /* TCP+Z3950 TCP+HTTP CONNECT 0 */
201 /* TCP+HTTP TCP+Z3950 TCP+HTTP 1 */
202 /* TCP+HTTP TCP+HTTP TCP+HTTP 1 */
203 /* SSL+* TCP+* CONNECT 0 */
206 if (proxy_host && !connect_host)
208 enum oid_proto proto1;
210 const char *host1 = 0;
212 if (!cs_parse_host(proxy_host, &host1, &t1, &proto1, &connect_host))
219 if (t1 != tcpip_type)
222 if (t == ssl_type || (proto == PROTO_Z3950 && proto1 == PROTO_HTTP))
223 connect_host = xstrdup(host1);
233 cs = yaz_tcpip_create3(-1, blocking, proto, connect_host ? host : 0,
234 0 /* user:pass */, bind_host);
236 else if (t == ssl_type)
238 cs = yaz_ssl_create(-1, blocking, proto, connect_host ? host : 0,
239 0 /* user:pass */, bind_host);
243 cs = cs_create(t, blocking, proto);
247 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
257 int cs_look (COMSTACK cs)
262 static int skip_crlf(const char *buf, int len, int *i)
266 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
271 else if (buf[*i] == '\n')
280 #define CHUNK_DEBUG 0
282 static int cs_read_chunk(const char *buf, int i, int len)
284 /* inside chunked body .. */
293 for (j = i; j <= i+3; j++)
294 printf ("%c", buf[j]);
298 /* read chunk length */
302 printf ("returning incomplete read at 1\n");
303 printf ("i=%d len=%d\n", i, len);
306 } else if (yaz_isdigit(buf[i]))
307 chunk_len = chunk_len * 16 +
309 else if (yaz_isupper(buf[i]))
310 chunk_len = chunk_len * 16 +
311 (buf[i++] - ('A'-10));
312 else if (yaz_islower(buf[i]))
313 chunk_len = chunk_len * 16 +
314 (buf[i++] - ('a'-10));
326 if (skip_crlf(buf, len, &i))
332 printf ("chunk_len=%d\n", chunk_len);
337 if (!skip_crlf(buf, len, &i))
340 /* consider trailing headers .. */
343 if (skip_crlf(buf, len, &i))
345 if (skip_crlf(buf, len, &i))
352 printf ("returning incomplete read at 2\n");
353 printf ("i=%d len=%d\n", i, len);
358 static int cs_complete_http(const char *buf, int len, int head_only)
360 /* deal with HTTP request/response */
361 int i, content_len = 0, chunked = 0;
363 /* need at least one line followed by \n or \r .. */
366 return 0; /* incomplete */
367 else if (buf[i] == '\n' || buf[i] == '\r')
370 /* check to see if it's a response with content */
371 if (!head_only && !memcmp(buf, "HTTP/", 5))
374 for (j = 5; j < i; j++)
378 if (buf[j] == '1') /* 1XX */
380 else if (!memcmp(buf + j, "204", 3))
382 else if (!memcmp(buf + j, "304", 3))
390 printf("len = %d\n", len);
391 fwrite (buf, 1, len, stdout);
392 printf("----------\n");
394 for (i = 2; i <= len-2; )
398 return i; /* do not allow more than 8K HTTP header */
400 if (skip_crlf(buf, len, &i))
402 if (skip_crlf(buf, len, &i))
406 return cs_read_chunk(buf, i, len);
408 { /* not chunked ; inside body */
409 if (content_len == -1)
410 return 0; /* no content length */
411 else if (len >= i + content_len)
413 return i + content_len;
418 else if (i < len - 20 &&
419 !yaz_strncasecmp((const char *) buf+i,
420 "Transfer-Encoding:", 18))
423 while (buf[i] == ' ')
426 if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7))
429 else if (i < len - 17 &&
430 !yaz_strncasecmp((const char *)buf+i,
431 "Content-Length:", 15))
434 while (buf[i] == ' ')
437 while (i <= len-4 && yaz_isdigit(buf[i]))
438 content_len = content_len*10 + (buf[i++] - '0');
439 if (content_len < 0) /* prevent negative offsets */
451 static int cs_complete_auto_x(const char *buf, int len, int head_only)
453 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
454 && buf[1] >= 0x20 && buf[1] < 0x7f
455 && buf[2] >= 0x20 && buf[2] < 0x7f)
457 int r = cs_complete_http(buf, len, head_only);
460 return completeBER(buf, len);
464 int cs_complete_auto(const char *buf, int len)
466 return cs_complete_auto_x(buf, len, 0);
469 int cs_complete_auto_head(const char *buf, int len)
471 return cs_complete_auto_x(buf, len, 1);
474 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
476 cs->max_recv_bytes = max_recv_bytes;
482 * c-file-style: "Stroustrup"
483 * indent-tabs-mode: nil
485 * vim: shiftwidth=4 tabstop=8 expandtab