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