1 /*
2 HTTP utility functions
3 Copyright (C) 1999-2004, 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 NEON_SSL
34 #include <openssl/opensslv.h>
35 #endif
36
37 /* libxml2: pick up the version string. */
38 #if defined(HAVE_LIBXML)
39 #include <libxml/xmlversion.h>
40 #elif defined(HAVE_EXPAT) && !defined(HAVE_XMLPARSE_H)
41 #include <expat.h>
42 #endif
43
44 #ifdef NEON_ZLIB
45 #include <zlib.h>
46 #endif
47
48 #include "ne_utils.h"
49 #include "ne_string.h" /* for ne_strdup */
50 #include "ne_dates.h"
51
52 int ne_debug_mask = 0;
53 FILE *ne_debug_stream = NULL;
54
ne_debug_init(FILE * stream,int mask)55 void ne_debug_init(FILE *stream, int mask)
56 {
57 ne_debug_stream = stream;
58 ne_debug_mask = mask;
59 #if defined(HAVE_SETVBUF) && defined(_IONBF)
60 /* If possible, turn off buffering on the debug log. this is very
61 * helpful if debugging segfaults. */
62 if (stream) setvbuf(stream, NULL, _IONBF, 0);
63 #endif
64 }
65
ne_debug(int ch,const char * template,...)66 void ne_debug(int ch, const char *template, ...)
67 {
68 va_list params;
69 if ((ch & ne_debug_mask) == 0) return;
70 fflush(stdout);
71 va_start(params, template);
72 vfprintf(ne_debug_stream, template, params);
73 va_end(params);
74 if ((ch & NE_DBG_FLUSH) == NE_DBG_FLUSH)
75 fflush(ne_debug_stream);
76 }
77
78 #define NE_STRINGIFY(x) # x
79 #define NE_EXPAT_VER(x,y,z) NE_STRINGIFY(x) "." NE_STRINGIFY(y) "." NE_STRINGIFY(z)
80
81 static const char *version_string = "neon " NEON_VERSION ": "
82 #ifdef NEON_IS_LIBRARY
83 "Library build"
84 #else
85 "Bundled build"
86 #endif
87 #ifdef HAVE_EXPAT
88 ", Expat"
89 /* expat >=1.95.2 exported the version */
90 #ifdef XML_MAJOR_VERSION
91 " " NE_EXPAT_VER(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION)
92 #endif
93 #else /* !HAVE_EXPAT */
94 #ifdef HAVE_LIBXML
95 ", libxml " LIBXML_DOTTED_VERSION
96 #endif /* HAVE_LIBXML */
97 #endif /* !HAVE_EXPAT */
98 #if defined(NEON_ZLIB) && defined(ZLIB_VERSION)
99 ", zlib " ZLIB_VERSION
100 #endif /* NEON_ZLIB && ... */
101 #ifdef NEON_SOCKS
102 ", SOCKSv5"
103 #endif
104 #ifdef NEON_SSL
105 #ifdef OPENSSL_VERSION_TEXT
106 ", " OPENSSL_VERSION_TEXT
107 #else
108 "OpenSSL (unknown version)"
109 #endif /* OPENSSL_VERSION_TEXT */
110 #endif
111 "."
112 ;
113
ne_version_string(void)114 const char *ne_version_string(void)
115 {
116 return version_string;
117 }
118
ne_version_match(int major,int minor)119 int ne_version_match(int major, int minor)
120 {
121 return (NEON_VERSION_MAJOR != major) || (NEON_VERSION_MINOR < minor);
122 }
123
ne_supports_ssl(void)124 int ne_supports_ssl(void)
125 {
126 #ifdef NEON_SSL
127 return 1;
128 #else
129 return 0;
130 #endif
131 }
132
ne_parse_statusline(const char * status_line,ne_status * st)133 int ne_parse_statusline(const char *status_line, ne_status *st)
134 {
135 const char *part;
136 int major, minor, status_code, klass;
137
138 /* skip leading garbage if any. */
139 part = strstr(status_line, "HTTP/");
140 if (part == NULL) return -1;
141
142 minor = major = 0;
143
144 /* Parse version string, skipping leading zeroes. */
145 for (part += 5; *part != '\0' && isdigit(*part); part++)
146 major = major*10 + (*part-'0');
147
148 if (*part++ != '.') return -1;
149
150 for (;*part != '\0' && isdigit(*part); part++)
151 minor = minor*10 + (*part-'0');
152
153 if (*part != ' ') return -1;
154
155 /* Skip any spaces */
156 for (; *part == ' '; part++) /* noop */;
157
158 /* Parse the Status-Code; part now points at the first Y in
159 * "HTTP/x.x YYY". */
160 if (!isdigit(part[0]) || !isdigit(part[1]) || !isdigit(part[2]) ||
161 (part[3] != '\0' && part[3] != ' ')) return -1;
162 status_code = 100*(part[0]-'0') + 10*(part[1]-'0') + (part[2]-'0');
163 klass = part[0]-'0';
164
165 /* Skip whitespace between status-code and reason-phrase */
166 for (part+=3; *part == ' ' || *part == '\t'; part++) /* noop */;
167
168 /* part now may be pointing to \0 if reason phrase is blank */
169
170 /* Fill in the results */
171 st->major_version = major;
172 st->minor_version = minor;
173 st->reason_phrase = ne_strclean(ne_strdup(part));
174 st->code = status_code;
175 st->klass = klass;
176 return 0;
177 }
178