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)
59 if (!strncmp(type_and_host, "unix:", 5))
61 const char *cp = strchr(type_and_host + 5, ':');
63 type_and_host = cp + 1;
65 type_and_host += strlen(type_and_host); /* empty string */
69 const char *cp = strchr(type_and_host, '/');
72 if (cp > type_and_host && !memcmp(cp - 1, "://", 3))
73 cp = strchr(cp + 2, '/');
80 int cs_parse_host(const char *uri, const char **host,
81 CS_TYPE *t, enum oid_proto *proto,
87 if (strncmp(uri, "connect:", 8) == 0)
89 const char *cp = strchr(uri, ',');
96 *connect_host = (char *) xmalloc(len + 1);
97 memcpy(*connect_host, uri, len);
98 (*connect_host)[len] = '\0';
102 else if (strncmp(uri, "unix:", 5) == 0)
107 cp = strchr(uri, ':');
110 size_t len = cp - uri;
111 *connect_host = (char *) xmalloc(len + 1);
112 memcpy(*connect_host, uri, len);
113 (*connect_host)[len] = '\0';
117 xfree(*connect_host);
125 if (strncmp (uri, "tcp:", 4) == 0)
128 *proto = PROTO_Z3950;
130 else if (strncmp (uri, "ssl:", 4) == 0)
135 *proto = PROTO_Z3950;
137 xfree(*connect_host);
142 else if (strncmp(uri, "http:", 5) == 0)
145 while (**host == '/')
149 else if (strncmp(uri, "https:", 6) == 0)
154 while (**host == '/')
158 xfree(*connect_host);
166 *proto = PROTO_Z3950;
171 COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
173 return cs_create_host_proxy(vhost, blocking, vp, 0);
176 COMSTACK cs_create_host_proxy(const char *vhost, int blocking, void **vp,
177 const char *proxy_host)
180 return cs_create_host2(vhost, blocking, vp, proxy_host, &proxy_mode);
183 COMSTACK cs_create_host2(const char *vhost, int blocking, void **vp,
184 const char *proxy_host, int *proxy_mode)
186 enum oid_proto proto = PROTO_Z3950;
187 const char *host = 0;
190 char *connect_host = 0;
192 const char *bind_host = strchr(vhost, ' ');
193 if (bind_host && bind_host[1])
199 if (!cs_parse_host(vhost, &host, &t, &proto, &connect_host))
202 /* vhost proxy proxy method proxy-flag */
203 /* TCP+Z3950 TCP+Z3950 TCP+Z3950 1 */
204 /* TCP+Z3950 TCP+HTTP CONNECT 0 */
205 /* TCP+HTTP TCP+Z3950 TCP+HTTP 1 */
206 /* TCP+HTTP TCP+HTTP TCP+HTTP 1 */
207 /* SSL+* TCP+* CONNECT 0 */
210 if (proxy_host && !connect_host)
212 enum oid_proto proto1;
214 const char *host1 = 0;
216 if (!cs_parse_host(proxy_host, &host1, &t1, &proto1, &connect_host))
223 if (t1 != tcpip_type)
226 if (t == ssl_type || (proto == PROTO_Z3950 && proto1 == PROTO_HTTP))
227 connect_host = xstrdup(host1);
237 cs = yaz_tcpip_create3(-1, blocking, proto, connect_host ? host : 0,
238 0 /* user:pass */, bind_host);
240 else if (t == ssl_type)
242 cs = yaz_ssl_create(-1, blocking, proto, connect_host ? host : 0,
243 0 /* user:pass */, bind_host);
247 cs = cs_create(t, blocking, proto);
251 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
261 int cs_look (COMSTACK cs)
266 static int skip_crlf(const char *buf, int len, int *i)
270 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
275 else if (buf[*i] == '\n')
284 #define CHUNK_DEBUG 0
286 static int cs_read_chunk(const char *buf, int i, int len)
288 /* inside chunked body .. */
297 for (j = i; j <= i+3; j++)
298 printf ("%c", buf[j]);
302 /* read chunk length */
306 printf ("returning incomplete read at 1\n");
307 printf ("i=%d len=%d\n", i, len);
310 } else if (yaz_isdigit(buf[i]))
311 chunk_len = chunk_len * 16 +
313 else if (yaz_isupper(buf[i]))
314 chunk_len = chunk_len * 16 +
315 (buf[i++] - ('A'-10));
316 else if (yaz_islower(buf[i]))
317 chunk_len = chunk_len * 16 +
318 (buf[i++] - ('a'-10));
330 if (skip_crlf(buf, len, &i))
336 printf ("chunk_len=%d\n", chunk_len);
341 if (!skip_crlf(buf, len, &i))
344 /* consider trailing headers .. */
347 if (skip_crlf(buf, len, &i))
349 if (skip_crlf(buf, len, &i))
356 printf ("returning incomplete read at 2\n");
357 printf ("i=%d len=%d\n", i, len);
362 static int cs_complete_http(const char *buf, int len, int head_only)
364 /* deal with HTTP request/response */
365 int i, content_len = 0, chunked = 0;
367 /* need at least one line followed by \n or \r .. */
370 return 0; /* incomplete */
371 else if (buf[i] == '\n' || buf[i] == '\r')
374 /* check to see if it's a response with content */
375 if (!head_only && !memcmp(buf, "HTTP/", 5))
378 for (j = 5; j < i; j++)
382 if (buf[j] == '1') /* 1XX */
384 else if (!memcmp(buf + j, "204", 3))
386 else if (!memcmp(buf + j, "304", 3))
394 printf("len = %d\n", len);
395 fwrite (buf, 1, len, stdout);
396 printf("----------\n");
398 for (i = 2; i <= len-2; )
402 return i; /* do not allow more than 8K HTTP header */
404 if (skip_crlf(buf, len, &i))
406 if (skip_crlf(buf, len, &i))
410 return cs_read_chunk(buf, i, len);
412 { /* not chunked ; inside body */
413 if (content_len == -1)
414 return 0; /* no content length */
415 else if (len >= i + content_len)
417 return i + content_len;
422 else if (i < len - 20 &&
423 !yaz_strncasecmp((const char *) buf+i,
424 "Transfer-Encoding:", 18))
427 while (buf[i] == ' ')
430 if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7))
433 else if (i < len - 17 &&
434 !yaz_strncasecmp((const char *)buf+i,
435 "Content-Length:", 15))
438 while (buf[i] == ' ')
441 while (i <= len-4 && yaz_isdigit(buf[i]))
442 content_len = content_len*10 + (buf[i++] - '0');
443 if (content_len < 0) /* prevent negative offsets */
455 static int cs_complete_auto_x(const char *buf, int len, int head_only)
457 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
458 && buf[1] >= 0x20 && buf[1] < 0x7f
459 && buf[2] >= 0x20 && buf[2] < 0x7f)
461 int r = cs_complete_http(buf, len, head_only);
464 return completeBER(buf, len);
468 int cs_complete_auto(const char *buf, int len)
470 return cs_complete_auto_x(buf, len, 0);
473 int cs_complete_auto_head(const char *buf, int len)
475 return cs_complete_auto_x(buf, len, 1);
478 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
480 cs->max_recv_bytes = max_recv_bytes;
486 * c-file-style: "Stroustrup"
487 * indent-tabs-mode: nil
489 * vim: shiftwidth=4 tabstop=8 expandtab