• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/uhttpd/utils.c

  1 /*
  2  * uhttpd - Tiny single-threaded httpd
  3  *
  4  *   Copyright (C) 2010-2013 Jo-Philipp Wich <xm@subsignal.org>
  5  *   Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  6  *
  7  * Permission to use, copy, modify, and/or distribute this software for any
  8  * purpose with or without fee is hereby granted, provided that the above
  9  * copyright notice and this permission notice appear in all copies.
 10  *
 11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 18  */
 19 
 20 #include "uhttpd.h"
 21 
 22 uint8_t chartypes[256] = {
 23 /* 00..07 */ CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL,
 24 /* 08..0f */ CT_CTL, CT_WSP, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL,
 25 /* 10..17 */ CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL,
 26 /* 18..1f */ CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL,
 27 /* 20..27 */ CT_WSP, CT_VCHAR, CT_VDELIM, CT_VCHAR, CT_VCHAR, CT_VCHAR, CT_VCHAR, CT_VCHAR,
 28 /* 28..2f */ CT_VDELIM, CT_VDELIM, CT_VCHAR, CT_VCHAR, CT_VDELIM, CT_VCHAR, CT_VCHAR, CT_VDELIM,
 29 /* 30..37 */ CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, CT_XDIGIT,
 30 /* 38..3f */ CT_XDIGIT, CT_XDIGIT, CT_VDELIM, CT_VDELIM, CT_VDELIM, CT_VDELIM, CT_VDELIM, CT_VDELIM,
 31 /* 40..47 */ CT_VDELIM, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_VALPHA,
 32 /* 48..4f */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA,
 33 /* 50..57 */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA,
 34 /* 58..5f */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VDELIM, CT_VDELIM, CT_VDELIM, CT_VCHAR, CT_VCHAR,
 35 /* 60..67 */ CT_VCHAR, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_VALPHA,
 36 /* 68..6f */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA,
 37 /* 70..77 */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA,
 38 /* 78..7f */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VDELIM, CT_VCHAR, CT_VDELIM, CT_VCHAR, CT_CTL,
 39 /* 80..ff: no flags */
 40 };
 41 
 42 bool uh_use_chunked(struct client *cl)
 43 {
 44         if (cl->request.version != UH_HTTP_VER_1_1)
 45                 return false;
 46 
 47         if (cl->request.method == UH_HTTP_MSG_HEAD || cl->request.method == UH_HTTP_MSG_OPTIONS)
 48                 return false;
 49 
 50         /* RFC2616 10.2.5, 10.3.5 */
 51         if (cl->http_code == 204 || cl->http_code == 304)
 52                 return false;
 53 
 54         return !cl->request.disable_chunked;
 55 }
 56 
 57 void uh_chunk_write(struct client *cl, const void *data, int len)
 58 {
 59         bool chunked = uh_use_chunked(cl);
 60 
 61         if (cl->state == CLIENT_STATE_CLEANUP)
 62                 return;
 63 
 64         uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000);
 65         if (chunked)
 66                 ustream_printf(cl->us, "%X\r\n", len);
 67         ustream_write(cl->us, data, len, true);
 68         if (chunked)
 69                 ustream_printf(cl->us, "\r\n");
 70 }
 71 
 72 void uh_chunk_vprintf(struct client *cl, const char *format, va_list arg)
 73 {
 74         char buf[256];
 75         va_list arg2;
 76         int len;
 77 
 78         if (cl->state != CLIENT_STATE_DATA &&
 79             cl->state != CLIENT_STATE_DONE)
 80                 return;
 81 
 82         uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000);
 83         if (!uh_use_chunked(cl)) {
 84                 ustream_vprintf(cl->us, format, arg);
 85                 return;
 86         }
 87 
 88         va_copy(arg2, arg);
 89         len = vsnprintf(buf, sizeof(buf), format, arg2);
 90         va_end(arg2);
 91 
 92         ustream_printf(cl->us, "%X\r\n", len);
 93         if (len < sizeof(buf))
 94                 ustream_write(cl->us, buf, len, true);
 95         else
 96                 ustream_vprintf(cl->us, format, arg);
 97         ustream_printf(cl->us, "\r\n");
 98 }
 99 
100 void uh_chunk_printf(struct client *cl, const char *format, ...)
101 {
102         va_list arg;
103 
104         va_start(arg, format);
105         uh_chunk_vprintf(cl, format, arg);
106         va_end(arg);
107 }
108 
109 void uh_chunk_eof(struct client *cl)
110 {
111         if (!uh_use_chunked(cl))
112                 return;
113 
114         if (cl->state != CLIENT_STATE_DATA &&
115             cl->state != CLIENT_STATE_DONE)
116                 return;
117 
118         ustream_printf(cl->us, "\r\n\r\n");
119 }
120 
121 /* blen is the size of buf; slen is the length of src.  The input-string need
122 ** not be null-terminated. The output string is always null-terminated when
123 ** blen > 0. Returns the length of the decoded string (excluding the trailing
124 ** NUL), -1 on buffer overflow, -2 on malformed string. */
125 int uh_urldecode(char *buf, int blen, const char *src, int slen)
126 {
127         int i;
128         int len = 0;
129 
130 #define hex(x) \
131         (((x) <= '9') ? ((x) - '') : \
132                 (((x) <= 'F') ? ((x) - 'A' + 10) : \
133                         ((x) - 'a' + 10)))
134 
135         if (blen <= 0)
136                 return -1;
137 
138         for (i = 0; (i < slen) && (len < blen - 1); i++)
139         {
140                 if (src[i] != '%') {
141                         buf[len++] = src[i];
142                         continue;
143                 }
144 
145                 if (i + 2 >= slen ||
146                     !(chartypes[(uint8_t)src[i + 1]] & CT_HEXDIG) ||
147                     !(chartypes[(uint8_t)src[i + 2]] & CT_HEXDIG))
148                         return -2;
149 
150                 buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
151                 i += 2;
152         }
153         buf[len] = 0;
154 
155         return (i == slen) ? len : -1;
156 }
157 
158 /* blen is the size of buf; slen is the length of src.  The input-string need
159 ** not be, and the output string will not be, null-terminated.  Returns the
160 ** length of the encoded string, or -1 on error (buffer overflow) */
161 int uh_urlencode(char *buf, int blen, const char *src, int slen)
162 {
163         int i;
164         int len = 0;
165         static const char hex[] = "0123456789abcdef";
166 
167         for (i = 0; (i < slen) && (len < blen); i++)
168         {
169                 if( (chartypes[(uint8_t)src[i]] & (CT_ALPHA | CT_DIGIT)) || (src[i] == '-') || (src[i] == '_') ||
170                     (src[i] == '.') || (src[i] == '~') )
171                 {
172                         buf[len++] = src[i];
173                 }
174                 else if ((len+3) <= blen)
175                 {
176                         buf[len++] = '%';
177                         buf[len++] = hex[(src[i] >> 4) & 15];
178                         buf[len++] = hex[ src[i]       & 15];
179                 }
180                 else
181                 {
182                         len = -1;
183                         break;
184                 }
185         }
186 
187         return (i == slen) ? len : -1;
188 }
189 
190 int uh_b64decode(char *buf, int blen, const void *src, int slen)
191 {
192         const unsigned char *str = src;
193         unsigned int cout = 0;
194         unsigned int cin  = 0;
195         int len = 0;
196         int i = 0;
197 
198         for (i = 0; (i < slen) && (str[i] != 0); i++)
199         {
200                 cin = str[i];
201 
202                 if ((cin >= '') && (cin <= '9'))
203                         cin = cin - '' + 52;
204                 else if ((cin >= 'A') && (cin <= 'Z'))
205                         cin = cin - 'A';
206                 else if ((cin >= 'a') && (cin <= 'z'))
207                         cin = cin - 'a' + 26;
208                 else if (cin == '+')
209                         cin = 62;
210                 else if (cin == '/')
211                         cin = 63;
212                 else if (cin == '=')
213                         cin = 0;
214                 else
215                         continue;
216 
217                 cout = (cout << 6) | cin;
218 
219                 if ((i % 4) != 3)
220                         continue;
221 
222                 if ((len + 3) >= blen)
223                         break;
224 
225                 buf[len++] = (char)(cout >> 16);
226                 buf[len++] = (char)(cout >> 8);
227                 buf[len++] = (char)(cout);
228         }
229 
230         buf[len++] = 0;
231         return len;
232 }
233 
234 bool uh_path_match(const char *prefix, const char *url)
235 {
236         int len = strlen(prefix);
237 
238         /* A prefix of "/" will - by definition - match any url */
239         if (prefix[0] == '/' && len == 1)
240                 return true;
241 
242         if (strncmp(url, prefix, len) != 0)
243                 return false;
244 
245         return url[len] == '/' || url[len] == '?' || url[len] == 0;
246 }
247 
248 char *uh_split_header(char *str, size_t len)
249 {
250         char *val, *end;
251 
252         val = memchr(str, ':', len);
253 
254         if (!val)
255                 return NULL;
256 
257         *val++ = 0;
258 
259         while (chartypes[(uint8_t)*val] & CT_WSP)
260                 val++;
261 
262         for (end = str + len - 1; end > val && (chartypes[(uint8_t)*end] & CT_WSP); end--)
263                 ;
264 
265         *(end + 1) = 0;
266 
267         return val;
268 }
269 
270 bool uh_addr_rfc1918(struct uh_addr *addr)
271 {
272         uint32_t a;
273 
274         if (addr->family != AF_INET)
275                 return false;
276 
277         a = htonl(addr->in.s_addr);
278         return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) ||
279                ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) ||
280                ((a >= 0xC0A80000) && (a <= 0xC0A8FFFF));
281 }
282 
283 
284 static bool is_html_special_char(char c)
285 {
286         switch (c)
287         {
288         case 0x22:
289         case 0x26:
290         case 0x27:
291         case 0x3C:
292         case 0x3E:
293                 return true;
294 
295         default:
296                 return false;
297         }
298 }
299 
300 char *uh_htmlescape(const char *str)
301 {
302         size_t i, len;
303         char *p, *copy;
304 
305         for (i = 0, len = 1; str[i]; i++)
306                 if (is_html_special_char(str[i]))
307                         len += 6; /* &#x??; */
308                 else
309                         len++;
310 
311         copy = calloc(1, len);
312 
313         if (!copy)
314                 return NULL;
315 
316         for (i = 0, p = copy; str[i]; i++)
317                 if (is_html_special_char(str[i]))
318                         p += sprintf(p, "&#x%02x;", (unsigned int)str[i]);
319                 else
320                         *p++ = str[i];
321 
322         return copy;
323 }
324 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt