1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2013 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>
24 #define strncasecmp _strnicmp
31 #if HAVE_OPENSSL_SSL_H
35 static const char *cs_errlist[] =
37 "No error or unspecified error",
38 "System (lower-layer) error",
39 "Operation out of state",
40 "No data (operation would block)",
41 "New data while half of old buffer is on the line (flow control)",
44 "Too large incoming buffer"
47 const char *cs_errmsg(int n)
51 if (n < CSNONE || n > CSLASTERROR) {
52 sprintf(buf, "unknown comstack error %d", n);
56 sprintf(buf, "%s: %s", cs_errlist[n], strerror(errno));
62 const char *cs_strerror(COMSTACK h)
64 return cs_errmsg(h->cerrno);
67 void cs_get_host_args(const char *type_and_host, const char **args)
71 if (!strncmp(type_and_host, "unix:", 5))
73 const char *cp = strchr(type_and_host + 5, ':');
75 type_and_host = cp + 1;
77 type_and_host += strlen(type_and_host); /* empty string */
82 cp = strstr(type_and_host, "://");
93 static int cs_parse_host(const char *uri, const char **host,
94 CS_TYPE *t, enum oid_proto *proto,
100 if (strncmp(uri, "connect:", 8) == 0)
102 const char *cp = strchr(uri, ',');
109 *connect_host = (char *) xmalloc(len + 1);
110 memcpy(*connect_host, uri, len);
111 (*connect_host)[len] = '\0';
115 else if (strncmp(uri, "unix:", 5) == 0)
120 cp = strchr(uri, ':');
123 size_t len = cp - uri;
124 *connect_host = (char *) xmalloc(len + 1);
125 memcpy(*connect_host, uri, len);
126 (*connect_host)[len] = '\0';
136 if (strncmp (uri, "tcp:", 4) == 0)
139 *proto = PROTO_Z3950;
141 else if (strncmp (uri, "ssl:", 4) == 0)
146 *proto = PROTO_Z3950;
151 else if (strncmp(uri, "http:", 5) == 0)
154 while (**host == '/')
158 else if (strncmp(uri, "https:", 6) == 0)
163 while (**host == '/')
173 *proto = PROTO_Z3950;
178 COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
180 return cs_create_host_proxy(vhost, blocking, vp, 0);
183 COMSTACK cs_create_host_proxy(const char *vhost, int blocking, void **vp,
184 const char *proxy_host)
186 enum oid_proto proto = PROTO_Z3950;
187 const char *host = 0;
190 char *connect_host = 0;
192 if (!cs_parse_host(vhost, &host, &t, &proto, &connect_host))
200 enum oid_proto proto1;
203 if (!cs_parse_host(proxy_host, &host, &t, &proto1, &connect_host))
212 cs = yaz_tcpip_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 = 2, content_len = 0, chunked = 0;
339 /* if dealing with HTTP responses - then default
340 content length is unlimited (socket close) */
341 if (!head_only && !memcmp(buf, "HTTP/", 5))
345 printf("len = %d\n", len);
346 fwrite (buf, 1, len, stdout);
347 printf("----------\n");
353 return i; /* do not allow more than 8K HTTP header */
355 if (skip_crlf(buf, len, &i))
357 if (skip_crlf(buf, len, &i))
361 return cs_read_chunk(buf, i, len);
363 { /* not chunked ; inside body */
364 if (content_len == -1)
365 return 0; /* no content length */
366 else if (len >= i + content_len)
368 return i + content_len;
373 else if (i < len - 20 &&
374 !strncasecmp((const char *) buf+i, "Transfer-Encoding:", 18))
377 while (buf[i] == ' ')
380 if (!strncasecmp((const char *) buf+i, "chunked", 7))
383 else if (i < len - 17 &&
384 !strncasecmp((const char *)buf+i, "Content-Length:", 15))
387 while (buf[i] == ' ')
390 while (i <= len-4 && yaz_isdigit(buf[i]))
391 content_len = content_len*10 + (buf[i++] - '0');
392 if (content_len < 0) /* prevent negative offsets */
404 static int cs_complete_auto_x(const char *buf, int len, int head_only)
406 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
407 && buf[1] >= 0x20 && buf[1] < 0x7f
408 && buf[2] >= 0x20 && buf[2] < 0x7f)
410 int r = cs_complete_http(buf, len, head_only);
413 return completeBER((const unsigned char *) buf, len);
417 int cs_complete_auto(const char *buf, int len)
419 return cs_complete_auto_x(buf, len, 0);
422 int cs_complete_auto_head(const char *buf, int len)
424 return cs_complete_auto_x(buf, len, 1);
427 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
429 cs->max_recv_bytes = max_recv_bytes;
435 * c-file-style: "Stroustrup"
436 * indent-tabs-mode: nil
438 * vim: shiftwidth=4 tabstop=8 expandtab