• 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 <ctype.h>
 21 #include "uhttpd.h"
 22 
 23 bool uh_use_chunked(struct client *cl)
 24 {
 25         if (cl->request.version != UH_HTTP_VER_1_1)
 26                 return false;
 27 
 28         if (cl->request.method == UH_HTTP_MSG_HEAD || cl->request.method == UH_HTTP_MSG_OPTIONS)
 29                 return false;
 30 
 31         /* RFC2616 10.2.5, 10.3.5 */
 32         if (cl->http_code == 204 || cl->http_code == 304)
 33                 return false;
 34 
 35         return !cl->request.disable_chunked;
 36 }
 37 
 38 void uh_chunk_write(struct client *cl, const void *data, int len)
 39 {
 40         bool chunked = uh_use_chunked(cl);
 41 
 42         if (cl->state == CLIENT_STATE_CLEANUP)
 43                 return;
 44 
 45         uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000);
 46         if (chunked)
 47                 ustream_printf(cl->us, "%X\r\n", len);
 48         ustream_write(cl->us, data, len, true);
 49         if (chunked)
 50                 ustream_printf(cl->us, "\r\n");
 51 }
 52 
 53 void uh_chunk_vprintf(struct client *cl, const char *format, va_list arg)
 54 {
 55         char buf[256];
 56         va_list arg2;
 57         int len;
 58 
 59         if (cl->state != CLIENT_STATE_DATA &&
 60             cl->state != CLIENT_STATE_DONE)
 61                 return;
 62 
 63         uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000);
 64         if (!uh_use_chunked(cl)) {
 65                 ustream_vprintf(cl->us, format, arg);
 66                 return;
 67         }
 68 
 69         va_copy(arg2, arg);
 70         len = vsnprintf(buf, sizeof(buf), format, arg2);
 71         va_end(arg2);
 72 
 73         ustream_printf(cl->us, "%X\r\n", len);
 74         if (len < sizeof(buf))
 75                 ustream_write(cl->us, buf, len, true);
 76         else
 77                 ustream_vprintf(cl->us, format, arg);
 78         ustream_printf(cl->us, "\r\n");
 79 }
 80 
 81 void uh_chunk_printf(struct client *cl, const char *format, ...)
 82 {
 83         va_list arg;
 84 
 85         va_start(arg, format);
 86         uh_chunk_vprintf(cl, format, arg);
 87         va_end(arg);
 88 }
 89 
 90 void uh_chunk_eof(struct client *cl)
 91 {
 92         if (!uh_use_chunked(cl))
 93                 return;
 94 
 95         if (cl->state != CLIENT_STATE_DATA &&
 96             cl->state != CLIENT_STATE_DONE)
 97                 return;
 98 
 99         ustream_printf(cl->us, "\r\n\r\n");
100 }
101 
102 /* blen is the size of buf; slen is the length of src.  The input-string need
103 ** not be, and the output string will not be, null-terminated.  Returns the
104 ** length of the decoded string, -1 on buffer overflow, -2 on malformed string. */
105 int uh_urldecode(char *buf, int blen, const char *src, int slen)
106 {
107         int i;
108         int len = 0;
109 
110 #define hex(x) \
111         (((x) <= '9') ? ((x) - '') : \
112                 (((x) <= 'F') ? ((x) - 'A' + 10) : \
113                         ((x) - 'a' + 10)))
114 
115         for (i = 0; (i < slen) && (len < blen); i++)
116         {
117                 if (src[i] != '%') {
118                         buf[len++] = src[i];
119                         continue;
120                 }
121 
122                 if (i + 2 >= slen || !isxdigit(src[i + 1]) || !isxdigit(src[i + 2]))
123                         return -2;
124 
125                 buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
126                 i += 2;
127         }
128         buf[len] = 0;
129 
130         return (i == slen) ? len : -1;
131 }
132 
133 /* blen is the size of buf; slen is the length of src.  The input-string need
134 ** not be, and the output string will not be, null-terminated.  Returns the
135 ** length of the encoded string, or -1 on error (buffer overflow) */
136 int uh_urlencode(char *buf, int blen, const char *src, int slen)
137 {
138         int i;
139         int len = 0;
140         static const char hex[] = "0123456789abcdef";
141 
142         for (i = 0; (i < slen) && (len < blen); i++)
143         {
144                 if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
145                     (src[i] == '.') || (src[i] == '~') )
146                 {
147                         buf[len++] = src[i];
148                 }
149                 else if ((len+3) <= blen)
150                 {
151                         buf[len++] = '%';
152                         buf[len++] = hex[(src[i] >> 4) & 15];
153                         buf[len++] = hex[ src[i]       & 15];
154                 }
155                 else
156                 {
157                         len = -1;
158                         break;
159                 }
160         }
161 
162         return (i == slen) ? len : -1;
163 }
164 
165 int uh_b64decode(char *buf, int blen, const void *src, int slen)
166 {
167         const unsigned char *str = src;
168         unsigned int cout = 0;
169         unsigned int cin  = 0;
170         int len = 0;
171         int i = 0;
172 
173         for (i = 0; (i <= slen) && (str[i] != 0); i++)
174         {
175                 cin = str[i];
176 
177                 if ((cin >= '') && (cin <= '9'))
178                         cin = cin - '' + 52;
179                 else if ((cin >= 'A') && (cin <= 'Z'))
180                         cin = cin - 'A';
181                 else if ((cin >= 'a') && (cin <= 'z'))
182                         cin = cin - 'a' + 26;
183                 else if (cin == '+')
184                         cin = 62;
185                 else if (cin == '/')
186                         cin = 63;
187                 else if (cin == '=')
188                         cin = 0;
189                 else
190                         continue;
191 
192                 cout = (cout << 6) | cin;
193 
194                 if ((i % 4) != 3)
195                         continue;
196 
197                 if ((len + 3) >= blen)
198                         break;
199 
200                 buf[len++] = (char)(cout >> 16);
201                 buf[len++] = (char)(cout >> 8);
202                 buf[len++] = (char)(cout);
203         }
204 
205         buf[len++] = 0;
206         return len;
207 }
208 
209 bool uh_path_match(const char *prefix, const char *url)
210 {
211         int len = strlen(prefix);
212 
213         /* A prefix of "/" will - by definition - match any url */
214         if (prefix[0] == '/' && len == 1)
215                 return true;
216 
217         if (strncmp(url, prefix, len) != 0)
218                 return false;
219 
220         return url[len] == '/' || url[len] == '?' || url[len] == 0;
221 }
222 
223 char *uh_split_header(char *str)
224 {
225         char *val;
226 
227         val = strchr(str, ':');
228         if (!val)
229                 return NULL;
230 
231         *val = 0;
232         val++;
233 
234         while (isspace(*val))
235                 val++;
236 
237         return val;
238 }
239 
240 bool uh_addr_rfc1918(struct uh_addr *addr)
241 {
242         uint32_t a;
243 
244         if (addr->family != AF_INET)
245                 return false;
246 
247         a = htonl(addr->in.s_addr);
248         return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) ||
249                ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) ||
250                ((a >= 0xC0A80000) && (a <= 0xC0A8FFFF));
251 
252         return 0;
253 }
254 
255 
256 static bool is_html_special_char(char c)
257 {
258         switch (c)
259         {
260         case 0x22:
261         case 0x26:
262         case 0x27:
263         case 0x3C:
264         case 0x3E:
265                 return true;
266 
267         default:
268                 return false;
269         }
270 }
271 
272 char *uh_htmlescape(const char *str)
273 {
274         size_t i, len;
275         char *p, *copy;
276 
277         for (i = 0, len = 1; str[i]; i++)
278                 if (is_html_special_char(str[i]))
279                         len += 6; /* &#x??; */
280                 else
281                         len++;
282 
283         copy = calloc(1, len);
284 
285         if (!copy)
286                 return NULL;
287 
288         for (i = 0, p = copy; str[i]; i++)
289                 if (is_html_special_char(str[i]))
290                         p += sprintf(p, "&#x%02x;", (unsigned int)str[i]);
291                 else
292                         *p++ = str[i];
293 
294         return copy;
295 }
296 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt