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;
187 if (!cs_parse_host(vhost, &host, &t, &proto, &connect_host))
192 enum oid_proto proto1;
195 if (!cs_parse_host(proxy_host, &host, &t, &proto1, &connect_host))
201 cs = yaz_tcpip_create(-1, blocking, proto, connect_host ? host : 0);
205 cs = cs_create(t, blocking, proto);
209 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
219 int cs_look (COMSTACK cs)
224 static int skip_crlf(const char *buf, int len, int *i)
228 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
233 else if (buf[*i] == '\n')
242 #define CHUNK_DEBUG 0
244 static int cs_read_chunk(const char *buf, int i, int len)
246 /* inside chunked body .. */
255 for (j = i; j <= i+3; j++)
256 printf ("%c", buf[j]);
260 /* read chunk length */
264 printf ("returning incomplete read at 1\n");
265 printf ("i=%d len=%d\n", i, len);
268 } else if (yaz_isdigit(buf[i]))
269 chunk_len = chunk_len * 16 +
271 else if (yaz_isupper(buf[i]))
272 chunk_len = chunk_len * 16 +
273 (buf[i++] - ('A'-10));
274 else if (yaz_islower(buf[i]))
275 chunk_len = chunk_len * 16 +
276 (buf[i++] - ('a'-10));
288 if (skip_crlf(buf, len, &i))
294 printf ("chunk_len=%d\n", chunk_len);
299 if (!skip_crlf(buf, len, &i))
302 /* consider trailing headers .. */
305 if (skip_crlf(buf, len, &i))
307 if (skip_crlf(buf, len, &i))
314 printf ("returning incomplete read at 2\n");
315 printf ("i=%d len=%d\n", i, len);
320 static int cs_complete_http(const char *buf, int len, int head_only)
322 /* deal with HTTP request/response */
323 int i, content_len = 0, chunked = 0;
325 /* need at least one line followed by \n or \r .. */
328 return 0; /* incomplete */
329 else if (buf[i] == '\n' || buf[i] == '\r')
332 /* check to see if it's a response with content */
333 if (!head_only && !memcmp(buf, "HTTP/", 5))
336 for (j = 5; j < i; j++)
340 if (buf[j] == '1') /* 1XX */
342 else if (!memcmp(buf + j, "204", 3))
344 else if (!memcmp(buf + j, "304", 3))
352 printf("len = %d\n", len);
353 fwrite (buf, 1, len, stdout);
354 printf("----------\n");
356 for (i = 2; i <= len-2; )
360 return i; /* do not allow more than 8K HTTP header */
362 if (skip_crlf(buf, len, &i))
364 if (skip_crlf(buf, len, &i))
368 return cs_read_chunk(buf, i, len);
370 { /* not chunked ; inside body */
371 if (content_len == -1)
372 return 0; /* no content length */
373 else if (len >= i + content_len)
375 return i + content_len;
380 else if (i < len - 20 &&
381 !yaz_strncasecmp((const char *) buf+i,
382 "Transfer-Encoding:", 18))
385 while (buf[i] == ' ')
388 if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7))
391 else if (i < len - 17 &&
392 !yaz_strncasecmp((const char *)buf+i,
393 "Content-Length:", 15))
396 while (buf[i] == ' ')
399 while (i <= len-4 && yaz_isdigit(buf[i]))
400 content_len = content_len*10 + (buf[i++] - '0');
401 if (content_len < 0) /* prevent negative offsets */
413 static int cs_complete_auto_x(const char *buf, int len, int head_only)
415 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
416 && buf[1] >= 0x20 && buf[1] < 0x7f
417 && buf[2] >= 0x20 && buf[2] < 0x7f)
419 int r = cs_complete_http(buf, len, head_only);
422 return completeBER(buf, len);
426 int cs_complete_auto(const char *buf, int len)
428 return cs_complete_auto_x(buf, len, 0);
431 int cs_complete_auto_head(const char *buf, int len)
433 return cs_complete_auto_x(buf, len, 1);
436 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
438 cs->max_recv_bytes = max_recv_bytes;
444 * c-file-style: "Stroustrup"
445 * indent-tabs-mode: nil
447 * vim: shiftwidth=4 tabstop=8 expandtab