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