New function cs_get_host_args for method/host/path parsing.
[yaz-moved-to-github.git] / comstack / comstack.c
1 /*
2  * Copyright (c) 1995-2003, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: comstack.c,v 1.13 2003-03-11 11:05:19 adam Exp $
6  */
7
8 #include <string.h>
9 #include <ctype.h>
10
11 #include <yaz/comstack.h>
12 #include <yaz/tcpip.h>
13 #include <yaz/unix.h>
14 #include <yaz/odr.h>
15
16 static const char *cs_errlist[] =
17 {
18     "No error or unspecified error",
19     "System (lower-layer) error",
20     "Operation out of state",
21     "No data (operation would block)",
22     "New data while half of old buffer is on the line (flow control)",
23     "Permission denied",
24     "SSL error"
25 };
26
27 const char *cs_errmsg(int n)
28 {
29     if (n < 0 || n > 6)
30         n = 0;
31     return cs_errlist[n];
32 }
33
34 const char *cs_strerror(COMSTACK h)
35 {
36     return cs_errmsg(h->cerrno);
37 }
38
39 void cs_get_host_args(const char *type_and_host, const char **args)
40 {
41     
42     *args = "";
43     if (*type_and_host && strncmp(type_and_host, "unix:", 5))
44     {
45         const char *cp;
46         cp = strstr(type_and_host, "://");
47         if (cp)
48             cp = cp+3;
49         else
50             cp = type_and_host;
51         cp = strchr(cp, '/');
52         if (cp)
53             *args = cp+1;
54     }
55 }
56
57 COMSTACK cs_create_host(const char *type_and_host, int blocking, void **vp)
58 {
59     enum oid_proto proto = PROTO_Z3950;
60     const char *host = 0;
61     COMSTACK cs;
62     CS_TYPE t;
63
64     if (strncmp (type_and_host, "tcp:", 4) == 0)
65     {
66         t = tcpip_type;
67         host = type_and_host + 4;
68     }
69     else if (strncmp (type_and_host, "ssl:", 4) == 0)
70     {
71 #if HAVE_OPENSSL_SSL_H
72         t = ssl_type;
73         host = type_and_host + 4;
74 #else
75         return 0;
76 #endif
77     }
78     else if (strncmp (type_and_host, "unix:", 5) == 0)
79     {
80 #ifndef WIN32
81         t = unix_type;
82         host = type_and_host + 5;
83 #else
84         return 0;
85 #endif
86     }
87     else if (strncmp(type_and_host, "http:", 5) == 0)
88     {
89         t = tcpip_type;
90         host = type_and_host + 5;
91         if (host[0] == '/' && host[1] == '/')
92             host = host + 2;
93         proto = PROTO_HTTP;
94     }
95     else if (strncmp(type_and_host, "https:", 6) == 0)
96     {
97 #if HAVE_OPENSSL_SSL_H
98         t = ssl_type;
99         host = type_and_host + 6;
100         if (host[0] == '/' && host[1] == '/')
101             host = host + 2;
102 #else
103         return 0;
104 #endif
105         proto = PROTO_HTTP;
106     }
107     else
108     {
109         t = tcpip_type;
110         host = type_and_host;
111         
112     }
113     cs = cs_create (t, blocking, proto);
114     if (!cs)
115         return 0;
116
117     if (!(*vp = cs_straddr(cs, host)))
118     {
119         cs_close (cs);
120         return 0;
121     }    
122     return cs;
123 }
124
125 int cs_look (COMSTACK cs)
126 {
127     return cs->event;
128 }
129
130 int cs_complete_auto(const unsigned char *buf, int len)
131 {
132     if (!len)
133         return 0;
134     if (!buf[0] && !buf[1])
135         return 0;
136     if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
137                 && buf[1] >= 0x20 && buf[1] < 0x7f
138                 && buf[2] >= 0x20 && buf[2] < 0x7f)
139     {
140         /* deal with HTTP request/response */
141         int i = 2, content_len = 0;
142
143         while (i <= len-4)
144         {
145             if (buf[i] == '\r' && buf[i+1] == '\n')
146             {
147                 i += 2;
148                 if (buf[i] == '\r' && buf[i+1] == '\n')
149                 {
150                     /* i += 2 seems not to work with GCC -O2 .. 
151                        so i+2 is used instead .. */
152                     if (len >= (i+2)+ content_len)
153                         return (i+2)+ content_len;
154                     break;
155                 }
156                 if (i < len-18)
157                 {
158                     if (!memcmp(buf+i, "Content-Length:", 15))
159                     {
160                         i+= 15;
161                         if (buf[i] == ' ')
162                             i++;
163                         content_len = 0;
164                         while (i <= len-4 && isdigit(buf[i]))
165                             content_len = content_len*10 + (buf[i++] - '0');
166                         if (content_len < 0) /* prevent negative offsets */
167                             content_len = 0;
168                     }
169                 }
170             }
171             else
172                 i++;
173         }
174         return 0;
175     }
176     return completeBER(buf, len);
177 }