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_host2(const char *vhost, int blocking, void **vp,
179 const char *proxy_host, const char *bind_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_create2(-1, blocking, proto, connect_host ? host : 0,
206 cs = cs_create(t, blocking, proto);
210 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
220 COMSTACK cs_create_host_proxy(const char *vhost, int blocking, void **vp,
221 const char *proxy_host)
223 return cs_create_host2(vhost, blocking, vp, proxy_host, 0);
226 int cs_look (COMSTACK cs)
231 static int skip_crlf(const char *buf, int len, int *i)
235 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
240 else if (buf[*i] == '\n')
249 #define CHUNK_DEBUG 0
251 static int cs_read_chunk(const char *buf, int i, int len)
253 /* inside chunked body .. */
262 for (j = i; j <= i+3; j++)
263 printf ("%c", buf[j]);
267 /* read chunk length */
271 printf ("returning incomplete read at 1\n");
272 printf ("i=%d len=%d\n", i, len);
275 } else if (yaz_isdigit(buf[i]))
276 chunk_len = chunk_len * 16 +
278 else if (yaz_isupper(buf[i]))
279 chunk_len = chunk_len * 16 +
280 (buf[i++] - ('A'-10));
281 else if (yaz_islower(buf[i]))
282 chunk_len = chunk_len * 16 +
283 (buf[i++] - ('a'-10));
295 if (skip_crlf(buf, len, &i))
301 printf ("chunk_len=%d\n", chunk_len);
306 if (!skip_crlf(buf, len, &i))
309 /* consider trailing headers .. */
312 if (skip_crlf(buf, len, &i))
314 if (skip_crlf(buf, len, &i))
321 printf ("returning incomplete read at 2\n");
322 printf ("i=%d len=%d\n", i, len);
327 static int cs_complete_http(const char *buf, int len, int head_only)
329 /* deal with HTTP request/response */
330 int i, content_len = 0, chunked = 0;
332 /* need at least one line followed by \n or \r .. */
335 return 0; /* incomplete */
336 else if (buf[i] == '\n' || buf[i] == '\r')
339 /* check to see if it's a response with content */
340 if (!head_only && !memcmp(buf, "HTTP/", 5))
343 for (j = 5; j < i; j++)
347 if (buf[j] == '1') /* 1XX */
349 else if (!memcmp(buf + j, "204", 3))
351 else if (!memcmp(buf + j, "304", 3))
359 printf("len = %d\n", len);
360 fwrite (buf, 1, len, stdout);
361 printf("----------\n");
363 for (i = 2; i <= len-2; )
367 return i; /* do not allow more than 8K HTTP header */
369 if (skip_crlf(buf, len, &i))
371 if (skip_crlf(buf, len, &i))
375 return cs_read_chunk(buf, i, len);
377 { /* not chunked ; inside body */
378 if (content_len == -1)
379 return 0; /* no content length */
380 else if (len >= i + content_len)
382 return i + content_len;
387 else if (i < len - 20 &&
388 !yaz_strncasecmp((const char *) buf+i,
389 "Transfer-Encoding:", 18))
392 while (buf[i] == ' ')
395 if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7))
398 else if (i < len - 17 &&
399 !yaz_strncasecmp((const char *)buf+i,
400 "Content-Length:", 15))
403 while (buf[i] == ' ')
406 while (i <= len-4 && yaz_isdigit(buf[i]))
407 content_len = content_len*10 + (buf[i++] - '0');
408 if (content_len < 0) /* prevent negative offsets */
420 static int cs_complete_auto_x(const char *buf, int len, int head_only)
422 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
423 && buf[1] >= 0x20 && buf[1] < 0x7f
424 && buf[2] >= 0x20 && buf[2] < 0x7f)
426 int r = cs_complete_http(buf, len, head_only);
429 return completeBER(buf, len);
433 int cs_complete_auto(const char *buf, int len)
435 return cs_complete_auto_x(buf, len, 0);
438 int cs_complete_auto_head(const char *buf, int len)
440 return cs_complete_auto_x(buf, len, 1);
443 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
445 cs->max_recv_bytes = max_recv_bytes;
451 * c-file-style: "Stroustrup"
452 * indent-tabs-mode: nil
454 * vim: shiftwidth=4 tabstop=8 expandtab