2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: comstack.c,v 1.21 2007-10-09 06:00:56 adam Exp $
10 * \brief Implements Generic COMSTACK functions
18 #include <yaz/comstack.h>
19 #include <yaz/tcpip.h>
24 #define strncasecmp _strnicmp
27 static const char *cs_errlist[] =
29 "No error or unspecified error",
30 "System (lower-layer) error",
31 "Operation out of state",
32 "No data (operation would block)",
33 "New data while half of old buffer is on the line (flow control)",
36 "Too large incoming buffer"
39 const char *cs_errmsg(int n)
43 if (n < CSNONE || n > CSLASTERROR) {
44 sprintf(buf, "unknown comstack error %d", n);
48 sprintf(buf, "%s: %s", cs_errlist[n], strerror(errno));
54 const char *cs_strerror(COMSTACK h)
56 return cs_errmsg(h->cerrno);
59 void cs_get_host_args(const char *type_and_host, const char **args)
63 if (*type_and_host && strncmp(type_and_host, "unix:", 5))
66 cp = strstr(type_and_host, "://");
77 static int cs_parse_host(const char *uri, const char **host,
78 CS_TYPE *t, enum oid_proto *proto,
82 if (strncmp(uri, "connect:", 8) == 0)
84 const char *cp = strchr(uri, ',');
87 size_t len = cp - (uri + 8);
88 *connect_host = xmalloc(len+1);
89 memcpy(*connect_host, uri + 8, len);
90 (*connect_host)[len] = '\0';
95 if (strncmp (uri, "tcp:", 4) == 0)
101 else if (strncmp (uri, "ssl:", 4) == 0)
103 #if HAVE_OPENSSL_SSL_H
106 *proto = PROTO_Z3950;
111 else if (strncmp (uri, "unix:", 5) == 0)
116 *proto = PROTO_Z3950;
121 else if (strncmp(uri, "http:", 5) == 0)
125 while (**host == '/')
129 else if (strncmp(uri, "https:", 6) == 0)
131 #if HAVE_OPENSSL_SSL_H
134 while (**host == '/')
143 *proto = PROTO_Z3950;
150 COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
152 enum oid_proto proto = PROTO_Z3950;
153 const char *host = 0;
156 char *connect_host = 0;
158 cs_parse_host(vhost, &host, &t, &proto, &connect_host);
162 cs = yaz_tcpip_create(-1, blocking, proto, connect_host ? host : 0);
166 cs = cs_create(t, blocking, proto);
170 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
180 int cs_look (COMSTACK cs)
185 static int skip_crlf(const char *buf, int len, int *i)
189 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
194 else if (buf[*i] == '\n')
203 #define CHUNK_DEBUG 0
205 static int cs_complete_http(const char *buf, int len, int head_only)
207 /* deal with HTTP request/response */
208 int i = 2, content_len = 0, chunked = 0;
213 /* if dealing with HTTP responses - then default
214 content length is unlimited (socket close) */
215 if (!head_only && !memcmp(buf, "HTTP/", 5))
219 printf("len = %d\n", len);
220 fwrite (buf, 1, len, stdout);
221 printf("----------\n");
227 return i; /* do not allow more than 8K HTTP header */
229 if (skip_crlf(buf, len, &i))
231 if (skip_crlf(buf, len, &i))
236 /* inside chunked body .. */
245 for (j = i; j <= i+3; j++)
246 printf ("%c", buf[j]);
250 /* read chunk length */
254 printf ("returning incomplete read at 1\n");
255 printf ("i=%d len=%d\n", i, len);
258 } else if (isdigit(buf[i]))
259 chunk_len = chunk_len * 16 +
261 else if (isupper(buf[i]))
262 chunk_len = chunk_len * 16 +
263 (buf[i++] - ('A'-10));
264 else if (islower(buf[i]))
265 chunk_len = chunk_len * 16 +
266 (buf[i++] - ('a'-10));
278 if (skip_crlf(buf, len, &i))
284 printf ("chunk_len=%d\n", chunk_len);
289 if (!skip_crlf(buf, len, &i))
292 /* consider trailing headers .. */
295 if (skip_crlf(buf, len, &i))
297 if (skip_crlf(buf, len, &i))
304 printf ("returning incomplete read at 2\n");
305 printf ("i=%d len=%d\n", i, len);
310 { /* not chunked ; inside body */
311 if (content_len == -1)
312 return 0; /* no content length */
313 else if (len >= i + content_len)
315 return i + content_len;
320 else if (i < len - 20 &&
321 !strncasecmp((const char *) buf+i, "Transfer-Encoding:", 18))
324 while (buf[i] == ' ')
327 if (!strncasecmp((const char *) buf+i, "chunked", 7))
330 else if (i < len - 17 &&
331 !strncasecmp((const char *)buf+i, "Content-Length:", 15))
334 while (buf[i] == ' ')
337 while (i <= len-4 && isdigit(buf[i]))
338 content_len = content_len*10 + (buf[i++] - '0');
339 if (content_len < 0) /* prevent negative offsets */
351 static int cs_complete_auto_x(const char *buf, int len, int head_only)
353 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
354 && buf[1] >= 0x20 && buf[1] < 0x7f
355 && buf[2] >= 0x20 && buf[2] < 0x7f)
357 int r = cs_complete_http(buf, len, head_only);
360 return completeBER((const unsigned char *) buf, len);
364 int cs_complete_auto(const char *buf, int len)
366 return cs_complete_auto_x(buf, len, 0);
369 int cs_complete_auto_head(const char *buf, int len)
371 return cs_complete_auto_x(buf, len, 1);
374 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
376 cs->max_recv_bytes = max_recv_bytes;
382 * indent-tabs-mode: nil
384 * vim: shiftwidth=4 tabstop=8 expandtab