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 const char *bind_host = strchr(vhost, ' ');
202 if (bind_host && bind_host[1])
206 cs = yaz_tcpip_create2(-1, blocking, proto, connect_host ? host : 0,
211 cs = cs_create(t, blocking, proto);
215 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
225 int cs_look (COMSTACK cs)
230 static int skip_crlf(const char *buf, int len, int *i)
234 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
239 else if (buf[*i] == '\n')
248 #define CHUNK_DEBUG 0
250 static int cs_read_chunk(const char *buf, int i, int len)
252 /* inside chunked body .. */
261 for (j = i; j <= i+3; j++)
262 printf ("%c", buf[j]);
266 /* read chunk length */
270 printf ("returning incomplete read at 1\n");
271 printf ("i=%d len=%d\n", i, len);
274 } else if (yaz_isdigit(buf[i]))
275 chunk_len = chunk_len * 16 +
277 else if (yaz_isupper(buf[i]))
278 chunk_len = chunk_len * 16 +
279 (buf[i++] - ('A'-10));
280 else if (yaz_islower(buf[i]))
281 chunk_len = chunk_len * 16 +
282 (buf[i++] - ('a'-10));
294 if (skip_crlf(buf, len, &i))
300 printf ("chunk_len=%d\n", chunk_len);
305 if (!skip_crlf(buf, len, &i))
308 /* consider trailing headers .. */
311 if (skip_crlf(buf, len, &i))
313 if (skip_crlf(buf, len, &i))
320 printf ("returning incomplete read at 2\n");
321 printf ("i=%d len=%d\n", i, len);
326 static int cs_complete_http(const char *buf, int len, int head_only)
328 /* deal with HTTP request/response */
329 int i, content_len = 0, chunked = 0;
331 /* need at least one line followed by \n or \r .. */
334 return 0; /* incomplete */
335 else if (buf[i] == '\n' || buf[i] == '\r')
338 /* check to see if it's a response with content */
339 if (!head_only && !memcmp(buf, "HTTP/", 5))
342 for (j = 5; j < i; j++)
346 if (buf[j] == '1') /* 1XX */
348 else if (!memcmp(buf + j, "204", 3))
350 else if (!memcmp(buf + j, "304", 3))
358 printf("len = %d\n", len);
359 fwrite (buf, 1, len, stdout);
360 printf("----------\n");
362 for (i = 2; i <= len-2; )
366 return i; /* do not allow more than 8K HTTP header */
368 if (skip_crlf(buf, len, &i))
370 if (skip_crlf(buf, len, &i))
374 return cs_read_chunk(buf, i, len);
376 { /* not chunked ; inside body */
377 if (content_len == -1)
378 return 0; /* no content length */
379 else if (len >= i + content_len)
381 return i + content_len;
386 else if (i < len - 20 &&
387 !yaz_strncasecmp((const char *) buf+i,
388 "Transfer-Encoding:", 18))
391 while (buf[i] == ' ')
394 if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7))
397 else if (i < len - 17 &&
398 !yaz_strncasecmp((const char *)buf+i,
399 "Content-Length:", 15))
402 while (buf[i] == ' ')
405 while (i <= len-4 && yaz_isdigit(buf[i]))
406 content_len = content_len*10 + (buf[i++] - '0');
407 if (content_len < 0) /* prevent negative offsets */
419 static int cs_complete_auto_x(const char *buf, int len, int head_only)
421 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
422 && buf[1] >= 0x20 && buf[1] < 0x7f
423 && buf[2] >= 0x20 && buf[2] < 0x7f)
425 int r = cs_complete_http(buf, len, head_only);
428 return completeBER(buf, len);
432 int cs_complete_auto(const char *buf, int len)
434 return cs_complete_auto_x(buf, len, 0);
437 int cs_complete_auto_head(const char *buf, int len)
439 return cs_complete_auto_x(buf, len, 1);
442 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
444 cs->max_recv_bytes = max_recv_bytes;
450 * c-file-style: "Stroustrup"
451 * indent-tabs-mode: nil
453 * vim: shiftwidth=4 tabstop=8 expandtab