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