mhd_str.h (39789B)
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 #endif /* mhd_HAVE_STR_TO_UPPER */ 206 207 /** 208 * Check whether @a str has case-insensitive @a token. 209 * Token could be surrounded by spaces and tabs and delimited by comma. 210 * Match succeed if substring between start, end (of string) or comma 211 * contains only case-insensitive token and optional spaces and tabs. 212 * @warning token must not contain null-characters except optional 213 * terminating null-character. 214 * @param str the string to check 215 * @param token the token to find 216 * @param token_len length of token, not including optional terminating 217 * null-character. 218 * @return non-zero if two strings are equal, zero otherwise. 219 */ 220 MHD_INTERNAL bool 221 mhd_str_has_token_caseless (const char *restrict str, 222 const char *const restrict token, 223 size_t token_len) 224 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) 225 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2); 226 227 /** 228 * Check whether @a str has case-insensitive static @a tkn. 229 * Token could be surrounded by spaces and tabs and delimited by comma. 230 * Match succeed if substring between start, end of string or comma 231 * contains only case-insensitive token and optional spaces and tabs. 232 * @warning tkn must be static string 233 * @param str the string to check 234 * @param tkn the static string of token to find 235 * @return non-zero if two strings are equal, zero otherwise. 236 */ 237 #define mhd_str_has_s_token_caseless(str,tkn) \ 238 mhd_str_has_token_caseless ((str),(tkn),mhd_SSTR_LEN (tkn)) 239 240 241 /** 242 * Remove case-insensitive @a token from the @a str and put result 243 * to the output @a buf. 244 * 245 * Tokens in @a str could be surrounded by spaces and tabs and delimited by 246 * comma. The token match succeed if substring between start, end (of string) 247 * or comma contains only case-insensitive token and optional spaces and tabs. 248 * The quoted strings and comments are not supported by this function. 249 * 250 * The output string is normalised: empty tokens and repeated whitespaces 251 * are removed, no whitespaces before commas, exactly one space is used after 252 * each comma. 253 * 254 * @param str the string to process 255 * @param str_len the length of the @a str, not including optional 256 * terminating null-character. 257 * @param token the token to find 258 * @param token_len the length of @a token, not including optional 259 * terminating null-character. 260 * @param[out] buf the output buffer, not null-terminated. 261 * @param[in,out] buf_size pointer to the size variable, at input it 262 * is the size of allocated buffer, at output 263 * it is the size of the resulting string (can 264 * be up to 50% larger than input) or negative value 265 * if there is not enough space for the result 266 * @return 'true' if token has been removed, 267 * 'false' otherwise. 268 */ 269 MHD_INTERNAL bool 270 mhd_str_remove_token_caseless (const char *restrict str, 271 size_t str_len, 272 const char *const restrict token, 273 const size_t token_len, 274 char *restrict buf, 275 ssize_t *restrict buf_size) 276 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) 277 MHD_FN_PAR_OUT_ (5) MHD_FN_PAR_INOUT_ (6); 278 279 280 /** 281 * Perform in-place case-insensitive removal of @a tokens from the @a str. 282 * 283 * Token could be surrounded by spaces and tabs and delimited by comma. 284 * The token match succeed if substring between start, end (of the string), or 285 * comma contains only case-insensitive token and optional spaces and tabs. 286 * The quoted strings and comments are not supported by this function. 287 * 288 * The input string must be normalised: empty tokens and repeated whitespaces 289 * are removed, no whitespaces before commas, exactly one space is used after 290 * each comma. The string is updated in-place. 291 * 292 * Behavior is undefined is the input string in not normalised. 293 * 294 * @param[in,out] str the string to update 295 * @param[in,out] str_len the length of the @a str, not including optional 296 * terminating null-character, not null-terminated 297 * @param tkns the token to find 298 * @param tkns_len the length of @a tokens, not including optional 299 * terminating null-character. 300 * @return 'true' if any token has been removed, 301 * 'false' otherwise. 302 */ 303 MHD_INTERNAL bool 304 mhd_str_remove_tokens_caseless (char *restrict str, 305 size_t *restrict str_len, 306 const char *const restrict tkns, 307 const size_t tkns_len) 308 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_INOUT_ (2) 309 MHD_FN_PAR_IN_SIZE_ (3,4); 310 311 312 #ifndef MHD_FAVOR_SMALL_CODE 313 /* Use individual function for each case to improve speed */ 314 315 /** 316 * Convert decimal US-ASCII digits in string to number in uint_fast64_t. 317 * Conversion stopped at first non-digit character. 318 * 319 * @param str string to convert 320 * @param[out] out_val pointer to uint_fast64_t to store result of conversion 321 * @return non-zero number of characters processed on succeed, 322 * zero if no digit is found or resulting value is larger 323 * then possible to store in uint_fast64_t 324 */ 325 MHD_INTERNAL size_t 326 mhd_str_to_uint64 (const char *restrict str, 327 uint_fast64_t *restrict out_val) 328 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_IN_ (1) 329 MHD_FN_PAR_OUT_ (2); 330 331 /** 332 * Convert not more then @a maxlen decimal US-ASCII digits in string to 333 * number in uint_fast64_t. 334 * Conversion stopped at first non-digit character or after @a maxlen 335 * digits. 336 * 337 * @param str string to convert 338 * @param maxlen maximum number of characters to process 339 * @param[out] out_val pointer to uint_fast64_t to store result of conversion 340 * @return non-zero number of characters processed on succeed, 341 * zero if no digit is found or resulting value is larger 342 * then possible to store in uint_fast64_t 343 */ 344 MHD_INTERNAL size_t 345 mhd_str_to_uint64_n (const char *restrict str, 346 size_t maxlen, 347 uint_fast64_t *restrict out_val) 348 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3); 349 350 351 /** 352 * Convert hexadecimal US-ASCII digits in string to number in uint_fast32_t. 353 * Conversion stopped at first non-digit character. 354 * 355 * @param str string to convert 356 * @param[out] out_val pointer to uint_fast32_t to store result of conversion 357 * @return non-zero number of characters processed on succeed, 358 * zero if no digit is found or resulting value is larger 359 * then possible to store in uint_fast32_t 360 */ 361 MHD_INTERNAL size_t 362 mhd_strx_to_uint32 (const char *restrict str, 363 uint_fast32_t *restrict out_val) 364 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) 365 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2); 366 367 368 /** 369 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string 370 * to number in uint_fast32_t. 371 * Conversion stopped at first non-digit character or after @a maxlen 372 * digits. 373 * 374 * @param str string to convert 375 * @param maxlen maximum number of characters to process 376 * @param[out] out_val pointer to uint_fast32_t to store result of conversion 377 * @return non-zero number of characters processed on succeed, 378 * zero if no digit is found or resulting value is larger 379 * then possible to store in uint_fast32_t 380 */ 381 MHD_INTERNAL size_t 382 mhd_strx_to_uint32_n (const char *restrict str, 383 size_t maxlen, 384 uint_fast32_t *restrict out_val) 385 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3); 386 387 388 /** 389 * Convert hexadecimal US-ASCII digits in string to number in uint_fast64_t. 390 * Conversion stopped at first non-digit character. 391 * 392 * @param str string to convert 393 * @param[out] out_val pointer to uint_fast64_t to store result of conversion 394 * @return non-zero number of characters processed on succeed, 395 * zero if no digit is found or resulting value is larger 396 * then possible to store in uint_fast64_t 397 */ 398 MHD_INTERNAL size_t 399 mhd_strx_to_uint64 (const char *restrict str, 400 uint_fast64_t *restrict out_val) 401 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) 402 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2); 403 404 405 /** 406 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string 407 * to number in uint_fast64_t. 408 * Conversion stopped at first non-digit character or after @a maxlen 409 * digits. 410 * 411 * @param str string to convert 412 * @param maxlen maximum number of characters to process 413 * @param[out] out_val pointer to uint_fast64_t to store result of conversion 414 * @return non-zero number of characters processed on succeed, 415 * zero if no digit is found or resulting value is larger 416 * then possible to store in uint_fast64_t 417 */ 418 MHD_INTERNAL size_t 419 mhd_strx_to_uint64_n (const char *restrict str, 420 size_t maxlen, 421 uint_fast64_t *restrict out_val) 422 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3); 423 424 #else /* MHD_FAVOR_SMALL_CODE */ 425 /* Use one universal function and macros to reduce size */ 426 427 /** 428 * Generic function for converting not more then @a maxlen 429 * hexadecimal or decimal US-ASCII digits in string to number. 430 * Conversion stopped at first non-digit character or after @a maxlen 431 * digits. 432 * To be used only within macro. 433 * 434 * @param str the string to convert 435 * @param maxlen the maximum number of characters to process 436 * @param out_val the pointer to variable to store result of conversion 437 * @param val_size the size of variable pointed by @a out_val, in bytes, 4 or 8 438 * @param max_val the maximum decoded number 439 * @param base the numeric base, 10 or 16 440 * @return non-zero number of characters processed on succeed, 441 * zero if no digit is found, resulting value is larger 442 * then @a max_val, @a val_size is not 4 or 8 443 * or @a base is not 10 or 16 444 */ 445 MHD_INTERNAL size_t 446 mhd_str_to_uvalue_n (const char *restrict str, 447 size_t maxlen, 448 void *restrict out_val, 449 size_t val_size, 450 uint_fast64_t max_val, 451 unsigned int base) 452 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4); 453 454 #define mhd_str_to_uint64(s,ov) \ 455 mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \ 456 sizeof(uint_fast64_t), \ 457 UINT64_MAX,10) 458 459 #define mhd_str_to_uint64_n(s,ml,ov) \ 460 mhd_str_to_uvalue_n ((s),(ml),(ov), \ 461 sizeof(uint_fast64_t), \ 462 UINT64_MAX,10) 463 464 #define mhd_strx_to_sizet(s,ov) \ 465 mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \ 466 sizeof(size_t),SIZE_MAX, \ 467 16) 468 469 #define mhd_strx_to_sizet_n(s,ml,ov) \ 470 mhd_str_to_uvalue_n ((s),(ml),(ov), \ 471 sizeof(size_t), \ 472 SIZE_MAX,16) 473 474 #define mhd_strx_to_uint32(s,ov) \ 475 mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \ 476 sizeof(uint_fast32_t), \ 477 UINT32_MAX,16) 478 479 #define mhd_strx_to_uint32_n(s,ml,ov) \ 480 mhd_str_to_uvalue_n ((s),(ml),(ov), \ 481 sizeof(uint_fast32_t), \ 482 UINT32_MAX,16) 483 484 #define mhd_strx_to_uint64(s,ov) \ 485 mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \ 486 sizeof(uint_fast64_t), \ 487 UINT64_MAX,16) 488 489 #define mhd_strx_to_uint64_n(s,ml,ov) \ 490 mhd_str_to_uvalue_n ((s),(ml),(ov), \ 491 sizeof(uint_fast64_t), \ 492 UINT64_MAX,16) 493 494 #endif /* MHD_FAVOR_SMALL_CODE */ 495 496 497 /** 498 * Convert uint_fast32_t value to hexdecimal US-ASCII string. 499 * @note: result is NOT zero-terminated. 500 * @param val the value to convert 501 * @param buf the buffer to result to 502 * @param buf_size size of the @a buffer 503 * @return number of characters has been put to the @a buf, 504 * zero if buffer is too small (buffer may be modified). 505 */ 506 MHD_INTERNAL size_t 507 mhd_uint32_to_strx (uint_fast32_t val, 508 char *buf, 509 size_t buf_size) 510 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (2,3); 511 512 513 #ifndef MHD_FAVOR_SMALL_CODE 514 /** 515 * Convert uint_least16_t value to decimal US-ASCII string. 516 * @note: result is NOT zero-terminated. 517 * @param val the value to convert 518 * @param buf the buffer to result to 519 * @param buf_size size of the @a buffer 520 * @return number of characters has been put to the @a buf, 521 * zero if buffer is too small (buffer may be modified). 522 */ 523 MHD_INTERNAL size_t 524 mhd_uint16_to_str (uint_least16_t val, 525 char *buf, 526 size_t buf_size) 527 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (2,3); 528 529 #else /* MHD_FAVOR_SMALL_CODE */ 530 #define mhd_uint16_to_str(v,b,s) mhd_uint64_to_str (v,b,s) 531 #endif /* MHD_FAVOR_SMALL_CODE */ 532 533 534 /** 535 * Convert uint_fast64_t value to decimal US-ASCII string. 536 * @note: result is NOT zero-terminated. 537 * @param val the value to convert 538 * @param buf the buffer to result to 539 * @param buf_size size of the @a buffer 540 * @return number of characters has been put to the @a buf, 541 * zero if buffer is too small (buffer may be modified). 542 */ 543 MHD_INTERNAL size_t 544 mhd_uint64_to_str (uint_fast64_t val, 545 char *buf, 546 size_t buf_size) 547 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (2,3); 548 549 550 /** 551 * Convert uint_least16_t value to decimal US-ASCII string padded with 552 * zeros on the left side. 553 * 554 * @note: result is NOT zero-terminated. 555 * @param val the value to convert 556 * @param min_digits the minimal number of digits to print, 557 * output padded with zeros on the left side, 558 * 'zero' value is interpreted as 'one', 559 * valid values are 3, 2, 1, 0 560 * @param buf the buffer to result to 561 * @param buf_size size of the @a buffer 562 * @return number of characters has been put to the @a buf, 563 * zero if buffer is too small (buffer may be modified). 564 */ 565 MHD_INTERNAL size_t 566 mhd_uint8_to_str_pad (uint8_t val, 567 uint8_t min_digits, 568 char *buf, 569 size_t buf_size) 570 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (3,4); 571 572 573 /** 574 * Convert @a size bytes from input binary data to lower case 575 * hexadecimal digits. 576 * Result is NOT zero-terminated 577 * @param bin the pointer to the binary data to convert 578 * @param size the size in bytes of the binary data to convert 579 * @param[out] hex the output buffer, should be at least 2 * @a size 580 * @return The number of characters written to the output buffer. 581 */ 582 MHD_INTERNAL size_t 583 mhd_bin_to_hex (const void *restrict bin, 584 size_t size, 585 char *restrict hex) 586 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3); 587 588 /** 589 * Convert @a size bytes from input binary data to lower case 590 * hexadecimal digits, zero-terminate the result. 591 * @param bin the pointer to the binary data to convert 592 * @param size the size in bytes of the binary data to convert 593 * @param[out] hex the output buffer, should be at least 2 * @a size + 1 594 * @return The number of characters written to the output buffer, 595 * not including terminating zero. 596 */ 597 MHD_INTERNAL size_t 598 mhd_bin_to_hex_z (const void *restrict bin, 599 size_t size, 600 char *restrict hex) 601 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3); 602 603 /** 604 * Convert hexadecimal digits to binary data. 605 * 606 * The input decoded byte-by-byte (each byte is two hexadecimal digits). 607 * If length is an odd number, extra leading zero is assumed. 608 * 609 * @param hex the input string with hexadecimal digits 610 * @param len the length of the input string 611 * @param[out] bin the output buffer, must be at least len/2 bytes long (or 612 * len/2 + 1 if @a len is not even number) 613 * @return the number of bytes written to the output buffer, 614 * zero if found any character which is not hexadecimal digits 615 */ 616 MHD_INTERNAL size_t 617 mhd_hex_to_bin (const char *restrict hex, 618 size_t len, 619 void *restrict bin) 620 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3); 621 622 /** 623 * Decode string with percent-encoded characters as defined by 624 * RFC 3986 #section-2.1. 625 * 626 * This function decode string by converting percent-encoded characters to 627 * their decoded versions and copying all other characters without extra 628 * processing. 629 * 630 * @param pct_encoded the input string to be decoded 631 * @param pct_encoded_len the length of the @a pct_encoded 632 * @param[out] decoded the output buffer, NOT zero-terminated, can point 633 * to the same buffer as @a pct_encoded 634 * @param buf_size the size of the output buffer 635 * @return the number of characters written to the output buffer or 636 * zero if any percent-encoded characters is broken ('%' followed 637 * by less than two hexadecimal digits) or output buffer is too 638 * small to hold the result 639 */ 640 MHD_INTERNAL size_t 641 mhd_str_pct_decode_strict_n (const char *pct_encoded, 642 size_t pct_encoded_len, 643 char *decoded, 644 size_t buf_size) 645 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4); 646 647 /** 648 * Decode string with percent-encoded characters as defined by 649 * RFC 3986 #section-2.1. 650 * 651 * This function decode string by converting percent-encoded characters to 652 * their decoded versions and copying all other characters without extra 653 * processing. 654 * 655 * Any invalid percent-encoding sequences ('%' symbol not followed by two 656 * valid hexadecimal digits) are copied to the output string without decoding. 657 * 658 * @param pct_encoded the input string to be decoded 659 * @param pct_encoded_len the length of the @a pct_encoded 660 * @param[out] decoded the output buffer, NOT zero-terminated, can point 661 * to the same buffer as @a pct_encoded 662 * @param buf_size the size of the output buffer 663 * @param[out] broken_encoding will be set to true if any '%' symbol is not 664 * followed by two valid hexadecimal digits, 665 * optional, can be NULL 666 * @return the number of characters written to the output buffer or 667 * zero if output buffer is too small to hold the result 668 */ 669 MHD_INTERNAL size_t 670 mhd_str_pct_decode_lenient_n (const char *pct_encoded, 671 size_t pct_encoded_len, 672 char *decoded, 673 size_t buf_size, 674 bool *restrict broken_encoding) 675 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3) 676 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4); 677 678 679 /** 680 * Decode string in-place with percent-encoded characters as defined by 681 * RFC 3986 #section-2.1. 682 * 683 * This function decode string by converting percent-encoded characters to 684 * their decoded versions and copying back all other characters without extra 685 * processing. 686 * 687 * @param[in,out] str the string to be updated in-place, must be zero-terminated 688 * on input, the output is zero-terminated; the string is 689 * truncated to zero length if broken encoding is found 690 * @return the number of character in decoded string 691 */ 692 MHD_INTERNAL size_t 693 mhd_str_pct_decode_in_place_strict (char *str) 694 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1); 695 696 697 /** 698 * Decode string in-place with percent-encoded characters as defined by 699 * RFC 3986 #section-2.1. 700 * 701 * This function decode string by converting percent-encoded characters to 702 * their decoded versions and copying back all other characters without extra 703 * processing. 704 * 705 * Any invalid percent-encoding sequences ('%' symbol not followed by two 706 * valid hexadecimal digits) are copied to the output string without decoding. 707 * 708 * @param[in,out] str the string to be updated in-place, must be zero-terminated 709 * on input, the output is zero-terminated 710 * @param[out] broken_encoding will be set to true if any '%' symbol is not 711 * followed by two valid hexadecimal digits, 712 * optional, can be NULL 713 * @return the number of character in decoded string 714 */ 715 MHD_INTERNAL size_t 716 mhd_str_pct_decode_in_place_lenient (char *restrict str, 717 bool *restrict broken_encoding) 718 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (1); 719 720 MHD_INTERNAL size_t 721 mhd_str_dec_norm_uri_path (size_t str_len, 722 char *restrict str) 723 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_INOUT_SIZE_ (2,1); 724 725 726 #ifdef MHD_SUPPORT_AUTH_DIGEST 727 /** 728 * Check two strings for equality, "unquoting" the first string from quoted 729 * form as specified by RFC7230#section-3.2.6 and RFC7694#quoted.strings. 730 * 731 * Null-termination for input strings is not required, binary zeros compared 732 * like other characters. 733 * 734 * @param quoted the quoted string to compare, must NOT include leading and 735 * closing DQUOTE chars, does not need to be zero-terminated 736 * @param quoted_len the length in chars of the @a quoted string 737 * @param unquoted the unquoted string to compare, does not need to be 738 * zero-terminated 739 * @param unquoted_len the length in chars of the @a unquoted string 740 * @return zero if quoted form is broken (no character after the last escaping 741 * backslash), zero if strings are not equal after unquoting of the 742 * first string, 743 * non-zero if two strings are equal after unquoting of the 744 * first string. 745 */ 746 MHD_INTERNAL bool 747 mhd_str_equal_quoted_bin_n (const char *quoted, 748 size_t quoted_len, 749 const char *unquoted, 750 size_t unquoted_len) 751 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ 752 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4); 753 754 /** 755 * Check whether the string after "unquoting" equals static string. 756 * 757 * Null-termination for input string is not required, binary zeros compared 758 * like other characters. 759 * 760 * @param q the quoted string to compare, must NOT include leading and 761 * closing DQUOTE chars, does not need to be zero-terminated 762 * @param l the length in chars of the @a q string 763 * @param u the unquoted static string to compare 764 * @return zero if quoted form is broken (no character after the last escaping 765 * backslash), zero if strings are not equal after unquoting of the 766 * first string, 767 * non-zero if two strings are equal after unquoting of the 768 * first string. 769 */ 770 #define mhd_str_equal_quoted_s_bin_n(q,l,u) \ 771 mhd_str_equal_quoted_bin_n (q,l,u,mhd_SSTR_LEN (u)) 772 773 /** 774 * Check two strings for equality, "unquoting" the first string from quoted 775 * form as specified by RFC7230#section-3.2.6 and RFC7694#quoted.strings and 776 * ignoring case of US-ASCII letters. 777 * 778 * Null-termination for input strings is not required, binary zeros compared 779 * like other characters. 780 * 781 * @param quoted the quoted string to compare, must NOT include leading and 782 * closing DQUOTE chars, does not need to be zero-terminated 783 * @param quoted_len the length in chars of the @a quoted string 784 * @param unquoted the unquoted string to compare, does not need to be 785 * zero-terminated 786 * @param unquoted_len the length in chars of the @a unquoted string 787 * @return zero if quoted form is broken (no character after the last escaping 788 * backslash), zero if strings are not equal after unquoting of the 789 * first string, 790 * non-zero if two strings are caseless equal after unquoting of the 791 * first string. 792 */ 793 MHD_INTERNAL bool 794 mhd_str_equal_caseless_quoted_bin_n (const char *quoted, 795 size_t quoted_len, 796 const char *unquoted, 797 size_t unquoted_len) 798 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ 799 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4); 800 801 /** 802 * Check whether the string after "unquoting" equals static string, ignoring 803 * case of US-ASCII letters. 804 * 805 * Null-termination for input string is not required, binary zeros compared 806 * like other characters. 807 * 808 * @param q the quoted string to compare, must NOT include leading and 809 * closing DQUOTE chars, does not need to be zero-terminated 810 * @param l the length in chars of the @a q string 811 * @param u the unquoted static string to compare 812 * @return zero if quoted form is broken (no character after the last escaping 813 * backslash), zero if strings are not equal after unquoting of the 814 * first string, 815 * non-zero if two strings are caseless equal after unquoting of the 816 * first string. 817 */ 818 #define mhd_str_equal_caseless_quoted_s_bin_n(q,l,u) \ 819 mhd_str_equal_caseless_quoted_bin_n (q,l,u,mhd_SSTR_LEN (u)) 820 821 #endif /* MHD_SUPPORT_AUTH_DIGEST */ 822 823 #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_POST_PARSER) 824 825 /** 826 * Convert string from quoted to unquoted form as specified by 827 * RFC7230#section-3.2.6 and RFC7694#quoted.strings. 828 * 829 * @param quoted the quoted string, must NOT include leading and closing 830 * DQUOTE chars, does not need to be zero-terminated 831 * @param quoted_len the length in chars of the @a quoted string 832 * @param[out] result the pointer to the buffer to put the result, must 833 * be at least @a size character long. May be modified even 834 * if @a quoted is invalid sequence. The result is NOT 835 * zero-terminated. 836 * @return The number of characters written to the output buffer, 837 * zero if last backslash is not followed by any character (or 838 * @a quoted_len is zero). 839 */ 840 MHD_INTERNAL size_t 841 mhd_str_unquote (const char *quoted, 842 size_t quoted_len, 843 char *result) 844 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,2); 845 846 #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_POST_PARSER */ 847 848 #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_AUTH_BASIC) 849 850 /** 851 * Convert string from unquoted to quoted form as specified by 852 * RFC7230#section-3.2.6 and RFC7694#quoted.strings. 853 * 854 * @param unquoted the unquoted string, does not need to be zero-terminated 855 * @param unquoted_len the length in chars of the @a unquoted string 856 * @param[out] result the pointer to the buffer to put the result. May be 857 * modified even if function failed due to insufficient 858 * space. The result is NOT zero-terminated and does not 859 * have opening and closing DQUOTE chars. 860 * @param buf_size the size of the allocated memory for @a result 861 * @return The number of copied characters, can be up to two times more than 862 * @a unquoted_len, zero if @a unquoted_len is zero or if quoted 863 * string is larger than @a buf_size. 864 */ 865 MHD_INTERNAL size_t 866 mhd_str_quote (const char *unquoted, 867 size_t unquoted_len, 868 char *result, 869 size_t buf_size) 870 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4); 871 872 #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_AUTH_BASIC */ 873 874 #ifdef MHD_SUPPORT_AUTH_BASIC 875 876 /** 877 * Returns the maximum possible size of the Base64 decoded data. 878 * The real recoded size could be up to two bytes smaller. 879 * @param enc_size the size of encoded data, in characters 880 * @return the maximum possible size of the decoded data, in bytes, if 881 * @a enc_size is valid (properly padded), 882 * undefined value smaller then @a enc_size if @a enc_size is not valid 883 */ 884 #define mhd_base64_max_dec_size(enc_size) (((enc_size) / 4) * 3) 885 886 /** 887 * Convert Base64 encoded string to binary data. 888 * @param base64 the input string with Base64 encoded data, could be NOT zero 889 * terminated 890 * @param base64_len the number of characters to decode in @a base64 string, 891 * valid number must be a multiple of four 892 * @param[out] bin the pointer to the output buffer, the buffer may be altered 893 * even if decoding failed 894 * @param bin_size the size of the @a bin buffer in bytes, if the size is 895 * at least @a base64_len / 4 * 3 then result will always 896 * fit, regardless of the amount of the padding characters 897 * @return 0 if @a base64_len is zero, or input string has wrong data (not 898 * valid Base64 sequence), or @a bin_size is too small; 899 * non-zero number of bytes written to the @a bin, the number must be 900 * (base64_len / 4 * 3 - 2), (base64_len / 4 * 3 - 1) or 901 * (base64_len / 4 * 3), depending on the number of padding characters. 902 */ 903 MHD_INTERNAL size_t 904 mhd_base64_to_bin_n (const char *base64, 905 size_t base64_len, 906 void *bin, 907 size_t bin_size) 908 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4); 909 910 #endif /* MHD_SUPPORT_AUTH_BASIC */ 911 912 913 /** 914 * Check whether the given field value string starts with given token. 915 * Token matched case-insensitive. 916 * 917 * Matched considered successful if string has given token at the first 918 * position. The token may be followed by optional whitespaces and the semicolon 919 * symbol. The string is not checked after the semicolon (if any). 920 * 921 * @param str the string to check 922 * @param token the token to find, must not be empty 923 * @return 'true' if match is successful, 924 * 'false' otherwise 925 */ 926 MHD_INTERNAL bool 927 mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str, 928 const struct MHD_String *restrict token) 929 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_; 930 931 932 /** 933 * The result of check for token with parameter 934 */ 935 enum MHD_FIXED_ENUM_ mhd_StingStartsWithTokenResult 936 { 937 /** 938 * The string does not start with the specified token 939 */ 940 mhd_STR_STARTS_W_TOKEN_NO_TOKEN = 0 941 , 942 /** 943 * The string has specified token at the initial position 944 * @note While formatting problems are not detected, it does not guarantee 945 * that string has a perfect format. 946 */ 947 mhd_STR_STARTS_W_TOKEN_HAS_TOKEN = 1 948 , 949 /** 950 * The string has specified token at the initial position, but broken 951 * formatting is detected. 952 */ 953 mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT = -1 954 }; 955 956 /** 957 * Check whether the given field value string starts with given token, find 958 * required parameter. 959 * Token and parameter matched case-insensitive. 960 * 961 * Matched considered successful if string has given token at the first 962 * position. The token should be followed by optional whitespaces and 963 * one or more parameters, delimited by the semicolon symbol. 964 * 965 * @param str the string to check 966 * @param token the token to find, must not be empty 967 * @param par the name of the parameter, must not be empty 968 * @param[out] par_value set to the found parameter value or @a data member 969 * set to NULL if parameter is not found 970 * @param par_value_needs_unquote set to 'true' if @a par_value 971 * needs to be "unquoted" 972 * @return result of token detection and string parsing; if token is found 973 * the presence of the required parameter is indicated only 974 * by @a par_value 975 * 976 */ 977 MHD_INTERNAL enum mhd_StingStartsWithTokenResult 978 mhd_str_starts_with_token_req_param ( 979 const struct MHD_String *restrict str, 980 const struct MHD_String *restrict token, 981 const struct MHD_String *restrict par, 982 struct mhd_BufferConst *restrict par_value, 983 bool *restrict par_value_needs_unquote) 984 MHD_FN_PAR_NONNULL_ALL_ 985 MHD_FN_PAR_IN_(1) MHD_FN_PAR_IN_(2) MHD_FN_PAR_IN_(3) 986 MHD_FN_PAR_OUT_(4) MHD_FN_PAR_OUT_ (5); 987 988 #endif /* MHD_STR_H */