1 /*
2 HTTP utility functions
3 Copyright (C) 1999-2006, Joe Orton <joe@manyfish.co.uk>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 MA 02111-1307, USA
19
20 */
21
22 #include "config.h"
23
24 #include <sys/types.h>
25
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #endif
29
30 #include <stdio.h>
31 #include <ctype.h> /* isdigit() for ne_parse_statusline */
32
33 #ifdef NE_HAVE_ZLIB
34 #include <zlib.h>
35 #endif
36
37 #ifdef HAVE_OPENSSL
38 #include <openssl/opensslv.h>
39 #endif
40
41 #ifdef HAVE_GNUTLS
42 #include <gnutls/gnutls.h>
43 #endif
44
45 /* libxml2: pick up the version string. */
46 #if defined(HAVE_LIBXML)
47 #include <libxml/xmlversion.h>
48 #elif defined(HAVE_EXPAT) && !defined(HAVE_XMLPARSE_H)
49 #include <expat.h>
50 #endif
51
52 #include "ne_utils.h"
53 #include "ne_string.h" /* for ne_strdup */
54 #include "ne_dates.h"
55
56 int ne_debug_mask = 0;
57 FILE *ne_debug_stream = NULL;
58
ne_debug_init(FILE * stream,int mask)59 void ne_debug_init(FILE *stream, int mask)
60 {
61 ne_debug_stream = stream;
62 ne_debug_mask = mask;
63 #if defined(HAVE_SETVBUF) && defined(_IONBF)
64 /* If possible, turn off buffering on the debug log. this is very
65 * helpful if debugging segfaults. */
66 if (stream) setvbuf(stream, NULL, _IONBF, 0);
67 #endif
68 }
69
ne_debug(int ch,const char * template,...)70 void ne_debug(int ch, const char *template, ...)
71 {
72 va_list params;
73 if ((ch & ne_debug_mask) == 0) return;
74 fflush(stdout);
75 va_start(params, template);
76 vfprintf(ne_debug_stream, template, params);
77 va_end(params);
78 if ((ch & NE_DBG_FLUSH) == NE_DBG_FLUSH)
79 fflush(ne_debug_stream);
80 }
81
82 #define NE_STRINGIFY(x) # x
83 #define NE_EXPAT_VER(x,y,z) NE_STRINGIFY(x) "." NE_STRINGIFY(y) "." NE_STRINGIFY(z)
84
85 static const char version_string[] = "neon " NEON_VERSION ": "
86 #ifdef NEON_IS_LIBRARY
87 "Library build"
88 #else
89 "Bundled build"
90 #endif
91 #ifdef NE_HAVE_IPV6
92 ", IPv6"
93 #endif
94 #ifdef HAVE_EXPAT
95 ", Expat"
96 /* expat >=1.95.2 exported the version */
97 #ifdef XML_MAJOR_VERSION
98 " " NE_EXPAT_VER(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION)
99 #endif
100 #else /* !HAVE_EXPAT */
101 #ifdef HAVE_LIBXML
102 ", libxml " LIBXML_DOTTED_VERSION
103 #endif /* HAVE_LIBXML */
104 #endif /* !HAVE_EXPAT */
105 #if defined(NE_HAVE_ZLIB) && defined(ZLIB_VERSION)
106 ", zlib " ZLIB_VERSION
107 #endif /* NE_HAVE_ZLIB && ... */
108 #ifdef NE_HAVE_SOCKS
109 ", SOCKSv5"
110 #endif
111 #ifdef HAVE_OPENSSL
112 #ifdef OPENSSL_VERSION_TEXT
113 ", " OPENSSL_VERSION_TEXT
114 #else
115 "OpenSSL (unknown version)"
116 #endif /* OPENSSL_VERSION_TEXT */
117 #endif /* HAVE_OPENSSL */
118 #ifdef HAVE_GNUTLS
119 ", GNU TLS " LIBGNUTLS_VERSION
120 #endif /* HAVE_GNUTLS */
121 "."
122 ;
123
ne_version_string(void)124 const char *ne_version_string(void)
125 {
126 return version_string;
127 }
128
ne_version_match(int major,int minor)129 int ne_version_match(int major, int minor)
130 {
131 return NE_VERSION_MAJOR != major || NE_VERSION_MINOR < minor
132 || (NE_VERSION_MAJOR == 0 && NE_VERSION_MINOR != minor);
133 }
134
ne_has_support(int feature)135 int ne_has_support(int feature)
136 {
137 switch (feature) {
138 #if defined(NE_HAVE_SSL) || defined(NE_HAVE_ZLIB) || defined(NE_HAVE_IPV6) \
139 || defined(NE_HAVE_SOCKS) || defined(NE_HAVE_LFS) \
140 || defined(NE_HAVE_TS_SSL) || defined(NE_HAVE_I18N)
141 #ifdef NE_HAVE_SSL
142 case NE_FEATURE_SSL:
143 #endif
144 #ifdef NE_HAVE_ZLIB
145 case NE_FEATURE_ZLIB:
146 #endif
147 #ifdef NE_HAVE_IPV6
148 case NE_FEATURE_IPV6:
149 #endif
150 #ifdef NE_HAVE_SOCKS
151 case NE_FEATURE_SOCKS:
152 #endif
153 #ifdef NE_HAVE_LFS
154 case NE_FEATURE_LFS:
155 #endif
156 #ifdef NE_HAVE_TS_SSL
157 case NE_FEATURE_TS_SSL:
158 #endif
159 #ifdef NE_HAVE_I18N
160 case NE_FEATURE_I18N:
161 #endif
162 return 1;
163 #endif /* NE_HAVE_* */
164 default:
165 return 0;
166 }
167 }
168
ne_parse_statusline(const char * status_line,ne_status * st)169 int ne_parse_statusline(const char *status_line, ne_status *st)
170 {
171 const char *part;
172 int major, minor, status_code, klass;
173
174 /* skip leading garbage if any. */
175 part = strstr(status_line, "HTTP/");
176 if (part == NULL) return -1;
177
178 minor = major = 0;
179
180 /* Parse version string, skipping leading zeroes. */
181 for (part += 5; *part != '\0' && isdigit(*part); part++)
182 major = major*10 + (*part-'0');
183
184 if (*part++ != '.') return -1;
185
186 for (;*part != '\0' && isdigit(*part); part++)
187 minor = minor*10 + (*part-'0');
188
189 if (*part != ' ') return -1;
190
191 /* Skip any spaces */
192 for (; *part == ' '; part++) /* noop */;
193
194 /* Parse the Status-Code; part now points at the first Y in
195 * "HTTP/x.x YYY". */
196 if (!isdigit(part[0]) || !isdigit(part[1]) || !isdigit(part[2]) ||
197 (part[3] != '\0' && part[3] != ' ')) return -1;
198 status_code = 100*(part[0]-'0') + 10*(part[1]-'0') + (part[2]-'0');
199 klass = part[0]-'0';
200
201 /* Skip whitespace between status-code and reason-phrase */
202 for (part+=3; *part == ' ' || *part == '\t'; part++) /* noop */;
203
204 /* part now may be pointing to \0 if reason phrase is blank */
205
206 /* Fill in the results */
207 st->major_version = major;
208 st->minor_version = minor;
209 st->reason_phrase = ne_strclean(ne_strdup(part));
210 st->code = status_code;
211 st->klass = klass;
212 return 0;
213 }
214