1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 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 static const char *cs_errlist[] =
30 "No error or unspecified error",
31 "System (lower-layer) error",
32 "Operation out of state",
33 "No data (operation would block)",
34 "New data while half of old buffer is on the line (flow control)",
37 "Too large incoming buffer"
40 const char *cs_errmsg(int n)
44 if (n < CSNONE || n > CSLASTERROR) {
45 sprintf(buf, "unknown comstack error %d", n);
49 sprintf(buf, "%s: %s", cs_errlist[n], strerror(errno));
55 const char *cs_strerror(COMSTACK h)
57 return cs_errmsg(h->cerrno);
60 void cs_get_host_args(const char *type_and_host, const char **args)
64 if (!strncmp(type_and_host, "unix:", 5))
66 const char *cp = strchr(type_and_host + 5, ':');
68 type_and_host = cp + 1;
70 type_and_host += strlen(type_and_host); /* empty string */
75 cp = strstr(type_and_host, "://");
86 int cs_parse_host(const char *uri, const char **host,
87 CS_TYPE *t, enum oid_proto *proto,
93 if (strncmp(uri, "connect:", 8) == 0)
95 const char *cp = strchr(uri, ',');
102 *connect_host = (char *) xmalloc(len + 1);
103 memcpy(*connect_host, uri, len);
104 (*connect_host)[len] = '\0';
108 else if (strncmp(uri, "unix:", 5) == 0)
113 cp = strchr(uri, ':');
116 size_t len = cp - uri;
117 *connect_host = (char *) xmalloc(len + 1);
118 memcpy(*connect_host, uri, len);
119 (*connect_host)[len] = '\0';
123 xfree(*connect_host);
131 if (strncmp (uri, "tcp:", 4) == 0)
134 *proto = PROTO_Z3950;
136 else if (strncmp (uri, "ssl:", 4) == 0)
141 *proto = PROTO_Z3950;
143 xfree(*connect_host);
148 else if (strncmp(uri, "http:", 5) == 0)
151 while (**host == '/')
155 else if (strncmp(uri, "https:", 6) == 0)
160 while (**host == '/')
164 xfree(*connect_host);
172 *proto = PROTO_Z3950;
177 COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
179 return cs_create_host_proxy(vhost, blocking, vp, 0);
182 COMSTACK cs_create_host_proxy(const char *vhost, int blocking, void **vp,
183 const char *proxy_host)
185 enum oid_proto proto = PROTO_Z3950;
186 const char *host = 0;
189 char *connect_host = 0;
191 if (!cs_parse_host(vhost, &host, &t, &proto, &connect_host))
196 enum oid_proto proto1;
199 if (!cs_parse_host(proxy_host, &host, &t, &proto1, &connect_host))
205 cs = yaz_tcpip_create(-1, blocking, proto, connect_host ? host : 0);
209 cs = cs_create(t, blocking, proto);
213 if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
223 int cs_look (COMSTACK cs)
228 static int skip_crlf(const char *buf, int len, int *i)
232 if (buf[*i] == '\r' && *i < len-1 && buf[*i + 1] == '\n')
237 else if (buf[*i] == '\n')
246 #define CHUNK_DEBUG 0
248 static int cs_read_chunk(const char *buf, int i, int len)
250 /* inside chunked body .. */
259 for (j = i; j <= i+3; j++)
260 printf ("%c", buf[j]);
264 /* read chunk length */
268 printf ("returning incomplete read at 1\n");
269 printf ("i=%d len=%d\n", i, len);
272 } else if (yaz_isdigit(buf[i]))
273 chunk_len = chunk_len * 16 +
275 else if (yaz_isupper(buf[i]))
276 chunk_len = chunk_len * 16 +
277 (buf[i++] - ('A'-10));
278 else if (yaz_islower(buf[i]))
279 chunk_len = chunk_len * 16 +
280 (buf[i++] - ('a'-10));
292 if (skip_crlf(buf, len, &i))
298 printf ("chunk_len=%d\n", chunk_len);
303 if (!skip_crlf(buf, len, &i))
306 /* consider trailing headers .. */
309 if (skip_crlf(buf, len, &i))
311 if (skip_crlf(buf, len, &i))
318 printf ("returning incomplete read at 2\n");
319 printf ("i=%d len=%d\n", i, len);
324 static int cs_complete_http(const char *buf, int len, int head_only)
326 /* deal with HTTP request/response */
327 int i, content_len = 0, chunked = 0;
329 /* need at least one line followed by \n or \r .. */
332 return 0; /* incomplete */
333 else if (buf[i] == '\n' || buf[i] == '\r')
336 /* check to see if it's a response with content */
337 if (!head_only && !memcmp(buf, "HTTP/", 5))
340 for (j = 5; j < i; j++)
344 if (buf[j] == '1') /* 1XX */
346 else if (!memcmp(buf + j, "204", 3))
348 else if (!memcmp(buf + j, "304", 3))
356 printf("len = %d\n", len);
357 fwrite (buf, 1, len, stdout);
358 printf("----------\n");
360 for (i = 2; i <= len-2; )
364 return i; /* do not allow more than 8K HTTP header */
366 if (skip_crlf(buf, len, &i))
368 if (skip_crlf(buf, len, &i))
372 return cs_read_chunk(buf, i, len);
374 { /* not chunked ; inside body */
375 if (content_len == -1)
376 return 0; /* no content length */
377 else if (len >= i + content_len)
379 return i + content_len;
384 else if (i < len - 20 &&
385 !yaz_strncasecmp((const char *) buf+i,
386 "Transfer-Encoding:", 18))
389 while (buf[i] == ' ')
392 if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7))
395 else if (i < len - 17 &&
396 !yaz_strncasecmp((const char *)buf+i,
397 "Content-Length:", 15))
400 while (buf[i] == ' ')
403 while (i <= len-4 && yaz_isdigit(buf[i]))
404 content_len = content_len*10 + (buf[i++] - '0');
405 if (content_len < 0) /* prevent negative offsets */
417 static int cs_complete_auto_x(const char *buf, int len, int head_only)
419 if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
420 && buf[1] >= 0x20 && buf[1] < 0x7f
421 && buf[2] >= 0x20 && buf[2] < 0x7f)
423 int r = cs_complete_http(buf, len, head_only);
426 return completeBER(buf, len);
430 int cs_complete_auto(const char *buf, int len)
432 return cs_complete_auto_x(buf, len, 0);
435 int cs_complete_auto_head(const char *buf, int len)
437 return cs_complete_auto_x(buf, len, 1);
440 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
442 cs->max_recv_bytes = max_recv_bytes;
448 * c-file-style: "Stroustrup"
449 * indent-tabs-mode: nil
451 * vim: shiftwidth=4 tabstop=8 expandtab