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)
181 enum oid_proto proto = PROTO_Z3950;
182 const char *host = 0;
185 char *connect_host = 0;
186 const char *bind_host = strchr(vhost, ' ');
187 if (bind_host && bind_host[1])
192 if (!cs_parse_host(vhost, &host, &t, &proto, &connect_host))
196 enum oid_proto proto1;
200 if (!cs_parse_host(proxy_host, &host, &t1, &proto1, &connect_host))
206 cs = yaz_tcpip_create3(-1, blocking, proto, connect_host ? host : 0,
209 else if (t == ssl_type)
211 cs = yaz_ssl_create(-1, blocking, proto, connect_host ? host : 0,
216 cs = cs_create(t, blocking, proto);
220 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
230 int cs_look (COMSTACK cs)
235 static int skip_crlf(const char *buf, int len, int *i)
239 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
244 else if (buf[*i] == '\n')
253 #define CHUNK_DEBUG 0
255 static int cs_read_chunk(const char *buf, int i, int len)
257 /* inside chunked body .. */
266 for (j = i; j <= i+3; j++)
267 printf ("%c", buf[j]);
271 /* read chunk length */
275 printf ("returning incomplete read at 1\n");
276 printf ("i=%d len=%d\n", i, len);
279 } else if (yaz_isdigit(buf[i]))
280 chunk_len = chunk_len * 16 +
282 else if (yaz_isupper(buf[i]))
283 chunk_len = chunk_len * 16 +
284 (buf[i++] - ('A'-10));
285 else if (yaz_islower(buf[i]))
286 chunk_len = chunk_len * 16 +
287 (buf[i++] - ('a'-10));
299 if (skip_crlf(buf, len, &i))
305 printf ("chunk_len=%d\n", chunk_len);
310 if (!skip_crlf(buf, len, &i))
313 /* consider trailing headers .. */
316 if (skip_crlf(buf, len, &i))
318 if (skip_crlf(buf, len, &i))
325 printf ("returning incomplete read at 2\n");
326 printf ("i=%d len=%d\n", i, len);
331 static int cs_complete_http(const char *buf, int len, int head_only)
333 /* deal with HTTP request/response */
334 int i, content_len = 0, chunked = 0;
336 /* need at least one line followed by \n or \r .. */
339 return 0; /* incomplete */
340 else if (buf[i] == '\n' || buf[i] == '\r')
343 /* check to see if it's a response with content */
344 if (!head_only && !memcmp(buf, "HTTP/", 5))
347 for (j = 5; j < i; j++)
351 if (buf[j] == '1') /* 1XX */
353 else if (!memcmp(buf + j, "204", 3))
355 else if (!memcmp(buf + j, "304", 3))
363 printf("len = %d\n", len);
364 fwrite (buf, 1, len, stdout);
365 printf("----------\n");
367 for (i = 2; i <= len-2; )
371 return i; /* do not allow more than 8K HTTP header */
373 if (skip_crlf(buf, len, &i))
375 if (skip_crlf(buf, len, &i))
379 return cs_read_chunk(buf, i, len);
381 { /* not chunked ; inside body */
382 if (content_len == -1)
383 return 0; /* no content length */
384 else if (len >= i + content_len)
386 return i + content_len;
391 else if (i < len - 20 &&
392 !yaz_strncasecmp((const char *) buf+i,
393 "Transfer-Encoding:", 18))
396 while (buf[i] == ' ')
399 if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7))
402 else if (i < len - 17 &&
403 !yaz_strncasecmp((const char *)buf+i,
404 "Content-Length:", 15))
407 while (buf[i] == ' ')
410 while (i <= len-4 && yaz_isdigit(buf[i]))
411 content_len = content_len*10 + (buf[i++] - '0');
412 if (content_len < 0) /* prevent negative offsets */
424 static int cs_complete_auto_x(const char *buf, int len, int head_only)
426 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
427 && buf[1] >= 0x20 && buf[1] < 0x7f
428 && buf[2] >= 0x20 && buf[2] < 0x7f)
430 int r = cs_complete_http(buf, len, head_only);
433 return completeBER(buf, len);
437 int cs_complete_auto(const char *buf, int len)
439 return cs_complete_auto_x(buf, len, 0);
442 int cs_complete_auto_head(const char *buf, int len)
444 return cs_complete_auto_x(buf, len, 1);
447 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
449 cs->max_recv_bytes = max_recv_bytes;
455 * c-file-style: "Stroustrup"
456 * indent-tabs-mode: nil
458 * vim: shiftwidth=4 tabstop=8 expandtab