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