1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2011 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 (*type_and_host && strncmp(type_and_host, "unix:", 5))
74 cp = strstr(type_and_host, "://");
85 static int cs_parse_host(const char *uri, const char **host,
86 CS_TYPE *t, enum oid_proto *proto,
90 if (strncmp(uri, "connect:", 8) == 0)
92 const char *cp = strchr(uri, ',');
95 size_t len = cp - (uri + 8);
96 *connect_host = (char *) xmalloc(len+1);
97 memcpy(*connect_host, uri + 8, len);
98 (*connect_host)[len] = '\0';
103 if (strncmp (uri, "tcp:", 4) == 0)
107 *proto = PROTO_Z3950;
109 else if (strncmp (uri, "ssl:", 4) == 0)
114 *proto = PROTO_Z3950;
119 else if (strncmp (uri, "unix:", 5) == 0)
124 *proto = PROTO_Z3950;
129 else if (strncmp(uri, "http:", 5) == 0)
133 while (**host == '/')
137 else if (strncmp(uri, "https:", 6) == 0)
142 while (**host == '/')
151 *proto = PROTO_Z3950;
158 COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
160 return cs_create_host_proxy(vhost, blocking, vp, 0);
163 COMSTACK cs_create_host_proxy(const char *vhost, int blocking, void **vp,
164 const char *proxy_host)
166 enum oid_proto proto = PROTO_Z3950;
167 const char *host = 0;
170 char *connect_host = 0;
172 cs_parse_host(vhost, &host, &t, &proto, &connect_host);
176 cs = yaz_tcpip_create(-1, blocking, proto, connect_host ? host : 0);
180 cs = cs_create(t, blocking, proto);
186 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
196 int cs_look (COMSTACK cs)
201 static int skip_crlf(const char *buf, int len, int *i)
205 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
210 else if (buf[*i] == '\n')
219 #define CHUNK_DEBUG 0
221 static int cs_read_chunk(const char *buf, int i, int len)
223 /* inside chunked body .. */
232 for (j = i; j <= i+3; j++)
233 printf ("%c", buf[j]);
237 /* read chunk length */
241 printf ("returning incomplete read at 1\n");
242 printf ("i=%d len=%d\n", i, len);
245 } else if (yaz_isdigit(buf[i]))
246 chunk_len = chunk_len * 16 +
248 else if (yaz_isupper(buf[i]))
249 chunk_len = chunk_len * 16 +
250 (buf[i++] - ('A'-10));
251 else if (yaz_islower(buf[i]))
252 chunk_len = chunk_len * 16 +
253 (buf[i++] - ('a'-10));
265 if (skip_crlf(buf, len, &i))
271 printf ("chunk_len=%d\n", chunk_len);
276 if (!skip_crlf(buf, len, &i))
279 /* consider trailing headers .. */
282 if (skip_crlf(buf, len, &i))
284 if (skip_crlf(buf, len, &i))
291 printf ("returning incomplete read at 2\n");
292 printf ("i=%d len=%d\n", i, len);
297 static int cs_complete_http(const char *buf, int len, int head_only)
299 /* deal with HTTP request/response */
300 int i = 2, content_len = 0, chunked = 0;
305 /* if dealing with HTTP responses - then default
306 content length is unlimited (socket close) */
307 if (!head_only && !memcmp(buf, "HTTP/", 5))
311 printf("len = %d\n", len);
312 fwrite (buf, 1, len, stdout);
313 printf("----------\n");
319 return i; /* do not allow more than 8K HTTP header */
321 if (skip_crlf(buf, len, &i))
323 if (skip_crlf(buf, len, &i))
327 return cs_read_chunk(buf, i, len);
329 { /* not chunked ; inside body */
330 if (content_len == -1)
331 return 0; /* no content length */
332 else if (len >= i + content_len)
334 return i + content_len;
339 else if (i < len - 20 &&
340 !strncasecmp((const char *) buf+i, "Transfer-Encoding:", 18))
343 while (buf[i] == ' ')
346 if (!strncasecmp((const char *) buf+i, "chunked", 7))
349 else if (i < len - 17 &&
350 !strncasecmp((const char *)buf+i, "Content-Length:", 15))
353 while (buf[i] == ' ')
356 while (i <= len-4 && yaz_isdigit(buf[i]))
357 content_len = content_len*10 + (buf[i++] - '0');
358 if (content_len < 0) /* prevent negative offsets */
370 static int cs_complete_auto_x(const char *buf, int len, int head_only)
372 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
373 && buf[1] >= 0x20 && buf[1] < 0x7f
374 && buf[2] >= 0x20 && buf[2] < 0x7f)
376 int r = cs_complete_http(buf, len, head_only);
379 return completeBER((const unsigned char *) buf, len);
383 int cs_complete_auto(const char *buf, int len)
385 return cs_complete_auto_x(buf, len, 0);
388 int cs_complete_auto_head(const char *buf, int len)
390 return cs_complete_auto_x(buf, len, 1);
393 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
395 cs->max_recv_bytes = max_recv_bytes;
401 * c-file-style: "Stroustrup"
402 * indent-tabs-mode: nil
404 * vim: shiftwidth=4 tabstop=8 expandtab