diff options
Diffstat (limited to 'src/lib/internal.c')
-rw-r--r-- | src/lib/internal.c | 281 |
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 | */ | ||
35 | const char * | ||
36 | MHD_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 | */ | ||
93 | void | ||
94 | MHD_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 | */ | ||
116 | void | ||
117 | MHD_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 | */ | ||
135 | size_t | ||
136 | MHD_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 | */ | ||
183 | int | ||
184 | MHD_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 */ | ||