1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2012 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';
131 *connect_host = xstrdup(uri);
132 uri += strlen(uri); /* set to "" */
141 if (strncmp (uri, "tcp:", 4) == 0)
144 *proto = PROTO_Z3950;
146 else if (strncmp (uri, "ssl:", 4) == 0)
151 *proto = PROTO_Z3950;
156 else if (strncmp(uri, "http:", 5) == 0)
159 while (**host == '/')
163 else if (strncmp(uri, "https:", 6) == 0)
168 while (**host == '/')
178 *proto = PROTO_Z3950;
183 COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
185 return cs_create_host_proxy(vhost, blocking, vp, 0);
188 COMSTACK cs_create_host_proxy(const char *vhost, int blocking, void **vp,
189 const char *proxy_host)
191 enum oid_proto proto = PROTO_Z3950;
192 const char *host = 0;
195 char *connect_host = 0;
197 if (!cs_parse_host(vhost, &host, &t, &proto, &connect_host))
202 cs = yaz_tcpip_create(-1, blocking, proto, connect_host ? host : 0);
206 cs = cs_create(t, blocking, proto);
212 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
222 int cs_look (COMSTACK cs)
227 static int skip_crlf(const char *buf, int len, int *i)
231 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
236 else if (buf[*i] == '\n')
245 #define CHUNK_DEBUG 0
247 static int cs_read_chunk(const char *buf, int i, int len)
249 /* inside chunked body .. */
258 for (j = i; j <= i+3; j++)
259 printf ("%c", buf[j]);
263 /* read chunk length */
267 printf ("returning incomplete read at 1\n");
268 printf ("i=%d len=%d\n", i, len);
271 } else if (yaz_isdigit(buf[i]))
272 chunk_len = chunk_len * 16 +
274 else if (yaz_isupper(buf[i]))
275 chunk_len = chunk_len * 16 +
276 (buf[i++] - ('A'-10));
277 else if (yaz_islower(buf[i]))
278 chunk_len = chunk_len * 16 +
279 (buf[i++] - ('a'-10));
291 if (skip_crlf(buf, len, &i))
297 printf ("chunk_len=%d\n", chunk_len);
302 if (!skip_crlf(buf, len, &i))
305 /* consider trailing headers .. */
308 if (skip_crlf(buf, len, &i))
310 if (skip_crlf(buf, len, &i))
317 printf ("returning incomplete read at 2\n");
318 printf ("i=%d len=%d\n", i, len);
323 static int cs_complete_http(const char *buf, int len, int head_only)
325 /* deal with HTTP request/response */
326 int i = 2, content_len = 0, chunked = 0;
331 /* if dealing with HTTP responses - then default
332 content length is unlimited (socket close) */
333 if (!head_only && !memcmp(buf, "HTTP/", 5))
337 printf("len = %d\n", len);
338 fwrite (buf, 1, len, stdout);
339 printf("----------\n");
345 return i; /* do not allow more than 8K HTTP header */
347 if (skip_crlf(buf, len, &i))
349 if (skip_crlf(buf, len, &i))
353 return cs_read_chunk(buf, i, len);
355 { /* not chunked ; inside body */
356 if (content_len == -1)
357 return 0; /* no content length */
358 else if (len >= i + content_len)
360 return i + content_len;
365 else if (i < len - 20 &&
366 !strncasecmp((const char *) buf+i, "Transfer-Encoding:", 18))
369 while (buf[i] == ' ')
372 if (!strncasecmp((const char *) buf+i, "chunked", 7))
375 else if (i < len - 17 &&
376 !strncasecmp((const char *)buf+i, "Content-Length:", 15))
379 while (buf[i] == ' ')
382 while (i <= len-4 && yaz_isdigit(buf[i]))
383 content_len = content_len*10 + (buf[i++] - '0');
384 if (content_len < 0) /* prevent negative offsets */
396 static int cs_complete_auto_x(const char *buf, int len, int head_only)
398 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
399 && buf[1] >= 0x20 && buf[1] < 0x7f
400 && buf[2] >= 0x20 && buf[2] < 0x7f)
402 int r = cs_complete_http(buf, len, head_only);
405 return completeBER((const unsigned char *) buf, len);
409 int cs_complete_auto(const char *buf, int len)
411 return cs_complete_auto_x(buf, len, 0);
414 int cs_complete_auto_head(const char *buf, int len)
416 return cs_complete_auto_x(buf, len, 1);
419 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
421 cs->max_recv_bytes = max_recv_bytes;
427 * c-file-style: "Stroustrup"
428 * indent-tabs-mode: nil
430 * vim: shiftwidth=4 tabstop=8 expandtab