mhd_str.h (39950B)
1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ 2 /* 3 This file is part of GNU libmicrohttpd. 4 Copyright (C) 2015-2024 Evgeny Grin (Karlson2k) 5 6 GNU libmicrohttpd is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 GNU libmicrohttpd is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 Alternatively, you can redistribute GNU libmicrohttpd and/or 17 modify it under the terms of the GNU General Public License as 18 published by the Free Software Foundation; either version 2 of 19 the License, or (at your option) any later version, together 20 with the eCos exception, as follows: 21 22 As a special exception, if other files instantiate templates or 23 use macros or inline functions from this file, or you compile this 24 file and link it with other works to produce a work based on this 25 file, this file does not by itself cause the resulting work to be 26 covered by the GNU General Public License. However the source code 27 for this file must still be made available in accordance with 28 section (3) of the GNU General Public License v2. 29 30 This exception does not invalidate any other reasons why a work 31 based on this file might be covered by the GNU General Public 32 License. 33 34 You should have received copies of the GNU Lesser General Public 35 License and the GNU General Public License along with this library; 36 if not, see <https://www.gnu.org/licenses/>. 37 */ 38 39 /** 40 * @file src/mhd2/mhd_str.h 41 * @brief Header for string manipulating helpers 42 * @author Karlson2k (Evgeny Grin) 43 */ 44 45 #ifndef MHD_STR_H 46 #define MHD_STR_H 1 47 48 #include "mhd_sys_options.h" 49 50 #include "sys_base_types.h" 51 #include "sys_bool_type.h" 52 53 #include "mhd_str_types.h" 54 #include "mhd_buffer.h" 55 56 #include "mhd_str_macros.h" 57 58 #ifdef MHD_FAVOR_SMALL_CODE 59 # include "mhd_limits.h" 60 #endif 61 62 #ifndef mhd_HAVE_STR_TO_UPPER 63 # ifdef MHD_SUPPORT_GNUTLS 64 # define mhd_HAVE_STR_TO_UPPER 1 65 # endif 66 #endif 67 68 /* 69 * Block of functions/macros that use US-ASCII charset as required by HTTP 70 * standards. Not affected by current locale settings. 71 */ 72 73 #ifndef MHD_FAVOR_SMALL_CODE 74 /** 75 * Check two strings for equality, ignoring case of US-ASCII letters. 76 * 77 * @param str1 first string to compare 78 * @param str2 second string to compare 79 * @return 'true' if two strings are equal, 'false' otherwise. 80 */ 81 MHD_INTERNAL bool 82 mhd_str_equal_caseless (const char *str1, 83 const char *str2) 84 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_CSTR_ (2); 85 86 #else /* MHD_FAVOR_SMALL_CODE */ 87 /* Reuse mhd_str_equal_caseless_n() to reduce size */ 88 #define mhd_str_equal_caseless(s1,s2) \ 89 mhd_str_equal_caseless_n ((s1),(s2), SIZE_MAX) 90 #endif /* MHD_FAVOR_SMALL_CODE */ 91 92 93 /** 94 * Check two string for equality, ignoring case of US-ASCII letters and 95 * checking not more than @a maxlen characters. 96 * Compares up to first terminating null character, but not more than 97 * first @a maxlen characters. 98 * @param str1 first string to compare 99 * @param str2 second string to compare 100 * @param maxlen maximum number of characters to compare 101 * @return 'true' if two strings are equal, 'false' otherwise. 102 */ 103 MHD_INTERNAL bool 104 mhd_str_equal_caseless_n (const char *const str1, 105 const char *const str2, 106 size_t maxlen) 107 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2); 108 109 110 /** 111 * Check two string for equality, ignoring case of US-ASCII letters and 112 * checking not more than @a len bytes. 113 * Compares not more first than @a len bytes, including binary zero characters. 114 * Comparison stops at first unmatched byte. 115 * @param str1 first string to compare 116 * @param str2 second string to compare 117 * @param len number of characters to compare 118 * @return 'true' if two strings are equal, 'false' otherwise. 119 */ 120 MHD_INTERNAL bool 121 mhd_str_equal_caseless_bin_n (const char *const str1, 122 const char *const str2, 123 size_t len) 124 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2); 125 126 127 /** 128 * Check whether string is equal statically allocated another string, 129 * ignoring case of US-ASCII letters and checking not more than @a len bytes. 130 * 131 * If strings have different sizes (lengths) then macro returns boolean false 132 * without checking the content. 133 * 134 * Compares not more first than @a len bytes, including binary zero characters. 135 * Comparison stops at first unmatched byte. 136 * @param arr the statically allocated string to compare 137 * @param str the string to compare 138 * @param l the number of characters in the @a s string 139 * @return 'true' if two strings are equal, 'false' otherwise. 140 */ 141 #define mhd_str_equal_caseless_n_st(arr,str,l) \ 142 ((mhd_SSTR_LEN (arr) == (l)) \ 143 && mhd_str_equal_caseless_bin_n (arr,str,l)) 144 145 /** 146 * Check two string for equality, converting first string to US-ASCII lower case 147 * before comparing and checking not more than @a len bytes. 148 * Compares not more first than @a len bytes, including binary zero characters. 149 * Comparison stops at first unmatched byte. 150 * @param mixstr mixed case string to compare 151 * @param lowstr lower case string to compare, 152 * must have no US-ASCII uppercase characters 153 * @param len number of characters to compare 154 * @return 'true' if two strings are equal, 'false' otherwise. 155 */ 156 MHD_INTERNAL bool 157 mhd_str_equal_lowercase_bin_n (const char *const mixstr, 158 const char *const lowstr, 159 size_t len) 160 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2); 161 162 /** 163 * Convert sequence of bytes to lower case US-ASCII letters. 164 * @param size the size of the data in the @a inbuff 165 * @param inbuff the input data, does not need to be zero-terminated; 166 * if it is zero-terminated and zero-termination of @a outbuff 167 * is needed, make sure that @a size includes zero-termination 168 * @param[out] outbuff the output buffer; should have at least @a size bytes 169 * available 170 */ 171 MHD_INTERNAL void 172 mhd_str_to_lowercase_bin_n (size_t size, 173 const char *restrict inbuff, 174 char *restrict outbuff) 175 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (2,1) MHD_FN_PAR_OUT_SIZE_ (3,1); 176 177 /** 178 * Check whether the string does not contain US-ASCII upper case letters. 179 * @param len the length of the @a str 180 * @param str the string to check, does not need to be zero terminated 181 * @return 'true' if not US-ASCII letter found in the string, 182 * 'false' otherwise. 183 */ 184 MHD_INTERNAL bool 185 mhd_str_is_lowercase_bin_n (size_t len, 186 const char *restrict str) 187 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (2,1); 188 189 190 #ifdef mhd_HAVE_STR_TO_UPPER 191 /** 192 * Convert sequence of bytes to upper case US-ASCII letters. 193 * @param size the size of the data in the @a inbuff 194 * @param inbuff the input data, does not need to be zero-terminated; 195 * if it is zero-terminated and zero-termination of @a outbuff 196 * is needed, make sure that @a size includes zero-termination 197 * @param[out] outbuff the output buffer; should have at least @a size bytes 198 * available 199 */ 200 MHD_INTERNAL void 201 mhd_str_to_uppercase_bin_n (size_t size, 202 const char *restrict inbuff, 203 char *restrict outbuff) 204 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (2,1) MHD_FN_PAR_OUT_SIZE_ (3,1); 205 206 #endif /* mhd_HAVE_STR_TO_UPPER */ 207 208 /** 209 * Check whether @a str has case-insensitive @a token. 210 * Token could be surrounded by spaces and tabs and delimited by comma. 211 * Match succeed if substring between start, end (of string) or comma 212 * contains only case-insensitive token and optional spaces and tabs. 213 * @warning token must not contain null-characters except optional 214 * terminating null-character. 215 * @param str the string to check 216 * @param token the token to find 217 * @param token_len length of token, not including optional terminating 218 * null-character. 219 * @return non-zero if two strings are equal, zero otherwise. 220 */ 221 MHD_INTERNAL bool 222 mhd_str_has_token_caseless (const char *restrict str, 223 const char *const restrict token, 224 size_t token_len) 225 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) 226 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2); 227 228 /** 229 * Check whether @a str has case-insensitive static @a tkn. 230 * Token could be surrounded by spaces and tabs and delimited by comma. 231 * Match succeed if substring between start, end of string or comma 232 * contains only case-insensitive token and optional spaces and tabs. 233 * @warning tkn must be static string 234 * @param str the string to check 235 * @param tkn the static string of token to find 236 * @return non-zero if two strings are equal, zero otherwise. 237 */ 238 #define mhd_str_has_s_token_caseless(str,tkn) \ 239 mhd_str_has_token_caseless ((str),(tkn),mhd_SSTR_LEN (tkn)) 240 241 242 /** 243 * Remove case-insensitive @a token from the @a str and put result 244 * to the output @a buf. 245 * 246 * Tokens in @a str could be surrounded by spaces and tabs and delimited by 247 * comma. The token match succeed if substring between start, end (of string) 248 * or comma contains only case-insensitive token and optional spaces and tabs. 249 * The quoted strings and comments are not supported by this function. 250 * 251 * The output string is normalised: empty tokens and repeated whitespaces 252 * are removed, no whitespaces before commas, exactly one space is used after 253 * each comma. 254 * 255 * @param str the string to process 256 * @param str_len the length of the @a str, not including optional 257 * terminating null-character. 258 * @param token the token to find 259 * @param token_len the length of @a token, not including optional 260 * terminating null-character. 261 * @param[out] buf the output buffer, not null-terminated. 262 * @param[in,out] buf_size pointer to the size variable, at input it 263 * is the size of allocated buffer, at output 264 * it is the size of the resulting string (can 265 * be up to 50% larger than input) or negative value 266 * if there is not enough space for the result 267 * @return 'true' if token has been removed, 268 * 'false' otherwise. 269 */ 270 MHD_INTERNAL bool 271 mhd_str_remove_token_caseless (const char *restrict str, 272 size_t str_len, 273 const char *const restrict token, 274 const size_t token_len, 275 char *restrict buf, 276 ssize_t *restrict buf_size) 277 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) 278 MHD_FN_PAR_OUT_ (5) MHD_FN_PAR_INOUT_ (6); 279 280 281 /** 282 * Perform in-place case-insensitive removal of @a tokens from the @a str. 283 * 284 * Token could be surrounded by spaces and tabs and delimited by comma. 285 * The token match succeed if substring between start, end (of the string), or 286 * comma contains only case-insensitive token and optional spaces and tabs. 287 * The quoted strings and comments are not supported by this function. 288 * 289 * The input string must be normalised: empty tokens and repeated whitespaces 290 * are removed, no whitespaces before commas, exactly one space is used after 291 * each comma. The string is updated in-place. 292 * 293 * Behavior is undefined is the input string in not normalised. 294 * 295 * @param[in,out] str the string to update 296 * @param[in,out] str_len the length of the @a str, not including optional 297 * terminating null-character, not null-terminated 298 * @param tkns the token to find 299 * @param tkns_len the length of @a tokens, not including optional 300 * terminating null-character. 301 * @return 'true' if any token has been removed, 302 * 'false' otherwise. 303 */ 304 MHD_INTERNAL bool 305 mhd_str_remove_tokens_caseless (char *restrict str, 306 size_t *restrict str_len, 307 const char *const restrict tkns, 308 const size_t tkns_len) 309 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_INOUT_ (2) 310 MHD_FN_PAR_IN_SIZE_ (3,4); 311 312 313 #ifndef MHD_FAVOR_SMALL_CODE 314 /* Use individual function for each case to improve speed */ 315 316 /** 317 * Convert decimal US-ASCII digits in string to number in uint_fast64_t. 318 * Conversion stopped at first non-digit character. 319 * 320 * @param str string to convert 321 * @param[out] out_val pointer to uint_fast64_t to store result of conversion 322 * @return non-zero number of characters processed on succeed, 323 * zero if no digit is found or resulting value is larger 324 * than possible to store in uint_fast64_t 325 */ 326 MHD_INTERNAL size_t 327 mhd_str_to_uint64 (const char *restrict str, 328 uint_fast64_t *restrict out_val) 329 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_IN_ (1) 330 MHD_FN_PAR_OUT_ (2); 331 332 /** 333 * Convert not more then @a maxlen decimal US-ASCII digits in string to 334 * number in uint_fast64_t. 335 * Conversion stopped at first non-digit character or after @a maxlen 336 * digits. 337 * 338 * @param str string to convert 339 * @param maxlen maximum number of characters to process 340 * @param[out] out_val pointer to uint_fast64_t to store result of conversion 341 * @return non-zero number of characters processed on succeed, 342 * zero if no digit is found or resulting value is larger 343 * than possible to store in uint_fast64_t 344 */ 345 MHD_INTERNAL size_t 346 mhd_str_to_uint64_n (const char *restrict str, 347 size_t maxlen, 348 uint_fast64_t *restrict out_val) 349 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3); 350 351 352 /** 353 * Convert hexadecimal US-ASCII digits in string to number in uint_fast32_t. 354 * Conversion stopped at first non-digit character. 355 * 356 * @param str string to convert 357 * @param[out] out_val pointer to uint_fast32_t to store result of conversion 358 * @return non-zero number of characters processed on succeed, 359 * zero if no digit is found or resulting value is larger 360 * than possible to store in uint_fast32_t 361 */ 362 MHD_INTERNAL size_t 363 mhd_strx_to_uint32 (const char *restrict str, 364 uint_fast32_t *restrict out_val) 365 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) 366 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2); 367 368 369 /** 370 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string 371 * to number in uint_fast32_t. 372 * Conversion stopped at first non-digit character or after @a maxlen 373 * digits. 374 * 375 * @param str string to convert 376 * @param maxlen maximum number of characters to process 377 * @param[out] out_val pointer to uint_fast32_t to store result of conversion 378 * @return non-zero number of characters processed on succeed, 379 * zero if no digit is found or resulting value is larger 380 * than possible to store in uint_fast32_t 381 */ 382 MHD_INTERNAL size_t 383 mhd_strx_to_uint32_n (const char *restrict str, 384 size_t maxlen, 385 uint_fast32_t *restrict out_val) 386 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3); 387 388 389 /** 390 * Convert hexadecimal US-ASCII digits in string to number in uint_fast64_t. 391 * Conversion stopped at first non-digit character. 392 * 393 * @param str string to convert 394 * @param[out] out_val pointer to uint_fast64_t to store result of conversion 395 * @return non-zero number of characters processed on succeed, 396 * zero if no digit is found or resulting value is larger 397 * than possible to store in uint_fast64_t 398 */ 399 MHD_INTERNAL size_t 400 mhd_strx_to_uint64 (const char *restrict str, 401 uint_fast64_t *restrict out_val) 402 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) 403 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2); 404 405 406 /** 407 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string 408 * to number in uint_fast64_t. 409 * Conversion stopped at first non-digit character or after @a maxlen 410 * digits. 411 * 412 * @param str string to convert 413 * @param maxlen maximum number of characters to process 414 * @param[out] out_val pointer to uint_fast64_t to store result of conversion 415 * @return non-zero number of characters processed on succeed, 416 * zero if no digit is found or resulting value is larger 417 * than possible to store in uint_fast64_t 418 */ 419 MHD_INTERNAL size_t 420 mhd_strx_to_uint64_n (const char *restrict str, 421 size_t maxlen, 422 uint_fast64_t *restrict out_val) 423 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3); 424 425 #else /* MHD_FAVOR_SMALL_CODE */ 426 /* Use one universal function and macros to reduce size */ 427 428 /** 429 * Generic function for converting not more then @a maxlen 430 * hexadecimal or decimal US-ASCII digits in string to number. 431 * Conversion stopped at first non-digit character or after @a maxlen 432 * digits. 433 * To be used only within macro. 434 * 435 * @param str the string to convert 436 * @param maxlen the maximum number of characters to process 437 * @param out_val the pointer to variable to store result of conversion 438 * @param val_size the size of variable pointed by @a out_val, in bytes, 4 or 8 439 * @param max_val the maximum decoded number 440 * @param base the numeric base, 10 or 16 441 * @return non-zero number of characters processed on succeed, 442 * zero if no digit is found, resulting value is larger 443 * than @a max_val, @a val_size is not 4 or 8 444 * or @a base is not 10 or 16 445 */ 446 MHD_INTERNAL size_t 447 mhd_str_to_uvalue_n (const char *restrict str, 448 size_t maxlen, 449 void *restrict out_val, 450 size_t val_size, 451 uint_fast64_t max_val, 452 unsigned int base) 453 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4); 454 455 #define mhd_str_to_uint64(s,ov) \ 456 mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \ 457 sizeof(uint_fast64_t), \ 458 UINT64_MAX,10) 459 460 #define mhd_str_to_uint64_n(s,ml,ov) \ 461 mhd_str_to_uvalue_n ((s),(ml),(ov), \ 462 sizeof(uint_fast64_t), \ 463 UINT64_MAX,10) 464 465 #define mhd_strx_to_sizet(s,ov) \ 466 mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \ 467 sizeof(size_t),SIZE_MAX, \ 468 16) 469 470 #define mhd_strx_to_sizet_n(s,ml,ov) \ 471 mhd_str_to_uvalue_n ((s),(ml),(ov), \ 472 sizeof(size_t), \ 473 SIZE_MAX,16) 474 475 #define mhd_strx_to_uint32(s,ov) \ 476 mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \ 477 sizeof(uint_fast32_t), \ 478 UINT32_MAX,16) 479 480 #define mhd_strx_to_uint32_n(s,ml,ov) \ 481 mhd_str_to_uvalue_n ((s),(ml),(ov), \ 482 sizeof(uint_fast32_t), \ 483 UINT32_MAX,16) 484 485 #define mhd_strx_to_uint64(s,ov) \ 486 mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \ 487 sizeof(uint_fast64_t), \ 488 UINT64_MAX,16) 489 490 #define mhd_strx_to_uint64_n(s,ml,ov) \ 491 mhd_str_to_uvalue_n ((s),(ml),(ov), \ 492 sizeof(uint_fast64_t), \ 493 UINT64_MAX,16) 494 495 #endif /* MHD_FAVOR_SMALL_CODE */ 496 497 498 /** 499 * Convert uint_fast32_t value to hexdecimal US-ASCII string. 500 * Only lowest 32 bits are used in the input value. 501 * @note: result is NOT zero-terminated. 502 * @param val the value to convert 503 * @param buf the buffer to result to 504 * @param buf_size size of the @a buffer 505 * @return number of characters has been put to the @a buf, 506 * zero if buffer is too small (buffer may be modified). 507 */ 508 MHD_INTERNAL size_t 509 mhd_uint32_to_strx (uint_fast32_t val, 510 char *buf, 511 size_t buf_size) 512 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (2,3); 513 514 515 #ifndef MHD_FAVOR_SMALL_CODE 516 /** 517 * Convert uint_least16_t value to decimal US-ASCII string. 518 * Only lowest 16 bits are used in the input value. 519 * @note: result is NOT zero-terminated. 520 * @param val the value to convert 521 * @param buf the buffer to result to 522 * @param buf_size size of the @a buffer 523 * @return number of characters has been put to the @a buf, 524 * zero if buffer is too small (buffer may be modified). 525 */ 526 MHD_INTERNAL size_t 527 mhd_uint16_to_str (uint_least16_t val, 528 char *buf, 529 size_t buf_size) 530 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (2,3); 531 532 #else /* MHD_FAVOR_SMALL_CODE */ 533 #define mhd_uint16_to_str(v,b,s) mhd_uint64_to_str (v,b,s) 534 #endif /* MHD_FAVOR_SMALL_CODE */ 535 536 537 /** 538 * Convert uint_fast64_t value to decimal US-ASCII string. 539 * Only lowest 64 bits are used in the input value. 540 * @note: result is NOT zero-terminated. 541 * @param val the value to convert 542 * @param buf the buffer to result to 543 * @param buf_size size of the @a buffer 544 * @return number of characters has been put to the @a buf, 545 * zero if buffer is too small (buffer may be modified). 546 */ 547 MHD_INTERNAL size_t 548 mhd_uint64_to_str (uint_fast64_t val, 549 char *buf, 550 size_t buf_size) 551 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (2,3); 552 553 554 /** 555 * Convert uint_least16_t value to decimal US-ASCII string padded with 556 * zeros on the left side. 557 * 558 * @note: result is NOT zero-terminated. 559 * @param val the value to convert 560 * @param min_digits the minimal number of digits to print, 561 * output padded with zeros on the left side, 562 * 'zero' value is interpreted as 'one', 563 * valid values are 3, 2, 1, 0 564 * @param buf the buffer to result to 565 * @param buf_size size of the @a buffer 566 * @return number of characters has been put to the @a buf, 567 * zero if buffer is too small (buffer may be modified). 568 */ 569 MHD_INTERNAL size_t 570 mhd_uint8_to_str_pad (uint8_t val, 571 uint8_t min_digits, 572 char *buf, 573 size_t buf_size) 574 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (3,4); 575 576 577 /** 578 * Convert @a size bytes from input binary data to lower case 579 * hexadecimal digits. 580 * Result is NOT zero-terminated 581 * @param bin the pointer to the binary data to convert 582 * @param size the size in bytes of the binary data to convert 583 * @param[out] hex the output buffer, should be at least 2 * @a size 584 * @return The number of characters written to the output buffer. 585 */ 586 MHD_INTERNAL size_t 587 mhd_bin_to_hex (const void *restrict bin, 588 size_t size, 589 char *restrict hex) 590 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3); 591 592 /** 593 * Convert @a size bytes from input binary data to lower case 594 * hexadecimal digits, zero-terminate the result. 595 * @param bin the pointer to the binary data to convert 596 * @param size the size in bytes of the binary data to convert 597 * @param[out] hex the output buffer, should be at least 2 * @a size + 1 598 * @return The number of characters written to the output buffer, 599 * not including terminating zero. 600 */ 601 MHD_INTERNAL size_t 602 mhd_bin_to_hex_z (const void *restrict bin, 603 size_t size, 604 char *restrict hex) 605 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3); 606 607 /** 608 * Convert hexadecimal digits to binary data. 609 * 610 * The input decoded byte-by-byte (each byte is two hexadecimal digits). 611 * If length is an odd number, extra leading zero is assumed. 612 * 613 * @param hex the input string with hexadecimal digits 614 * @param len the length of the input string 615 * @param[out] bin the output buffer, must be at least len/2 bytes long (or 616 * len/2 + 1 if @a len is not even number) 617 * @return the number of bytes written to the output buffer, 618 * zero if found any character which is not hexadecimal digits 619 */ 620 MHD_INTERNAL size_t 621 mhd_hex_to_bin (const char *restrict hex, 622 size_t len, 623 void *restrict bin) 624 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3); 625 626 /** 627 * Decode string with percent-encoded characters as defined by 628 * RFC 3986 #section-2.1. 629 * 630 * This function decode string by converting percent-encoded characters to 631 * their decoded versions and copying all other characters without extra 632 * processing. 633 * 634 * @param pct_encoded the input string to be decoded 635 * @param pct_encoded_len the length of the @a pct_encoded 636 * @param[out] decoded the output buffer, NOT zero-terminated, can point 637 * to the same buffer as @a pct_encoded 638 * @param buf_size the size of the output buffer 639 * @return the number of characters written to the output buffer or 640 * zero if any percent-encoded characters is broken ('%' followed 641 * by less than two hexadecimal digits) or output buffer is too 642 * small to hold the result 643 */ 644 MHD_INTERNAL size_t 645 mhd_str_pct_decode_strict_n (const char *pct_encoded, 646 size_t pct_encoded_len, 647 char *decoded, 648 size_t buf_size) 649 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4); 650 651 /** 652 * Decode string with percent-encoded characters as defined by 653 * RFC 3986 #section-2.1. 654 * 655 * This function decode string by converting percent-encoded characters to 656 * their decoded versions and copying all other characters without extra 657 * processing. 658 * 659 * Any invalid percent-encoding sequences ('%' symbol not followed by two 660 * valid hexadecimal digits) are copied to the output string without decoding. 661 * 662 * @param pct_encoded the input string to be decoded 663 * @param pct_encoded_len the length of the @a pct_encoded 664 * @param[out] decoded the output buffer, NOT zero-terminated, can point 665 * to the same buffer as @a pct_encoded 666 * @param buf_size the size of the output buffer 667 * @param[out] broken_encoding will be set to true if any '%' symbol is not 668 * followed by two valid hexadecimal digits, 669 * optional, can be NULL 670 * @return the number of characters written to the output buffer or 671 * zero if output buffer is too small to hold the result 672 */ 673 MHD_INTERNAL size_t 674 mhd_str_pct_decode_lenient_n (const char *pct_encoded, 675 size_t pct_encoded_len, 676 char *decoded, 677 size_t buf_size, 678 bool *restrict broken_encoding) 679 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3) 680 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4); 681 682 683 /** 684 * Decode string in-place with percent-encoded characters as defined by 685 * RFC 3986 #section-2.1. 686 * 687 * This function decode string by converting percent-encoded characters to 688 * their decoded versions and copying back all other characters without extra 689 * processing. 690 * 691 * @param[in,out] str the string to be updated in-place, must be zero-terminated 692 * on input, the output is zero-terminated; the string is 693 * truncated to zero length if broken encoding is found 694 * @return the number of character in decoded string 695 */ 696 MHD_INTERNAL size_t 697 mhd_str_pct_decode_in_place_strict (char *str) 698 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1); 699 700 701 /** 702 * Decode string in-place with percent-encoded characters as defined by 703 * RFC 3986 #section-2.1. 704 * 705 * This function decode string by converting percent-encoded characters to 706 * their decoded versions and copying back all other characters without extra 707 * processing. 708 * 709 * Any invalid percent-encoding sequences ('%' symbol not followed by two 710 * valid hexadecimal digits) are copied to the output string without decoding. 711 * 712 * @param[in,out] str the string to be updated in-place, must be zero-terminated 713 * on input, the output is zero-terminated 714 * @param[out] broken_encoding will be set to true if any '%' symbol is not 715 * followed by two valid hexadecimal digits, 716 * optional, can be NULL 717 * @return the number of character in decoded string 718 */ 719 MHD_INTERNAL size_t 720 mhd_str_pct_decode_in_place_lenient (char *restrict str, 721 bool *restrict broken_encoding) 722 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (1); 723 724 MHD_INTERNAL size_t 725 mhd_str_dec_norm_uri_path (size_t str_len, 726 char *restrict str) 727 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_INOUT_SIZE_ (2,1); 728 729 730 #ifdef MHD_SUPPORT_AUTH_DIGEST 731 /** 732 * Check two strings for equality, "unquoting" the first string from quoted 733 * form as specified by RFC7230#section-3.2.6 and RFC7694#quoted.strings. 734 * 735 * Null-termination for input strings is not required, binary zeros compared 736 * like other characters. 737 * 738 * @param quoted the quoted string to compare, must NOT include leading and 739 * closing DQUOTE chars, does not need to be zero-terminated 740 * @param quoted_len the length in chars of the @a quoted string 741 * @param unquoted the unquoted string to compare, does not need to be 742 * zero-terminated 743 * @param unquoted_len the length in chars of the @a unquoted string 744 * @return zero if quoted form is broken (no character after the last escaping 745 * backslash), zero if strings are not equal after unquoting of the 746 * first string, 747 * non-zero if two strings are equal after unquoting of the 748 * first string. 749 */ 750 MHD_INTERNAL bool 751 mhd_str_equal_quoted_bin_n (const char *quoted, 752 size_t quoted_len, 753 const char *unquoted, 754 size_t unquoted_len) 755 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ 756 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4); 757 758 /** 759 * Check whether the string after "unquoting" equals static string. 760 * 761 * Null-termination for input string is not required, binary zeros compared 762 * like other characters. 763 * 764 * @param q the quoted string to compare, must NOT include leading and 765 * closing DQUOTE chars, does not need to be zero-terminated 766 * @param l the length in chars of the @a q string 767 * @param u the unquoted static string to compare 768 * @return zero if quoted form is broken (no character after the last escaping 769 * backslash), zero if strings are not equal after unquoting of the 770 * first string, 771 * non-zero if two strings are equal after unquoting of the 772 * first string. 773 */ 774 #define mhd_str_equal_quoted_s_bin_n(q,l,u) \ 775 mhd_str_equal_quoted_bin_n (q,l,u,mhd_SSTR_LEN (u)) 776 777 /** 778 * Check two strings for equality, "unquoting" the first string from quoted 779 * form as specified by RFC7230#section-3.2.6 and RFC7694#quoted.strings and 780 * ignoring case of US-ASCII letters. 781 * 782 * Null-termination for input strings is not required, binary zeros compared 783 * like other characters. 784 * 785 * @param quoted the quoted string to compare, must NOT include leading and 786 * closing DQUOTE chars, does not need to be zero-terminated 787 * @param quoted_len the length in chars of the @a quoted string 788 * @param unquoted the unquoted string to compare, does not need to be 789 * zero-terminated 790 * @param unquoted_len the length in chars of the @a unquoted string 791 * @return zero if quoted form is broken (no character after the last escaping 792 * backslash), zero if strings are not equal after unquoting of the 793 * first string, 794 * non-zero if two strings are caseless equal after unquoting of the 795 * first string. 796 */ 797 MHD_INTERNAL bool 798 mhd_str_equal_caseless_quoted_bin_n (const char *quoted, 799 size_t quoted_len, 800 const char *unquoted, 801 size_t unquoted_len) 802 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ 803 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4); 804 805 /** 806 * Check whether the string after "unquoting" equals static string, ignoring 807 * case of US-ASCII letters. 808 * 809 * Null-termination for input string is not required, binary zeros compared 810 * like other characters. 811 * 812 * @param q the quoted string to compare, must NOT include leading and 813 * closing DQUOTE chars, does not need to be zero-terminated 814 * @param l the length in chars of the @a q string 815 * @param u the unquoted static string to compare 816 * @return zero if quoted form is broken (no character after the last escaping 817 * backslash), zero if strings are not equal after unquoting of the 818 * first string, 819 * non-zero if two strings are caseless equal after unquoting of the 820 * first string. 821 */ 822 #define mhd_str_equal_caseless_quoted_s_bin_n(q,l,u) \ 823 mhd_str_equal_caseless_quoted_bin_n (q,l,u,mhd_SSTR_LEN (u)) 824 825 #endif /* MHD_SUPPORT_AUTH_DIGEST */ 826 827 #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_POST_PARSER) 828 829 /** 830 * Convert string from quoted to unquoted form as specified by 831 * RFC7230#section-3.2.6 and RFC7694#quoted.strings. 832 * 833 * @param quoted the quoted string, must NOT include leading and closing 834 * DQUOTE chars, does not need to be zero-terminated 835 * @param quoted_len the length in chars of the @a quoted string 836 * @param[out] result the pointer to the buffer to put the result, must 837 * be at least @a size character long. May be modified even 838 * if @a quoted is invalid sequence. The result is NOT 839 * zero-terminated. 840 * @return The number of characters written to the output buffer, 841 * zero if last backslash is not followed by any character (or 842 * @a quoted_len is zero). 843 */ 844 MHD_INTERNAL size_t 845 mhd_str_unquote (const char *quoted, 846 size_t quoted_len, 847 char *result) 848 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,2); 849 850 #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_POST_PARSER */ 851 852 #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_AUTH_BASIC) 853 854 /** 855 * Convert string from unquoted to quoted form as specified by 856 * RFC7230#section-3.2.6 and RFC7694#quoted.strings. 857 * 858 * @param unquoted the unquoted string, does not need to be zero-terminated 859 * @param unquoted_len the length in chars of the @a unquoted string 860 * @param[out] result the pointer to the buffer to put the result. May be 861 * modified even if function failed due to insufficient 862 * space. The result is NOT zero-terminated and does not 863 * have opening and closing DQUOTE chars. 864 * @param buf_size the size of the allocated memory for @a result 865 * @return The number of copied characters, can be up to two times more than 866 * @a unquoted_len, zero if @a unquoted_len is zero or if quoted 867 * string is larger than @a buf_size. 868 */ 869 MHD_INTERNAL size_t 870 mhd_str_quote (const char *unquoted, 871 size_t unquoted_len, 872 char *result, 873 size_t buf_size) 874 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4); 875 876 #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_AUTH_BASIC */ 877 878 #ifdef MHD_SUPPORT_AUTH_BASIC 879 880 /** 881 * Returns the maximum possible size of the Base64 decoded data. 882 * The real recoded size could be up to two bytes smaller. 883 * @param enc_size the size of encoded data, in characters 884 * @return the maximum possible size of the decoded data, in bytes, if 885 * @a enc_size is valid (properly padded), 886 * undefined value smaller then @a enc_size if @a enc_size is not valid 887 */ 888 #define mhd_base64_max_dec_size(enc_size) (((enc_size) / 4) * 3) 889 890 /** 891 * Convert Base64 encoded string to binary data. 892 * @param base64 the input string with Base64 encoded data, could be NOT zero 893 * terminated 894 * @param base64_len the number of characters to decode in @a base64 string, 895 * valid number must be a multiple of four 896 * @param[out] bin the pointer to the output buffer, the buffer may be altered 897 * even if decoding failed 898 * @param bin_size the size of the @a bin buffer in bytes, if the size is 899 * at least @a base64_len / 4 * 3 then result will always 900 * fit, regardless of the amount of the padding characters 901 * @return 0 if @a base64_len is zero, or input string has wrong data (not 902 * valid Base64 sequence), or @a bin_size is too small; 903 * non-zero number of bytes written to the @a bin, the number must be 904 * (base64_len / 4 * 3 - 2), (base64_len / 4 * 3 - 1) or 905 * (base64_len / 4 * 3), depending on the number of padding characters. 906 */ 907 MHD_INTERNAL size_t 908 mhd_base64_to_bin_n (const char *base64, 909 size_t base64_len, 910 void *bin, 911 size_t bin_size) 912 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4); 913 914 #endif /* MHD_SUPPORT_AUTH_BASIC */ 915 916 917 /** 918 * Check whether the given field value string starts with given token. 919 * Token matched case-insensitive. 920 * 921 * Matched considered successful if string has given token at the first 922 * position. The token may be followed by optional whitespaces and the semicolon 923 * symbol. The string is not checked after the semicolon (if any). 924 * 925 * @param str the string to check 926 * @param token the token to find, must not be empty 927 * @return 'true' if match is successful, 928 * 'false' otherwise 929 */ 930 MHD_INTERNAL bool 931 mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str, 932 const struct MHD_String *restrict token) 933 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_; 934 935 936 /** 937 * The result of check for token with parameter 938 */ 939 enum MHD_FIXED_ENUM_ mhd_StingStartsWithTokenResult 940 { 941 /** 942 * The string does not start with the specified token 943 */ 944 mhd_STR_STARTS_W_TOKEN_NO_TOKEN = 0 945 , 946 /** 947 * The string has specified token at the initial position 948 * @note While formatting problems are not detected, it does not guarantee 949 * that string has a perfect format. 950 */ 951 mhd_STR_STARTS_W_TOKEN_HAS_TOKEN = 1 952 , 953 /** 954 * The string has specified token at the initial position, but broken 955 * formatting is detected. 956 */ 957 mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT = -1 958 }; 959 960 /** 961 * Check whether the given field value string starts with given token, find 962 * required parameter. 963 * Token and parameter matched case-insensitive. 964 * 965 * Matched considered successful if string has given token at the first 966 * position. The token should be followed by optional whitespaces and 967 * one or more parameters, delimited by the semicolon symbol. 968 * 969 * @param str the string to check 970 * @param token the token to find, must not be empty 971 * @param par the name of the parameter, must not be empty 972 * @param[out] par_value set to the found parameter value or @a data member 973 * set to NULL if parameter is not found 974 * @param par_value_needs_unquote set to 'true' if @a par_value 975 * needs to be "unquoted" 976 * @return result of token detection and string parsing; if token is found 977 * the presence of the required parameter is indicated only 978 * by @a par_value 979 * 980 */ 981 MHD_INTERNAL enum mhd_StingStartsWithTokenResult 982 mhd_str_starts_with_token_req_param ( 983 const struct MHD_String *restrict str, 984 const struct MHD_String *restrict token, 985 const struct MHD_String *restrict par, 986 struct mhd_BufferConst *restrict par_value, 987 bool *restrict par_value_needs_unquote) 988 MHD_FN_PAR_NONNULL_ALL_ 989 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) MHD_FN_PAR_IN_ (3) 990 MHD_FN_PAR_OUT_ (4) MHD_FN_PAR_OUT_ (5); 991 992 #endif /* MHD_STR_H */