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>
22 #include <yaz/matchstr.h>
28 #if HAVE_OPENSSL_SSL_H
32 static const char *cs_errlist[] =
34 "No error or unspecified error",
35 "System (lower-layer) error",
36 "Operation out of state",
37 "No data (operation would block)",
38 "New data while half of old buffer is on the line (flow control)",
41 "Too large incoming buffer"
44 const char *cs_errmsg(int n)
48 if (n < CSNONE || n > CSLASTERROR) {
49 sprintf(buf, "unknown comstack error %d", n);
53 sprintf(buf, "%s: %s", cs_errlist[n], strerror(errno));
59 const char *cs_strerror(COMSTACK h)
61 return cs_errmsg(h->cerrno);
64 void cs_get_host_args(const char *type_and_host, const char **args)
68 if (!strncmp(type_and_host, "unix:", 5))
70 const char *cp = strchr(type_and_host + 5, ':');
72 type_and_host = cp + 1;
74 type_and_host += strlen(type_and_host); /* empty string */
79 cp = strstr(type_and_host, "://");
90 static int cs_parse_host(const char *uri, const char **host,
91 CS_TYPE *t, enum oid_proto *proto,
97 if (strncmp(uri, "connect:", 8) == 0)
99 const char *cp = strchr(uri, ',');
106 *connect_host = (char *) xmalloc(len + 1);
107 memcpy(*connect_host, uri, len);
108 (*connect_host)[len] = '\0';
112 else if (strncmp(uri, "unix:", 5) == 0)
117 cp = strchr(uri, ':');
120 size_t len = cp - uri;
121 *connect_host = (char *) xmalloc(len + 1);
122 memcpy(*connect_host, uri, len);
123 (*connect_host)[len] = '\0';
133 if (strncmp (uri, "tcp:", 4) == 0)
136 *proto = PROTO_Z3950;
138 else if (strncmp (uri, "ssl:", 4) == 0)
143 *proto = PROTO_Z3950;
148 else if (strncmp(uri, "http:", 5) == 0)
151 while (**host == '/')
155 else if (strncmp(uri, "https:", 6) == 0)
160 while (**host == '/')
170 *proto = PROTO_Z3950;
175 COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
177 return cs_create_host_proxy(vhost, blocking, vp, 0);
180 COMSTACK cs_create_host_proxy(const char *vhost, int blocking, void **vp,
181 const char *proxy_host)
183 enum oid_proto proto = PROTO_Z3950;
184 const char *host = 0;
187 char *connect_host = 0;
189 if (!cs_parse_host(vhost, &host, &t, &proto, &connect_host))
197 enum oid_proto proto1;
200 if (!cs_parse_host(proxy_host, &host, &t, &proto1, &connect_host))
209 cs = yaz_tcpip_create(-1, blocking, proto, connect_host ? host : 0);
213 cs = cs_create(t, blocking, proto);
217 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
227 int cs_look (COMSTACK cs)
232 static int skip_crlf(const char *buf, int len, int *i)
236 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
241 else if (buf[*i] == '\n')
250 #define CHUNK_DEBUG 0
252 static int cs_read_chunk(const char *buf, int i, int len)
254 /* inside chunked body .. */
263 for (j = i; j <= i+3; j++)
264 printf ("%c", buf[j]);
268 /* read chunk length */
272 printf ("returning incomplete read at 1\n");
273 printf ("i=%d len=%d\n", i, len);
276 } else if (yaz_isdigit(buf[i]))
277 chunk_len = chunk_len * 16 +
279 else if (yaz_isupper(buf[i]))
280 chunk_len = chunk_len * 16 +
281 (buf[i++] - ('A'-10));
282 else if (yaz_islower(buf[i]))
283 chunk_len = chunk_len * 16 +
284 (buf[i++] - ('a'-10));
296 if (skip_crlf(buf, len, &i))
302 printf ("chunk_len=%d\n", chunk_len);
307 if (!skip_crlf(buf, len, &i))
310 /* consider trailing headers .. */
313 if (skip_crlf(buf, len, &i))
315 if (skip_crlf(buf, len, &i))
322 printf ("returning incomplete read at 2\n");
323 printf ("i=%d len=%d\n", i, len);
328 static int cs_complete_http(const char *buf, int len, int head_only)
330 /* deal with HTTP request/response */
331 int i, content_len = 0, chunked = 0;
333 /* need at least one line followed by \n or \r .. */
336 return 0; /* incomplete */
337 else if (buf[i] == '\n' || buf[i] == '\r')
340 /* check to see if it's a response with content */
341 if (!head_only && !memcmp(buf, "HTTP/", 5))
344 for (j = 5; j < i; j++)
348 if (buf[j] == '1') /* 1XX */
350 else if (!memcmp(buf + j, "204", 3))
352 else if (!memcmp(buf + j, "304", 3))
360 printf("len = %d\n", len);
361 fwrite (buf, 1, len, stdout);
362 printf("----------\n");
364 for (i = 2; i <= len-2; )
368 return i; /* do not allow more than 8K HTTP header */
370 if (skip_crlf(buf, len, &i))
372 if (skip_crlf(buf, len, &i))
376 return cs_read_chunk(buf, i, len);
378 { /* not chunked ; inside body */
379 if (content_len == -1)
380 return 0; /* no content length */
381 else if (len >= i + content_len)
383 return i + content_len;
388 else if (i < len - 20 &&
389 !yaz_strncasecmp((const char *) buf+i,
390 "Transfer-Encoding:", 18))
393 while (buf[i] == ' ')
396 if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7))
399 else if (i < len - 17 &&
400 !yaz_strncasecmp((const char *)buf+i,
401 "Content-Length:", 15))
404 while (buf[i] == ' ')
407 while (i <= len-4 && yaz_isdigit(buf[i]))
408 content_len = content_len*10 + (buf[i++] - '0');
409 if (content_len < 0) /* prevent negative offsets */
421 static int cs_complete_auto_x(const char *buf, int len, int head_only)
423 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
424 && buf[1] >= 0x20 && buf[1] < 0x7f
425 && buf[2] >= 0x20 && buf[2] < 0x7f)
427 int r = cs_complete_http(buf, len, head_only);
430 return completeBER((const unsigned char *) buf, len);
434 int cs_complete_auto(const char *buf, int len)
436 return cs_complete_auto_x(buf, len, 0);
439 int cs_complete_auto_head(const char *buf, int len)
441 return cs_complete_auto_x(buf, len, 1);
444 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
446 cs->max_recv_bytes = max_recv_bytes;
452 * c-file-style: "Stroustrup"
453 * indent-tabs-mode: nil
455 * vim: shiftwidth=4 tabstop=8 expandtab