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