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)
40 if (n < CSNONE || n > CSLASTERROR) {
41 sprintf(buf, "unknown comstack error %d", n);
45 sprintf(buf, "%s: %s", cs_errlist[n], strerror(errno));
51 const char *cs_strerror(COMSTACK h)
53 return cs_errmsg(h->cerrno);
56 void cs_get_host_args(const char *type_and_host, const char **args)
60 if (!strncmp(type_and_host, "unix:", 5))
62 const char *cp = strchr(type_and_host + 5, ':');
64 type_and_host = cp + 1;
66 type_and_host += strlen(type_and_host); /* empty string */
71 cp = strstr(type_and_host, "://");
82 int cs_parse_host(const char *uri, const char **host,
83 CS_TYPE *t, enum oid_proto *proto,
89 if (strncmp(uri, "connect:", 8) == 0)
91 const char *cp = strchr(uri, ',');
98 *connect_host = (char *) xmalloc(len + 1);
99 memcpy(*connect_host, uri, len);
100 (*connect_host)[len] = '\0';
104 else if (strncmp(uri, "unix:", 5) == 0)
109 cp = strchr(uri, ':');
112 size_t len = cp - uri;
113 *connect_host = (char *) xmalloc(len + 1);
114 memcpy(*connect_host, uri, len);
115 (*connect_host)[len] = '\0';
119 xfree(*connect_host);
127 if (strncmp (uri, "tcp:", 4) == 0)
130 *proto = PROTO_Z3950;
132 else if (strncmp (uri, "ssl:", 4) == 0)
137 *proto = PROTO_Z3950;
139 xfree(*connect_host);
144 else if (strncmp(uri, "http:", 5) == 0)
147 while (**host == '/')
151 else if (strncmp(uri, "https:", 6) == 0)
156 while (**host == '/')
160 xfree(*connect_host);
168 *proto = PROTO_Z3950;
173 COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
175 return cs_create_host_proxy(vhost, blocking, vp, 0);
178 COMSTACK cs_create_host_proxy(const char *vhost, int blocking, void **vp,
179 const char *proxy_host)
182 return cs_create_host2(vhost, blocking, vp, proxy_host, &proxy_mode);
185 COMSTACK cs_create_host2(const char *vhost, int blocking, void **vp,
186 const char *proxy_host, int *proxy_mode)
188 enum oid_proto proto = PROTO_Z3950;
189 const char *host = 0;
192 char *connect_host = 0;
194 const char *bind_host = strchr(vhost, ' ');
195 if (bind_host && bind_host[1])
201 if (!cs_parse_host(vhost, &host, &t, &proto, &connect_host))
204 /* vhost proxy proxy method proxy-flag */
205 /* TCP+Z3950 TCP+Z3950 TCP+Z3950 1 */
206 /* TCP+Z3950 TCP+HTTP CONNECT 0 */
207 /* TCP+HTTP TCP+Z3950 TCP+HTTP 1 */
208 /* TCP+HTTP TCP+HTTP TCP+HTTP 1 */
209 /* SSL+* TCP+* CONNECT 0 */
212 if (proxy_host && !connect_host)
214 enum oid_proto proto1;
216 const char *host1 = 0;
218 if (!cs_parse_host(proxy_host, &host1, &t1, &proto1, &connect_host))
225 if (t1 != tcpip_type)
228 if (t == ssl_type || (proto == PROTO_Z3950 && proto1 == PROTO_HTTP))
229 connect_host = xstrdup(host1);
239 cs = yaz_tcpip_create3(-1, blocking, proto, connect_host ? host : 0,
240 0 /* user:pass */, bind_host);
242 else if (t == ssl_type)
244 cs = yaz_ssl_create(-1, blocking, proto, connect_host ? host : 0,
245 0 /* user:pass */, bind_host);
249 cs = cs_create(t, blocking, proto);
253 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
263 int cs_look (COMSTACK cs)
268 static int skip_crlf(const char *buf, int len, int *i)
272 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
277 else if (buf[*i] == '\n')
286 #define CHUNK_DEBUG 0
288 static int cs_read_chunk(const char *buf, int i, int len)
290 /* inside chunked body .. */
299 for (j = i; j <= i+3; j++)
300 printf ("%c", buf[j]);
304 /* read chunk length */
308 printf ("returning incomplete read at 1\n");
309 printf ("i=%d len=%d\n", i, len);
312 } else if (yaz_isdigit(buf[i]))
313 chunk_len = chunk_len * 16 +
315 else if (yaz_isupper(buf[i]))
316 chunk_len = chunk_len * 16 +
317 (buf[i++] - ('A'-10));
318 else if (yaz_islower(buf[i]))
319 chunk_len = chunk_len * 16 +
320 (buf[i++] - ('a'-10));
332 if (skip_crlf(buf, len, &i))
338 printf ("chunk_len=%d\n", chunk_len);
343 if (!skip_crlf(buf, len, &i))
346 /* consider trailing headers .. */
349 if (skip_crlf(buf, len, &i))
351 if (skip_crlf(buf, len, &i))
358 printf ("returning incomplete read at 2\n");
359 printf ("i=%d len=%d\n", i, len);
364 static int cs_complete_http(const char *buf, int len, int head_only)
366 /* deal with HTTP request/response */
367 int i, content_len = 0, chunked = 0;
369 /* need at least one line followed by \n or \r .. */
372 return 0; /* incomplete */
373 else if (buf[i] == '\n' || buf[i] == '\r')
376 /* check to see if it's a response with content */
377 if (!head_only && !memcmp(buf, "HTTP/", 5))
380 for (j = 5; j < i; j++)
384 if (buf[j] == '1') /* 1XX */
386 else if (!memcmp(buf + j, "204", 3))
388 else if (!memcmp(buf + j, "304", 3))
396 printf("len = %d\n", len);
397 fwrite (buf, 1, len, stdout);
398 printf("----------\n");
400 for (i = 2; i <= len-2; )
404 return i; /* do not allow more than 8K HTTP header */
406 if (skip_crlf(buf, len, &i))
408 if (skip_crlf(buf, len, &i))
412 return cs_read_chunk(buf, i, len);
414 { /* not chunked ; inside body */
415 if (content_len == -1)
416 return 0; /* no content length */
417 else if (len >= i + content_len)
419 return i + content_len;
424 else if (i < len - 20 &&
425 !yaz_strncasecmp((const char *) buf+i,
426 "Transfer-Encoding:", 18))
429 while (buf[i] == ' ')
432 if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7))
435 else if (i < len - 17 &&
436 !yaz_strncasecmp((const char *)buf+i,
437 "Content-Length:", 15))
440 while (buf[i] == ' ')
443 while (i <= len-4 && yaz_isdigit(buf[i]))
444 content_len = content_len*10 + (buf[i++] - '0');
445 if (content_len < 0) /* prevent negative offsets */
457 static int cs_complete_auto_x(const char *buf, int len, int head_only)
459 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
460 && buf[1] >= 0x20 && buf[1] < 0x7f
461 && buf[2] >= 0x20 && buf[2] < 0x7f)
463 int r = cs_complete_http(buf, len, head_only);
466 return completeBER(buf, len);
470 int cs_complete_auto(const char *buf, int len)
472 return cs_complete_auto_x(buf, len, 0);
475 int cs_complete_auto_head(const char *buf, int len)
477 return cs_complete_auto_x(buf, len, 1);
480 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
482 cs->max_recv_bytes = max_recv_bytes;
488 * c-file-style: "Stroustrup"
489 * indent-tabs-mode: nil
491 * vim: shiftwidth=4 tabstop=8 expandtab