aboutsummaryrefslogtreecommitdiff
path: root/src/lib/internal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/internal.c')
-rw-r--r--src/lib/internal.c281
1 files changed, 281 insertions, 0 deletions
diff --git a/src/lib/internal.c b/src/lib/internal.c
new file mode 100644
index 00000000..d2532c54
--- /dev/null
+++ b/src/lib/internal.c
@@ -0,0 +1,281 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file microhttpd/internal.c
22 * @brief internal shared structures
23 * @author Daniel Pittman
24 * @author Christian Grothoff
25 */
26
27#include "internal.h"
28#include "mhd_str.h"
29
30#ifdef HAVE_MESSAGES
31#if DEBUG_STATES
32/**
33 * State to string dictionary.
34 */
35const char *
36MHD_state_to_string (enum MHD_CONNECTION_STATE state)
37{
38 switch (state)
39 {
40 case MHD_CONNECTION_INIT:
41 return "connection init";
42 case MHD_CONNECTION_URL_RECEIVED:
43 return "connection url received";
44 case MHD_CONNECTION_HEADER_PART_RECEIVED:
45 return "header partially received";
46 case MHD_CONNECTION_HEADERS_RECEIVED:
47 return "headers received";
48 case MHD_CONNECTION_HEADERS_PROCESSED:
49 return "headers processed";
50 case MHD_CONNECTION_CONTINUE_SENDING:
51 return "continue sending";
52 case MHD_CONNECTION_CONTINUE_SENT:
53 return "continue sent";
54 case MHD_CONNECTION_BODY_RECEIVED:
55 return "body received";
56 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
57 return "footer partially received";
58 case MHD_CONNECTION_FOOTERS_RECEIVED:
59 return "footers received";
60 case MHD_CONNECTION_HEADERS_SENDING:
61 return "headers sending";
62 case MHD_CONNECTION_HEADERS_SENT:
63 return "headers sent";
64 case MHD_CONNECTION_NORMAL_BODY_READY:
65 return "normal body ready";
66 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
67 return "normal body unready";
68 case MHD_CONNECTION_CHUNKED_BODY_READY:
69 return "chunked body ready";
70 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
71 return "chunked body unready";
72 case MHD_CONNECTION_BODY_SENT:
73 return "body sent";
74 case MHD_CONNECTION_FOOTERS_SENDING:
75 return "footers sending";
76 case MHD_CONNECTION_FOOTERS_SENT:
77 return "footers sent";
78 case MHD_CONNECTION_CLOSED:
79 return "closed";
80 default:
81 return "unrecognized connection state";
82 }
83}
84#endif
85#endif
86
87
88#ifdef HAVE_MESSAGES
89/**
90 * fprintf-like helper function for logging debug
91 * messages.
92 */
93void
94MHD_DLOG (const struct MHD_Daemon *daemon,
95 const char *format,
96 ...)
97{
98 va_list va;
99
100 if (0 == (daemon->options & MHD_USE_ERROR_LOG))
101 return;
102 va_start (va, format);
103 daemon->custom_error_log (daemon->custom_error_log_cls,
104 format,
105 va);
106 va_end (va);
107}
108#endif
109
110
111/**
112 * Convert all occurrences of '+' to ' '.
113 *
114 * @param arg string that is modified (in place), must be 0-terminated
115 */
116void
117MHD_unescape_plus (char *arg)
118{
119 char *p;
120
121 for (p=strchr (arg, '+'); NULL != p; p = strchr (p + 1, '+'))
122 *p = ' ';
123}
124
125
126/**
127 * Process escape sequences ('%HH') Updates val in place; the
128 * result should be UTF-8 encoded and cannot be larger than the input.
129 * The result must also still be 0-terminated.
130 *
131 * @param val value to unescape (modified in the process)
132 * @return length of the resulting val (strlen(val) maybe
133 * shorter afterwards due to elimination of escape sequences)
134 */
135size_t
136MHD_http_unescape (char *val)
137{
138 char *rpos = val;
139 char *wpos = val;
140
141 while ('\0' != *rpos)
142 {
143 uint32_t num;
144 switch (*rpos)
145 {
146 case '%':
147 if (2 == MHD_strx_to_uint32_n_ (rpos + 1,
148 2,
149 &num))
150 {
151 *wpos = (char)((unsigned char) num);
152 wpos++;
153 rpos += 3;
154 break;
155 }
156 /* TODO: add bad sequence handling */
157 /* intentional fall through! */
158 default:
159 *wpos = *rpos;
160 wpos++;
161 rpos++;
162 }
163 }
164 *wpos = '\0'; /* add 0-terminator */
165 return wpos - val; /* = strlen(val) */
166}
167
168
169/**
170 * Parse and unescape the arguments given by the client
171 * as part of the HTTP request URI.
172 *
173 * @param kind header kind to pass to @a cb
174 * @param connection connection to add headers to
175 * @param[in,out] args argument URI string (after "?" in URI),
176 * clobbered in the process!
177 * @param cb function to call on each key-value pair found
178 * @param[out] num_headers set to the number of headers found
179 * @return #MHD_NO on failure (@a cb returned #MHD_NO),
180 * #MHD_YES for success (parsing succeeded, @a cb always
181 * returned #MHD_YES)
182 */
183int
184MHD_parse_arguments_ (struct MHD_Connection *connection,
185 enum MHD_ValueKind kind,
186 char *args,
187 MHD_ArgumentIterator_ cb,
188 unsigned int *num_headers)
189{
190 struct MHD_Daemon *daemon = connection->daemon;
191 char *equals;
192 char *amper;
193
194 *num_headers = 0;
195 while ( (NULL != args) &&
196 ('\0' != args[0]) )
197 {
198 equals = strchr (args, '=');
199 amper = strchr (args, '&');
200 if (NULL == amper)
201 {
202 /* last argument */
203 if (NULL == equals)
204 {
205 /* last argument, without '=' */
206 MHD_unescape_plus (args);
207 daemon->unescape_callback (daemon->unescape_callback_cls,
208 connection,
209 args);
210 if (MHD_YES != cb (connection,
211 args,
212 NULL,
213 kind))
214 return MHD_NO;
215 (*num_headers)++;
216 break;
217 }
218 /* got 'foo=bar' */
219 equals[0] = '\0';
220 equals++;
221 MHD_unescape_plus (args);
222 daemon->unescape_callback (daemon->unescape_callback_cls,
223 connection,
224 args);
225 MHD_unescape_plus (equals);
226 daemon->unescape_callback (daemon->unescape_callback_cls,
227 connection,
228 equals);
229 if (MHD_YES != cb (connection,
230 args,
231 equals,
232 kind))
233 return MHD_NO;
234 (*num_headers)++;
235 break;
236 }
237 /* amper is non-NULL here */
238 amper[0] = '\0';
239 amper++;
240 if ( (NULL == equals) ||
241 (equals >= amper) )
242 {
243 /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */
244 MHD_unescape_plus (args);
245 daemon->unescape_callback (daemon->unescape_callback_cls,
246 connection,
247 args);
248 if (MHD_YES != cb (connection,
249 args,
250 NULL,
251 kind))
252 return MHD_NO;
253 /* continue with 'bar' */
254 (*num_headers)++;
255 args = amper;
256 continue;
257 }
258 /* equals and amper are non-NULL here, and equals < amper,
259 so we got regular 'foo=value&bar...'-kind of argument */
260 equals[0] = '\0';
261 equals++;
262 MHD_unescape_plus (args);
263 daemon->unescape_callback (daemon->unescape_callback_cls,
264 connection,
265 args);
266 MHD_unescape_plus (equals);
267 daemon->unescape_callback (daemon->unescape_callback_cls,
268 connection,
269 equals);
270 if (MHD_YES != cb (connection,
271 args,
272 equals,
273 kind))
274 return MHD_NO;
275 (*num_headers)++;
276 args = amper;
277 }
278 return MHD_YES;
279}
280
281/* end of internal.c */