xref: /lighttpd1.4/src/buffer.c (revision 3b23130e)
1 #include "buffer.h"
2 
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include <stdio.h>
7 #include <assert.h>
8 #include <ctype.h>
9 
10 #if defined HAVE_STDINT_H
11 # include <stdint.h>
12 #elif defined HAVE_INTTYPES_H
13 # include <inttypes.h>
14 #endif
15 
16 static const char hex_chars[] = "0123456789abcdef";
17 
18 
19 /**
20  * init the buffer
21  *
22  */
23 
24 buffer* buffer_init(void) {
25 	buffer *b;
26 
27 	b = malloc(sizeof(*b));
28 	force_assert(b);
29 
30 	b->ptr = NULL;
31 	b->size = 0;
32 	b->used = 0;
33 
34 	return b;
35 }
36 
37 buffer *buffer_init_buffer(buffer *src) {
38 	buffer *b = buffer_init();
39 	buffer_copy_string_buffer(b, src);
40 	return b;
41 }
42 
43 /**
44  * free the buffer
45  *
46  */
47 
48 void buffer_free(buffer *b) {
49 	if (!b) return;
50 
51 	free(b->ptr);
52 	free(b);
53 }
54 
55 void buffer_reset(buffer *b) {
56 	if (!b) return;
57 
58 	/* limit don't reuse buffer larger than ... bytes */
59 	if (b->size > BUFFER_MAX_REUSE_SIZE) {
60 		free(b->ptr);
61 		b->ptr = NULL;
62 		b->size = 0;
63 	} else if (b->size) {
64 		b->ptr[0] = '\0';
65 	}
66 
67 	b->used = 0;
68 }
69 
70 
71 /**
72  *
73  * allocate (if neccessary) enough space for 'size' bytes and
74  * set the 'used' counter to 0
75  *
76  */
77 
78 #define BUFFER_PIECE_SIZE 64
79 
80 int buffer_prepare_copy(buffer *b, size_t size) {
81 	if (!b) return -1;
82 
83 	if ((0 == b->size) ||
84 	    (size > b->size)) {
85 		if (b->size) free(b->ptr);
86 
87 		b->size = size;
88 
89 		/* always allocate a multiply of BUFFER_PIECE_SIZE */
90 		b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
91 
92 		b->ptr = malloc(b->size);
93 		force_assert(b->ptr);
94 	}
95 	b->used = 0;
96 	return 0;
97 }
98 
99 /**
100  *
101  * increase the internal buffer (if neccessary) to append another 'size' byte
102  * ->used isn't changed
103  *
104  */
105 
106 int buffer_prepare_append(buffer *b, size_t size) {
107 	if (!b) return -1;
108 
109 	if (0 == b->size) {
110 		b->size = size;
111 
112 		/* always allocate a multiply of BUFFER_PIECE_SIZE */
113 		b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
114 
115 		b->ptr = malloc(b->size);
116 		b->used = 0;
117 		force_assert(b->ptr);
118 	} else if (b->used + size > b->size) {
119 		b->size += size;
120 
121 		/* always allocate a multiply of BUFFER_PIECE_SIZE */
122 		b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
123 
124 		b->ptr = realloc(b->ptr, b->size);
125 		force_assert(b->ptr);
126 	}
127 	return 0;
128 }
129 
130 int buffer_copy_string(buffer *b, const char *s) {
131 	size_t s_len;
132 
133 	if (!s || !b) return -1;
134 
135 	s_len = strlen(s) + 1;
136 	buffer_prepare_copy(b, s_len);
137 
138 	memcpy(b->ptr, s, s_len);
139 	b->used = s_len;
140 
141 	return 0;
142 }
143 
144 int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
145 	if (!s || !b) return -1;
146 #if 0
147 	/* removed optimization as we have to keep the empty string
148 	 * in some cases for the config handling
149 	 *
150 	 * url.access-deny = ( "" )
151 	 */
152 	if (s_len == 0) return 0;
153 #endif
154 	buffer_prepare_copy(b, s_len + 1);
155 
156 	memcpy(b->ptr, s, s_len);
157 	b->ptr[s_len] = '\0';
158 	b->used = s_len + 1;
159 
160 	return 0;
161 }
162 
163 int buffer_copy_string_buffer(buffer *b, const buffer *src) {
164 	if (!src) return -1;
165 
166 	if (src->used == 0) {
167 		buffer_reset(b);
168 		return 0;
169 	}
170 	return buffer_copy_string_len(b, src->ptr, src->used - 1);
171 }
172 
173 int buffer_append_string(buffer *b, const char *s) {
174 	size_t s_len;
175 
176 	if (!s || !b) return -1;
177 
178 	s_len = strlen(s);
179 	buffer_prepare_append(b, s_len + 1);
180 	if (b->used == 0)
181 		b->used++;
182 
183 	memcpy(b->ptr + b->used - 1, s, s_len + 1);
184 	b->used += s_len;
185 
186 	return 0;
187 }
188 
189 int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen) {
190 	size_t s_len;
191 
192 	if (!s || !b) return -1;
193 
194 	s_len = strlen(s);
195 	if (s_len > maxlen)  s_len = maxlen;
196 	buffer_prepare_append(b, maxlen + 1);
197 	if (b->used == 0)
198 		b->used++;
199 
200 	memcpy(b->ptr + b->used - 1, s, s_len);
201 	if (maxlen > s_len) {
202 		memset(b->ptr + b->used - 1 + s_len, ' ', maxlen - s_len);
203 	}
204 
205 	b->used += maxlen;
206 	b->ptr[b->used - 1] = '\0';
207 	return 0;
208 }
209 
210 /**
211  * append a string to the end of the buffer
212  *
213  * the resulting buffer is terminated with a '\0'
214  * s is treated as a un-terminated string (a \0 is handled a normal character)
215  *
216  * @param b a buffer
217  * @param s the string
218  * @param s_len size of the string (without the terminating \0)
219  */
220 
221 int buffer_append_string_len(buffer *b, const char *s, size_t s_len) {
222 	if (!s || !b) return -1;
223 	if (s_len == 0) return 0;
224 
225 	buffer_prepare_append(b, s_len + 1);
226 	if (b->used == 0)
227 		b->used++;
228 
229 	memcpy(b->ptr + b->used - 1, s, s_len);
230 	b->used += s_len;
231 	b->ptr[b->used - 1] = '\0';
232 
233 	return 0;
234 }
235 
236 int buffer_append_string_buffer(buffer *b, const buffer *src) {
237 	if (!src) return -1;
238 	if (src->used == 0) return 0;
239 
240 	return buffer_append_string_len(b, src->ptr, src->used - 1);
241 }
242 
243 int buffer_append_memory(buffer *b, const char *s, size_t s_len) {
244 	if (!s || !b) return -1;
245 	if (s_len == 0) return 0;
246 
247 	buffer_prepare_append(b, s_len);
248 	memcpy(b->ptr + b->used, s, s_len);
249 	b->used += s_len;
250 
251 	return 0;
252 }
253 
254 int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
255 	if (!s || !b) return -1;
256 
257 	b->used = 0;
258 
259 	return buffer_append_memory(b, s, s_len);
260 }
261 
262 int buffer_append_long_hex(buffer *b, unsigned long value) {
263 	char *buf;
264 	int shift = 0;
265 	unsigned long copy = value;
266 
267 	while (copy) {
268 		copy >>= 4;
269 		shift++;
270 	}
271 	if (shift == 0)
272 		shift++;
273 	if (shift & 0x01)
274 		shift++;
275 
276 	buffer_prepare_append(b, shift + 1);
277 	if (b->used == 0)
278 		b->used++;
279 	buf = b->ptr + (b->used - 1);
280 	b->used += shift;
281 
282 	shift <<= 2;
283 	while (shift > 0) {
284 		shift -= 4;
285 		*(buf++) = hex_chars[(value >> shift) & 0x0F];
286 	}
287 	*buf = '\0';
288 
289 	return 0;
290 }
291 
292 int LI_ltostr(char *buf, long val) {
293 	char swap;
294 	char *end;
295 	int len = 1;
296 
297 	if (val < 0) {
298 		len++;
299 		*(buf++) = '-';
300 		val = -val;
301 	}
302 
303 	end = buf;
304 	while (val > 9) {
305 		*(end++) = '0' + (val % 10);
306 		val = val / 10;
307 	}
308 	*(end) = '0' + val;
309 	*(end + 1) = '\0';
310 	len += end - buf;
311 
312 	while (buf < end) {
313 		swap = *end;
314 		*end = *buf;
315 		*buf = swap;
316 
317 		buf++;
318 		end--;
319 	}
320 
321 	return len;
322 }
323 
324 int buffer_append_long(buffer *b, long val) {
325 	if (!b) return -1;
326 
327 	buffer_prepare_append(b, 32);
328 	if (b->used == 0)
329 		b->used++;
330 
331 	b->used += LI_ltostr(b->ptr + (b->used - 1), val);
332 	return 0;
333 }
334 
335 int buffer_copy_long(buffer *b, long val) {
336 	if (!b) return -1;
337 
338 	b->used = 0;
339 	return buffer_append_long(b, val);
340 }
341 
342 #if !defined(SIZEOF_LONG) || (SIZEOF_LONG != SIZEOF_OFF_T)
343 int buffer_append_off_t(buffer *b, off_t val) {
344 	char swap;
345 	char *end;
346 	char *start;
347 	int len = 1;
348 
349 	if (!b) return -1;
350 
351 	buffer_prepare_append(b, 32);
352 	if (b->used == 0)
353 		b->used++;
354 
355 	start = b->ptr + (b->used - 1);
356 	if (val < 0) {
357 		len++;
358 		*(start++) = '-';
359 		val = -val;
360 	}
361 
362 	end = start;
363 	while (val > 9) {
364 		*(end++) = '0' + (val % 10);
365 		val = val / 10;
366 	}
367 	*(end) = '0' + val;
368 	*(end + 1) = '\0';
369 	len += end - start;
370 
371 	while (start < end) {
372 		swap   = *end;
373 		*end   = *start;
374 		*start = swap;
375 
376 		start++;
377 		end--;
378 	}
379 
380 	b->used += len;
381 	return 0;
382 }
383 
384 int buffer_copy_off_t(buffer *b, off_t val) {
385 	if (!b) return -1;
386 
387 	b->used = 0;
388 	return buffer_append_off_t(b, val);
389 }
390 #endif /* !defined(SIZEOF_LONG) || (SIZEOF_LONG != SIZEOF_OFF_T) */
391 
392 char int2hex(char c) {
393 	return hex_chars[(c & 0x0F)];
394 }
395 
396 /* converts hex char (0-9, A-Z, a-z) to decimal.
397  * returns 0xFF on invalid input.
398  */
399 char hex2int(unsigned char hex) {
400 	hex = hex - '0';
401 	if (hex > 9) {
402 		hex = (hex + '0' - 1) | 0x20;
403 		hex = hex - 'a' + 11;
404 	}
405 	if (hex > 15)
406 		hex = 0xFF;
407 
408 	return hex;
409 }
410 
411 
412 /**
413  * init the buffer
414  *
415  */
416 
417 buffer_array* buffer_array_init(void) {
418 	buffer_array *b;
419 
420 	b = malloc(sizeof(*b));
421 
422 	force_assert(b);
423 	b->ptr = NULL;
424 	b->size = 0;
425 	b->used = 0;
426 
427 	return b;
428 }
429 
430 void buffer_array_reset(buffer_array *b) {
431 	size_t i;
432 
433 	if (!b) return;
434 
435 	/* if they are too large, reduce them */
436 	for (i = 0; i < b->used; i++) {
437 		buffer_reset(b->ptr[i]);
438 	}
439 
440 	b->used = 0;
441 }
442 
443 
444 /**
445  * free the buffer_array
446  *
447  */
448 
449 void buffer_array_free(buffer_array *b) {
450 	size_t i;
451 	if (!b) return;
452 
453 	for (i = 0; i < b->size; i++) {
454 		if (b->ptr[i]) buffer_free(b->ptr[i]);
455 	}
456 	free(b->ptr);
457 	free(b);
458 }
459 
460 buffer *buffer_array_append_get_buffer(buffer_array *b) {
461 	size_t i;
462 
463 	if (b->size == 0) {
464 		b->size = 16;
465 		b->ptr = malloc(sizeof(*b->ptr) * b->size);
466 		force_assert(b->ptr);
467 		for (i = 0; i < b->size; i++) {
468 			b->ptr[i] = NULL;
469 		}
470 	} else if (b->size == b->used) {
471 		b->size += 16;
472 		b->ptr = realloc(b->ptr, sizeof(*b->ptr) * b->size);
473 		force_assert(b->ptr);
474 		for (i = b->used; i < b->size; i++) {
475 			b->ptr[i] = NULL;
476 		}
477 	}
478 
479 	if (b->ptr[b->used] == NULL) {
480 		b->ptr[b->used] = buffer_init();
481 	}
482 
483 	b->ptr[b->used]->used = 0;
484 
485 	return b->ptr[b->used++];
486 }
487 
488 
489 char * buffer_search_string_len(buffer *b, const char *needle, size_t len) {
490 	size_t i;
491 	if (len == 0) return NULL;
492 	if (needle == NULL) return NULL;
493 
494 	if (b->used < len) return NULL;
495 
496 	for(i = 0; i < b->used - len; i++) {
497 		if (0 == memcmp(b->ptr + i, needle, len)) {
498 			return b->ptr + i;
499 		}
500 	}
501 
502 	return NULL;
503 }
504 
505 buffer *buffer_init_string(const char *str) {
506 	buffer *b = buffer_init();
507 
508 	buffer_copy_string(b, str);
509 
510 	return b;
511 }
512 
513 int buffer_is_empty(buffer *b) {
514 	if (!b) return 1;
515 	return (b->used == 0);
516 }
517 
518 /**
519  * check if two buffer contain the same data
520  *
521  * HISTORY: this function was pretty much optimized, but didn't handled
522  * alignment properly.
523  */
524 
525 int buffer_is_equal(buffer *a, buffer *b) {
526 	if (a->used != b->used) return 0;
527 	if (a->used == 0) return 1;
528 
529 	return (0 == strcmp(a->ptr, b->ptr));
530 }
531 
532 int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
533 	buffer b;
534 
535 	b.ptr = (char *)s;
536 	b.used = b_len + 1;
537 
538 	return buffer_is_equal(a, &b);
539 }
540 
541 /* buffer_is_equal_caseless_string(b, CONST_STR_LEN("value")) */
542 int buffer_is_equal_caseless_string(buffer *a, const char *s, size_t b_len) {
543 	if (a->used != b_len + 1) return 0;
544 
545 	return (0 == strcasecmp(a->ptr, s));
546 }
547 
548 int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
549 	size_t const len = (a_len < b_len) ? a_len : b_len;
550 	size_t i;
551 
552 	for (i = 0; i < len; ++i) {
553 		unsigned char ca = a[i], cb = b[i];
554 		if (ca == cb) continue;
555 
556 		/* always lowercase for transitive results */
557 #if 1
558 		if (ca >= 'A' && ca <= 'Z') ca |= 32;
559 		if (cb >= 'A' && cb <= 'Z') cb |= 32;
560 #else
561 		/* try to produce code without branching (jumps) */
562 		ca |= ((unsigned char)(ca - (unsigned char)'A') <= (unsigned char)('Z' - 'A')) ? 32 : 0;
563 		cb |= ((unsigned char)(cb - (unsigned char)'A') <= (unsigned char)('Z' - 'A')) ? 32 : 0;
564 #endif
565 
566 		if (ca == cb) continue;
567 		return ca - cb;
568 	}
569 	if (a_len == b_len) return 0;
570 	return a_len - b_len;
571 }
572 
573 /**
574  * check if the rightmost bytes of the string are equal.
575  *
576  *
577  */
578 
579 int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
580 	/* no, len -> equal */
581 	if (len == 0) return 1;
582 
583 	/* len > 0, but empty buffers -> not equal */
584 	if (b1->used == 0 || b2->used == 0) return 0;
585 
586 	/* buffers too small -> not equal */
587 	if (b1->used - 1 < len || b2->used - 1 < len) return 0;
588 
589 	if (0 == strncmp(b1->ptr + b1->used - 1 - len,
590 			 b2->ptr + b2->used - 1 - len, len)) {
591 		return 1;
592 	}
593 
594 	return 0;
595 }
596 
597 int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
598 	size_t i;
599 
600 	/* BO protection */
601 	if (in_len * 2 < in_len) return -1;
602 
603 	buffer_prepare_copy(b, in_len * 2 + 1);
604 
605 	for (i = 0; i < in_len; i++) {
606 		b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
607 		b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
608 	}
609 	b->ptr[b->used++] = '\0';
610 
611 	return 0;
612 }
613 
614 /* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
615 static const char encoded_chars_rel_uri_part[] = {
616 	/*
617 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
618 	*/
619 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
620 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
621 	1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,  /*  20 -  2F space " # $ % & ' + , / */
622 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; < = > ? */
623 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */
624 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */
625 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
626 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  /*  70 -  7F { | } ~ DEL */
627 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
628 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
629 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
630 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
631 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
632 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
633 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
634 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
635 };
636 
637 /* everything except: ! ( ) * - . / 0-9 A-Z _ a-z */
638 static const char encoded_chars_rel_uri[] = {
639 	/*
640 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
641 	*/
642 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
643 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
644 	1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,  /*  20 -  2F space " # $ % & ' + , */
645 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; < = > ? */
646 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */
647 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */
648 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
649 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  /*  70 -  7F { | } ~ DEL */
650 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
651 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
652 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
653 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
654 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
655 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
656 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
657 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
658 };
659 
660 static const char encoded_chars_html[] = {
661 	/*
662 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
663 	*/
664 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
665 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
666 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
667 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
668 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
669 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
670 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */
671 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  /*  70 -  7F DEL */
672 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
673 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
674 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
675 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
676 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
677 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
678 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
679 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
680 };
681 
682 static const char encoded_chars_minimal_xml[] = {
683 	/*
684 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
685 	*/
686 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
687 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
688 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
689 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
690 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
691 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
692 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */
693 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  /*  70 -  7F DEL */
694 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  80 -  8F */
695 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  90 -  9F */
696 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  A0 -  AF */
697 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  B0 -  BF */
698 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  C0 -  CF */
699 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  D0 -  DF */
700 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  E0 -  EF */
701 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  F0 -  FF */
702 };
703 
704 static const char encoded_chars_hex[] = {
705 	/*
706 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
707 	*/
708 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
709 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
710 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */
711 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */
712 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */
713 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */
714 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */
715 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  70 -  7F */
716 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
717 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
718 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
719 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
720 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
721 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
722 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
723 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
724 };
725 
726 static const char encoded_chars_http_header[] = {
727 	/*
728 	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
729 	*/
730 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  /*  00 -  0F */
731 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  10 -  1F */
732 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F */
733 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  30 -  3F */
734 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
735 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
736 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */
737 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  70 -  7F */
738 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  80 -  8F */
739 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  90 -  9F */
740 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  A0 -  AF */
741 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  B0 -  BF */
742 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  C0 -  CF */
743 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  D0 -  DF */
744 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  E0 -  EF */
745 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  F0 -  FF */
746 };
747 
748 
749 
750 int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {
751 	unsigned char *ds, *d;
752 	size_t d_len, ndx;
753 	const char *map = NULL;
754 
755 	if (!s || !b) return -1;
756 
757 	if (b->ptr[b->used - 1] != '\0') {
758 		SEGFAULT();
759 	}
760 
761 	if (s_len == 0) return 0;
762 
763 	switch(encoding) {
764 	case ENCODING_REL_URI:
765 		map = encoded_chars_rel_uri;
766 		break;
767 	case ENCODING_REL_URI_PART:
768 		map = encoded_chars_rel_uri_part;
769 		break;
770 	case ENCODING_HTML:
771 		map = encoded_chars_html;
772 		break;
773 	case ENCODING_MINIMAL_XML:
774 		map = encoded_chars_minimal_xml;
775 		break;
776 	case ENCODING_HEX:
777 		map = encoded_chars_hex;
778 		break;
779 	case ENCODING_HTTP_HEADER:
780 		map = encoded_chars_http_header;
781 		break;
782 	case ENCODING_UNSET:
783 		break;
784 	}
785 
786 	force_assert(map != NULL);
787 
788 	/* count to-be-encoded-characters */
789 	for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
790 		if (map[*ds]) {
791 			switch(encoding) {
792 			case ENCODING_REL_URI:
793 			case ENCODING_REL_URI_PART:
794 				d_len += 3;
795 				break;
796 			case ENCODING_HTML:
797 			case ENCODING_MINIMAL_XML:
798 				d_len += 6;
799 				break;
800 			case ENCODING_HTTP_HEADER:
801 			case ENCODING_HEX:
802 				d_len += 2;
803 				break;
804 			case ENCODING_UNSET:
805 				break;
806 			}
807 		} else {
808 			d_len ++;
809 		}
810 	}
811 
812 	buffer_prepare_append(b, d_len);
813 
814 	for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
815 		if (map[*ds]) {
816 			switch(encoding) {
817 			case ENCODING_REL_URI:
818 			case ENCODING_REL_URI_PART:
819 				d[d_len++] = '%';
820 				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
821 				d[d_len++] = hex_chars[(*ds) & 0x0F];
822 				break;
823 			case ENCODING_HTML:
824 			case ENCODING_MINIMAL_XML:
825 				d[d_len++] = '&';
826 				d[d_len++] = '#';
827 				d[d_len++] = 'x';
828 				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
829 				d[d_len++] = hex_chars[(*ds) & 0x0F];
830 				d[d_len++] = ';';
831 				break;
832 			case ENCODING_HEX:
833 				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
834 				d[d_len++] = hex_chars[(*ds) & 0x0F];
835 				break;
836 			case ENCODING_HTTP_HEADER:
837 				d[d_len++] = *ds;
838 				d[d_len++] = '\t';
839 				break;
840 			case ENCODING_UNSET:
841 				break;
842 			}
843 		} else {
844 			d[d_len++] = *ds;
845 		}
846 	}
847 
848 	/* terminate buffer and calculate new length */
849 	b->ptr[b->used + d_len - 1] = '\0';
850 
851 	b->used += d_len;
852 
853 	return 0;
854 }
855 
856 
857 /* decodes url-special-chars inplace.
858  * replaces non-printable characters with '_'
859  */
860 
861 static int buffer_urldecode_internal(buffer *url, int is_query) {
862 	unsigned char high, low;
863 	const char *src;
864 	char *dst;
865 
866 	if (!url || !url->ptr) return -1;
867 
868 	src = (const char*) url->ptr;
869 	dst = (char*) url->ptr;
870 
871 	while ((*src) != '\0') {
872 		if (is_query && *src == '+') {
873 			*dst = ' ';
874 		} else if (*src == '%') {
875 			*dst = '%';
876 
877 			high = hex2int(*(src + 1));
878 			if (high != 0xFF) {
879 				low = hex2int(*(src + 2));
880 				if (low != 0xFF) {
881 					high = (high << 4) | low;
882 
883 					/* map control-characters out */
884 					if (high < 32 || high == 127) high = '_';
885 
886 					*dst = high;
887 					src += 2;
888 				}
889 			}
890 		} else {
891 			*dst = *src;
892 		}
893 
894 		dst++;
895 		src++;
896 	}
897 
898 	*dst = '\0';
899 	url->used = (dst - url->ptr) + 1;
900 
901 	return 0;
902 }
903 
904 int buffer_urldecode_path(buffer *url) {
905 	return buffer_urldecode_internal(url, 0);
906 }
907 
908 int buffer_urldecode_query(buffer *url) {
909 	return buffer_urldecode_internal(url, 1);
910 }
911 
912 /* Remove "/../", "//", "/./" parts from path.
913  *
914  * /blah/..         gets  /
915  * /blah/../foo     gets  /foo
916  * /abc/./xyz       gets  /abc/xyz
917  * /abc//xyz        gets  /abc/xyz
918  *
919  * NOTE: src and dest can point to the same buffer, in which case,
920  *       the operation is performed in-place.
921  */
922 
923 int buffer_path_simplify(buffer *dest, buffer *src)
924 {
925 	int toklen;
926 	char c, pre1;
927 	char *start, *slash, *walk, *out;
928 	unsigned short pre;
929 
930 	if (src == NULL || src->ptr == NULL || dest == NULL)
931 		return -1;
932 
933 	if (src == dest)
934 		buffer_prepare_append(dest, 1);
935 	else
936 		buffer_prepare_copy(dest, src->used + 1);
937 
938 	walk  = src->ptr;
939 	start = dest->ptr;
940 	out   = dest->ptr;
941 	slash = dest->ptr;
942 
943 
944 #if defined(__WIN32) || defined(__CYGWIN__)
945 	/* cygwin is treating \ and / the same, so we have to that too
946 	 */
947 
948 	for (walk = src->ptr; *walk; walk++) {
949 		if (*walk == '\\') *walk = '/';
950 	}
951 	walk = src->ptr;
952 #endif
953 
954 	while (*walk == ' ') {
955 		walk++;
956 	}
957 
958 	pre1 = *(walk++);
959 	c    = *(walk++);
960 	pre  = pre1;
961 	if (pre1 != '/') {
962 		pre = ('/' << 8) | pre1;
963 		*(out++) = '/';
964 	}
965 	*(out++) = pre1;
966 
967 	if (pre1 == '\0') {
968 		dest->used = (out - start) + 1;
969 		return 0;
970 	}
971 
972 	while (1) {
973 		if (c == '/' || c == '\0') {
974 			toklen = out - slash;
975 			if (toklen == 3 && pre == (('.' << 8) | '.')) {
976 				out = slash;
977 				if (out > start) {
978 					out--;
979 					while (out > start && *out != '/') {
980 						out--;
981 					}
982 				}
983 
984 				if (c == '\0')
985 					out++;
986 			} else if (toklen == 1 || pre == (('/' << 8) | '.')) {
987 				out = slash;
988 				if (c == '\0')
989 					out++;
990 			}
991 
992 			slash = out;
993 		}
994 
995 		if (c == '\0')
996 			break;
997 
998 		pre1 = c;
999 		pre  = (pre << 8) | pre1;
1000 		c    = *walk;
1001 		*out = pre1;
1002 
1003 		out++;
1004 		walk++;
1005 	}
1006 
1007 	*out = '\0';
1008 	dest->used = (out - start) + 1;
1009 
1010 	return 0;
1011 }
1012 
1013 int light_isdigit(int c) {
1014 	return (c >= '0' && c <= '9');
1015 }
1016 
1017 int light_isxdigit(int c) {
1018 	if (light_isdigit(c)) return 1;
1019 
1020 	c |= 32;
1021 	return (c >= 'a' && c <= 'f');
1022 }
1023 
1024 int light_isalpha(int c) {
1025 	c |= 32;
1026 	return (c >= 'a' && c <= 'z');
1027 }
1028 
1029 int light_isalnum(int c) {
1030 	return light_isdigit(c) || light_isalpha(c);
1031 }
1032 
1033 int buffer_to_lower(buffer *b) {
1034 	char *c;
1035 
1036 	if (b->used == 0) return 0;
1037 
1038 	for (c = b->ptr; *c; c++) {
1039 		if (*c >= 'A' && *c <= 'Z') {
1040 			*c |= 32;
1041 		}
1042 	}
1043 
1044 	return 0;
1045 }
1046 
1047 
1048 int buffer_to_upper(buffer *b) {
1049 	char *c;
1050 
1051 	if (b->used == 0) return 0;
1052 
1053 	for (c = b->ptr; *c; c++) {
1054 		if (*c >= 'a' && *c <= 'z') {
1055 			*c &= ~32;
1056 		}
1057 	}
1058 
1059 	return 0;
1060 }
1061 
1062 void log_failed_assert(const char *filename, unsigned int line, const char *msg) {
1063 	/* can't use buffer here; could lead to recursive assertions */
1064 	fprintf(stderr, "%s.%d: %s\n", filename, line, msg);
1065 	fflush(stderr);
1066 	abort();
1067 }
1068