post_parser_funcs.c (113869B)
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) 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/post_parser_funcs.c 41 * @brief The implementation of internal POST parser functions 42 * @author Karlson2k (Evgeny Grin) 43 */ 44 45 46 #include "mhd_sys_options.h" 47 48 #include "post_parser_funcs.h" 49 50 #include "mhd_assert.h" 51 #include "mhd_unreachable.h" 52 53 #include "mhd_post_parser.h" 54 55 #include <string.h> 56 57 #include "mhd_action.h" 58 #include "mhd_request.h" 59 #include "mhd_connection.h" 60 #include "mhd_daemon.h" 61 62 #include "mhd_str_macros.h" 63 64 #include "mhd_str.h" 65 #include "daemon_logger.h" 66 #include "stream_funcs.h" 67 #include "stream_process_request.h" 68 69 #include "daemon_funcs.h" 70 #include "request_get_value.h" 71 72 /** 73 * The result of 'multipart/form-data' processing 74 */ 75 enum MHD_FIXED_ENUM_ mhd_MPartDetectResult 76 { 77 /** 78 * Sting processed successfully, boundary detected 79 */ 80 mhd_MPART_DET_OK = 0 81 , 82 /** 83 * Error processing string, the error result is set 84 */ 85 mhd_MPART_DET_ERROR_SET 86 , 87 /** 88 * The string is not 'multipart/form-data' header 89 */ 90 mhd_MPART_DET_NO_MPART 91 }; 92 93 94 /** 95 * Process 'Content-Type:' header value as 'multipart/form-data' data to 96 * prepare POST parsing data, including setting correct 'boundary' value 97 * @param c the stream to use 98 * @param h_cnt_tp the 'Content-Type:' header value string 99 * @return 'mhd_MPART_DET_OK' if processed successfully and boundary has been 100 * detected and set, 101 * 'mhd_MPART_DET_ERROR_SET' is has some error in processing which 102 * resulted in specific error set in 103 * the stream, 104 * 'mhd_MPART_DET_NO_MPART' is string is not 'multipart/form-data' data 105 */ 106 static MHD_FN_PAR_NONNULL_ALL_ enum mhd_MPartDetectResult 107 process_mpart_header (struct MHD_Connection *restrict c, 108 const struct MHD_String *restrict h_cnt_tp) 109 { 110 static const struct MHD_String mpart_token = 111 mhd_MSTR_INIT ("multipart/form-data"); 112 static const struct MHD_String mpart_bound_par = 113 mhd_MSTR_INIT ("boundary"); 114 struct mhd_BufferConst mpart_bound; 115 bool mpart_bound_quoted; 116 enum mhd_StingStartsWithTokenResult res; 117 char *buf; 118 119 mhd_assert (NULL != h_cnt_tp->cstr); 120 121 res = mhd_str_starts_with_token_req_param (h_cnt_tp, 122 &mpart_token, 123 &mpart_bound_par, 124 &mpart_bound, 125 &mpart_bound_quoted); 126 127 if (mhd_STR_STARTS_W_TOKEN_NO_TOKEN == res) 128 return mhd_MPART_DET_NO_MPART; 129 130 if (mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT == res) 131 { 132 mhd_LOG_PRINT (c->daemon, \ 133 MHD_SC_REQ_POST_PARSE_FAILED_HEADER_MISFORMED, \ 134 mhd_LOG_FMT ("The request POST data cannot be parsed " \ 135 "because 'Content-Type: " \ 136 "multipart/form-data' header is " \ 137 "misformed: %.*s%s"), \ 138 (int) ((h_cnt_tp->len <= 127) ? h_cnt_tp->len : 127), 139 h_cnt_tp->cstr, 140 (h_cnt_tp->len <= 127) ? "" : "..."); 141 c->rq.u_proc.post.parse_result = 142 MHD_POST_PARSE_RES_FAILED_HEADER_MISFORMED; 143 return mhd_MPART_DET_ERROR_SET; 144 } 145 146 mhd_assert (mhd_STR_STARTS_W_TOKEN_HAS_TOKEN == res); 147 148 if (0 == mpart_bound.size) 149 { 150 mhd_LOG_MSG (c->daemon, \ 151 MHD_SC_REQ_POST_PARSE_FAILED_HEADER_NO_BOUNDARY, \ 152 "The request POST data cannot be parsed because " \ 153 "'Content-Type: multipart/form-data' header has " \ 154 "no 'boundary' parameter value."); 155 c->rq.u_proc.post.parse_result = 156 MHD_POST_PARSE_RES_FAILED_HEADER_NO_BOUNDARY; 157 return mhd_MPART_DET_ERROR_SET; 158 } 159 160 mhd_assert (NULL != mpart_bound.data); 161 162 buf = (char *) 163 mhd_stream_alloc_memory (c, 164 mpart_bound.size + 4); 165 if (NULL == buf) 166 { 167 /* It is very low probability that pool would not have memory just 168 * to held the small boundary string. While it could be possible 169 * to allocate memory from "large buffer", it would over-complicate 170 * code here and at freeing part. */ 171 mhd_LOG_MSG (c->daemon, MHD_SC_REQ_POST_PARSE_FAILED_NO_POOL_MEM, \ 172 "The request POST data cannot be parsed because " \ 173 "there is not enough pool memory."); 174 c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_FAILED_NO_POOL_MEM; 175 return mhd_MPART_DET_ERROR_SET; 176 } 177 178 c->rq.u_proc.post.enc = MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA; 179 180 buf[0] = '\r'; 181 buf[1] = '\n'; 182 buf[2] = '-'; 183 buf[3] = '-'; 184 185 if (! mpart_bound_quoted) 186 { 187 memcpy (buf + 4, 188 mpart_bound.data, 189 mpart_bound.size); 190 c->rq.u_proc.post.e_d.m_form.delim.data = buf; 191 c->rq.u_proc.post.e_d.m_form.delim.size = mpart_bound.size + 4; 192 } 193 else 194 { 195 size_t unq_size; 196 mhd_assert (2 <= mpart_bound.size); /* At least one char and at least one '\' */ 197 198 unq_size = mhd_str_unquote (mpart_bound.data, 199 mpart_bound.size, 200 buf + 4); 201 c->rq.u_proc.post.e_d.m_form.delim.data = buf; 202 c->rq.u_proc.post.e_d.m_form.delim.size = unq_size + 4; 203 } 204 mhd_assert (4 < c->rq.u_proc.post.e_d.m_form.delim.size); 205 return mhd_MPART_DET_OK; 206 } 207 208 209 /** 210 * Detect used POST encoding and 'boundary' for 'multipart/form-data'. 211 * @param c the stream to use 212 * @return 'true' if detected successfully, 213 * 'false' if POST encoding cannot be detected 214 */ 215 static MHD_FN_PAR_NONNULL_ (1) bool 216 detect_post_enc (struct MHD_Connection *restrict c) 217 { 218 struct MHD_StringNullable hdr_cnt_tp; 219 220 mhd_assert (mhd_HTTP_STAGE_BODY_RECEIVING > c->stage); 221 222 if (! mhd_request_get_value_st (&(c->rq), 223 MHD_VK_HEADER, 224 MHD_HTTP_HEADER_CONTENT_TYPE, 225 &hdr_cnt_tp)) 226 { 227 mhd_LOG_MSG (c->daemon, MHD_SC_REQ_POST_PARSE_FAILED_NO_CNTN_TYPE, \ 228 "The request POST data cannot be parsed because " \ 229 "the request has no 'Content-Type:' header and no " \ 230 "explicit POST encoding is set."); 231 c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_FAILED_NO_CNTN_TYPE; 232 return false; /* The "Content-Type:" is not defined by the client */ 233 } 234 235 mhd_assert (NULL != hdr_cnt_tp.cstr); 236 237 if (mhd_str_equal_caseless_n_st ("application/x-www-form-urlencoded", 238 hdr_cnt_tp.cstr, 239 hdr_cnt_tp.len)) 240 { 241 c->rq.u_proc.post.enc = MHD_HTTP_POST_ENCODING_FORM_URLENCODED; 242 return true; 243 } 244 245 if (1) 246 { 247 enum mhd_MPartDetectResult res; 248 249 res = process_mpart_header (c, 250 (const struct MHD_String *) (const void *) 251 &hdr_cnt_tp); 252 253 if (mhd_MPART_DET_OK == res) 254 return true; 255 256 if (mhd_MPART_DET_ERROR_SET == res) 257 return false; 258 259 mhd_assert (mhd_MPART_DET_NO_MPART == res); 260 } 261 262 if (1) 263 { 264 static const struct MHD_String txt_tkn = mhd_MSTR_INIT ("text/plain"); 265 struct MHD_String h_cnt_tp_copy; 266 mhd_assert (NULL != hdr_cnt_tp.cstr); 267 h_cnt_tp_copy.len = hdr_cnt_tp.len; 268 h_cnt_tp_copy.cstr = hdr_cnt_tp.cstr; 269 270 if (mhd_str_starts_with_token_opt_param (&h_cnt_tp_copy, 271 &txt_tkn)) 272 { 273 c->rq.u_proc.post.enc = MHD_HTTP_POST_ENCODING_TEXT_PLAIN; 274 return true; 275 } 276 } 277 mhd_LOG_MSG (c->daemon, \ 278 MHD_SC_REQ_POST_PARSE_FAILED_UNKNOWN_CNTN_TYPE, \ 279 "The request POST data cannot be parsed because " \ 280 "'Content-Type' header value is unknown or unsupported."); 281 c->rq.u_proc.post.parse_result = 282 MHD_POST_PARSE_RES_FAILED_UNKNOWN_CNTN_TYPE; 283 return false; 284 } 285 286 287 /** 288 * Detect 'boundary' for 'multipart/form-data' POST encoding. 289 * @param c the stream to use 290 * @return 'true' if succeed, 291 * 'false' if failed and error result is set 292 */ 293 static MHD_FN_PAR_NONNULL_ALL_ bool 294 detect_mpart_boundary_from_the_header (struct MHD_Connection *restrict c) 295 { 296 struct MHD_StringNullable hdr_cnt_tp; 297 enum mhd_MPartDetectResult res; 298 299 mhd_assert (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == \ 300 c->rq.app_act.head_act.data.post_parse.enc); 301 302 if (! mhd_request_get_value_st (&(c->rq), 303 MHD_VK_HEADER, 304 MHD_HTTP_HEADER_CONTENT_TYPE, 305 &hdr_cnt_tp)) 306 { 307 mhd_LOG_MSG (c->daemon, MHD_SC_REQ_POST_PARSE_FAILED_NO_CNTN_TYPE, \ 308 "The request POST data cannot be parsed because " \ 309 "'multipart/form-data' requires 'boundary' parameter, but " \ 310 "the request has no 'Content-Type:' header."); 311 c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_FAILED_NO_CNTN_TYPE; 312 return false; 313 } 314 315 mhd_assert (NULL != hdr_cnt_tp.cstr); 316 317 res = process_mpart_header (c, 318 (const struct MHD_String *) (const void *) 319 &hdr_cnt_tp); 320 321 if (mhd_MPART_DET_OK == res) 322 return true; 323 324 if (mhd_MPART_DET_NO_MPART == res) 325 { 326 mhd_LOG_MSG (c->daemon, MHD_SC_REQ_POST_PARSE_FAILED_HEADER_NOT_MPART, \ 327 "The request POST data cannot be parsed because " \ 328 "'multipart/form-data' requires 'boundary' parameter, but " \ 329 "the request has no 'Content-Type: multipart/form-data' " \ 330 "header."); 331 c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_FAILED_HEADER_NOT_MPART; 332 return false; 333 } 334 335 mhd_assert (mhd_MPART_DET_ERROR_SET == res); 336 return false; 337 } 338 339 340 /** 341 * Reset field parsing data for "application/x-www-form-urlencoded" 342 * @param pdata the parsing data 343 */ 344 static MHD_FN_PAR_NONNULL_ (1) void 345 reset_parse_field_data_urlenc (struct mhd_PostParserData *pdata) 346 { 347 mhd_assert (MHD_HTTP_POST_ENCODING_FORM_URLENCODED == pdata->enc); 348 memset (&(pdata->e_d.u_enc), 0, sizeof(pdata->e_d.u_enc)); 349 pdata->field_start = 0; 350 } 351 352 353 /** 354 * Initial reset field parsing data for "multipart/form-data" 355 * @param pdata the parsing data 356 */ 357 static MHD_FN_PAR_NONNULL_ (1) void 358 reset_parse_field_data_mpart_init (struct mhd_PostParserData *pdata) 359 { 360 mhd_assert (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == pdata->enc); 361 memset (&(pdata->e_d.m_form.f), 0, sizeof(pdata->e_d.m_form.f)); 362 pdata->e_d.m_form.st = mhd_POST_MPART_ST_NOT_STARTED; 363 pdata->e_d.m_form.line_start = mhd_POST_INVALID_POS; 364 pdata->e_d.m_form.delim_check_start = mhd_POST_INVALID_POS; 365 mhd_assert (NULL != pdata->e_d.m_form.delim.data); 366 mhd_assert (4 < pdata->e_d.m_form.delim.size); 367 mhd_assert (0 == memcmp (pdata->e_d.m_form.delim.data, "\r\n--", 4)); 368 mhd_assert (NULL == memchr (pdata->e_d.m_form.delim.data + 4, '\r', \ 369 pdata->e_d.m_form.delim.size - 4)); 370 mhd_assert (NULL == memchr (pdata->e_d.m_form.delim.data + 4, '\n', \ 371 pdata->e_d.m_form.delim.size - 4)); 372 pdata->field_start = 0; 373 } 374 375 376 /** 377 * Reset field parsing data for "multipart/form-data" after processing 378 * previous field 379 * @param pdata the parsing data 380 * @param final 'true' if last field was "closed" by the "final" delimiter 381 */ 382 static MHD_FN_PAR_NONNULL_ (1) void 383 reset_parse_field_data_mpart_cont (struct mhd_PostParserData *pdata, 384 bool final) 385 { 386 mhd_assert (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == pdata->enc); 387 memset (&(pdata->e_d.m_form.f), 0, sizeof(pdata->e_d.m_form.f)); 388 pdata->e_d.m_form.st = final ? 389 mhd_POST_MPART_ST_EPILOGUE : 390 mhd_POST_MPART_ST_PART_START; 391 pdata->field_start = 0; 392 } 393 394 395 /** 396 * Reset field parsing data for "text/plain" 397 * @param pdata the parsing data 398 */ 399 static MHD_FN_PAR_NONNULL_ (1) void 400 reset_parse_field_data_text (struct mhd_PostParserData *pdata) 401 { 402 mhd_assert (MHD_HTTP_POST_ENCODING_TEXT_PLAIN == pdata->enc); 403 memset (&(pdata->e_d.text), 0, sizeof(pdata->e_d.text)); 404 pdata->field_start = 0; 405 } 406 407 408 /** 409 * Finish initialisation of data for POST parsing 410 * @param c the stream to use 411 */ 412 static MHD_FN_PAR_NONNULL_ (1) void 413 init_post_parse_data (struct MHD_Connection *restrict c) 414 { 415 struct mhd_PostParserData *const pdata = 416 &(c->rq.u_proc.post); 417 418 mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act); 419 mhd_assert (MHD_HTTP_POST_ENCODING_OTHER != \ 420 c->rq.u_proc.post.enc); 421 mhd_assert (0 == pdata->lbuf_used); 422 423 pdata->lbuf_limit = c->rq.app_act.head_act.data.post_parse.buffer_size; 424 425 switch (pdata->enc) 426 { 427 case MHD_HTTP_POST_ENCODING_FORM_URLENCODED: 428 reset_parse_field_data_urlenc (pdata); 429 break; 430 case MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA: 431 reset_parse_field_data_mpart_init (pdata); 432 break; 433 case MHD_HTTP_POST_ENCODING_TEXT_PLAIN: 434 reset_parse_field_data_text (pdata); 435 break; 436 case MHD_HTTP_POST_ENCODING_OTHER: 437 default: 438 mhd_UNREACHABLE (); 439 break; 440 } 441 } 442 443 444 MHD_INTERNAL 445 MHD_FN_PAR_NONNULL_ (1) bool 446 mhd_stream_prepare_for_post_parse (struct MHD_Connection *restrict c) 447 { 448 mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act); 449 if (MHD_HTTP_POST_ENCODING_OTHER == 450 c->rq.app_act.head_act.data.post_parse.enc) 451 { 452 if (! detect_post_enc (c)) 453 { 454 mhd_assert (MHD_POST_PARSE_RES_OK != c->rq.u_proc.post.parse_result); 455 c->discard_request = true; 456 c->stage = mhd_HTTP_STAGE_FULL_REQ_RECEIVED; 457 return false; 458 } 459 } 460 else if (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == 461 c->rq.app_act.head_act.data.post_parse.enc) 462 { 463 if (! detect_mpart_boundary_from_the_header (c)) 464 { 465 mhd_assert (MHD_POST_PARSE_RES_OK != c->rq.u_proc.post.parse_result); 466 c->discard_request = true; 467 c->stage = mhd_HTTP_STAGE_FULL_REQ_RECEIVED; 468 return false; 469 } 470 } 471 else 472 c->rq.u_proc.post.enc = c->rq.app_act.head_act.data.post_parse.enc; 473 474 mhd_assert (MHD_HTTP_POST_ENCODING_OTHER != \ 475 c->rq.u_proc.post.enc); 476 mhd_assert ((MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA != \ 477 c->rq.u_proc.post.enc) || \ 478 (4 < c->rq.u_proc.post.e_d.m_form.delim.size)); 479 480 init_post_parse_data (c); 481 482 return true; 483 } 484 485 486 #if 0 /* Disable unused functions */ 487 488 /** 489 * Allocate memory from "large shared buffer" for POST parsing 490 * @param c the stream to use 491 * @param alloc_size the size to allocate 492 * @param[out] buf the buffer to allocate 493 * @return 'true' if succeed, 494 * 'false' otherwise 495 */ 496 static MHD_FN_PAR_NONNULL_ALL_ 497 MHD_FN_PAR_INOUT_ (3) bool 498 get_lbuf_fixed_size (struct MHD_Connection *restrict c, 499 size_t alloc_size, 500 struct mhd_Buffer *restrict buf) 501 { 502 mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act); 503 mhd_assert (0 == buf->size); 504 mhd_assert (NULL == buf->data); 505 506 if (alloc_size > c->rq.u_proc.post.lbuf_limit) 507 return false; 508 509 return mhd_daemon_get_lbuf (c->daemon, 510 alloc_size, 511 buf); 512 } 513 514 515 /** 516 * Grow the allocated memory from "large shared buffer" for POST parsing 517 * @param c the stream to use 518 * @param grow_size the size to grow 519 * @param[in,out] buf the buffer to grow 520 * @return 'true' if succeed, 521 * 'false' otherwise 522 */ 523 static MHD_FN_PAR_NONNULL_ALL_ 524 MHD_FN_PAR_INOUT_ (3) bool 525 grow_lbuf_fixed_size (struct MHD_Connection *restrict c, 526 size_t grow_size, 527 struct mhd_Buffer *restrict buf) 528 { 529 mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act); 530 mhd_assert (0 != buf->size); 531 mhd_assert (NULL != buf->data); 532 mhd_assert (c->rq.u_proc.post.lbuf_limit >= buf->size); 533 534 if (buf->size + grow_size > c->rq.u_proc.post.lbuf_limit) 535 return false; 536 537 return mhd_daemon_grow_lbuf (c->daemon, 538 grow_size, 539 buf); 540 } 541 542 543 #endif /* Disable unused functions */ 544 545 /** 546 * Grow or allocate the new memory from "large shared buffer" for POST parsing 547 * If the requested grow size is not possible, grow up to max possible size. 548 * @param c the stream to use 549 * @param desired_grow_size the desired size to grow 550 * @param[in,out] buf the buffer to grow 551 * @return the resulting grow size 552 */ 553 static MHD_FN_PAR_NONNULL_ALL_ 554 MHD_FN_PAR_INOUT_ (3) size_t 555 extend_lbuf_up_to (struct MHD_Connection *restrict c, 556 size_t desired_grow_size, 557 struct mhd_Buffer *restrict buf) 558 { 559 mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act); 560 mhd_assert (c->rq.u_proc.post.lbuf_limit >= buf->size); 561 562 if (buf->size + desired_grow_size > c->rq.u_proc.post.lbuf_limit) 563 desired_grow_size = c->rq.u_proc.post.lbuf_limit - buf->size; 564 565 if (0 == desired_grow_size) 566 return 0; 567 568 return mhd_daemon_extend_lbuf_up_to (c->daemon, 569 desired_grow_size, 570 buf); 571 } 572 573 574 /** 575 * Report "no memory in larger shared buffer". 576 * Set parsing status accordingly 577 * @param c the stream to use 578 * @return 'true' if the stream state has been changed, 579 * 'false' otherwise 580 */ 581 static MHD_FN_PAR_NONNULL_ALL_ bool 582 report_low_lbuf_mem (struct MHD_Connection *restrict c) 583 { 584 mhd_LOG_MSG (c->daemon, \ 585 MHD_SC_REQ_POST_PARSE_FAILED_NO_LARGE_BUF_MEM, \ 586 "Not enough large shared buffer memory to " \ 587 "parse POST request."); 588 c->rq.u_proc.post.parse_result = 589 MHD_POST_PARSE_RES_FAILED_NO_LARGE_BUF_MEM; 590 if (c->stage < mhd_HTTP_STAGE_FULL_REQ_RECEIVED) 591 { 592 c->discard_request = true; 593 c->stage = mhd_HTTP_STAGE_FULL_REQ_RECEIVED; 594 595 return true; 596 } 597 return false; 598 } 599 600 601 /** 602 * Report broken POST encoding termination 603 * @param c the stream to use 604 */ 605 static MHD_FN_PAR_NONNULL_ALL_ void 606 report_invalid_termination (struct MHD_Connection *restrict c) 607 { 608 mhd_LOG_MSG (c->daemon, \ 609 MHD_SC_REQ_POST_PARSE_OK_BAD_TERMINATION, \ 610 "The POST request content has invalid termination / ending. " \ 611 "The last parsed field may be incorrect."); 612 c->rq.u_proc.post.parse_result = MHD_POST_PARSE_RES_OK_BAD_TERMINATION; 613 } 614 615 616 /** 617 * Test whether current incomplete value must be provided to the "stream" 618 * reader. 619 * @param c the connection to use 620 * @param field_cur_size the current size of the current field 621 * @return 'true' if the value must be provided via the "stream" reader, 622 * 'false' otherwise. 623 */ 624 mhd_static_inline MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ bool 625 is_value_streaming_needed (struct MHD_Connection *restrict c, 626 size_t field_cur_size) 627 { 628 struct mhd_PostParseActionData *const p_par = 629 &(c->rq.app_act.head_act.data.post_parse); 630 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 631 632 if (NULL == p_par->stream_reader) 633 { 634 mhd_assert (0 == p_data->value_off); 635 mhd_assert (! p_data->force_streamed); 636 return false; /* No value streaming possible */ 637 } 638 639 /* If part of the value has been already provided to "stream" 640 reader, the rest of the value should be provided 641 in the same way */ 642 mhd_assert ((0 == p_data->value_off) || p_data->force_streamed); 643 if (p_data->force_streamed) 644 return true; 645 646 return (p_par->max_nonstream_size < field_cur_size); 647 } 648 649 650 /** 651 * Add parsed POST field to the list of request's fields 652 * @param c the stream to use 653 * @param name the name of the field 654 * @param filename the filename of the field 655 * @param content_type the "Content-Type:" of the field 656 * @param transfer_encoding the "Transfer-Encoding:" of the field 657 * @param value the value of the field 658 * @return 'true' if succeed, 659 * 'false' if memory allocation failed (no pool memory in the stream) 660 */ 661 static MHD_FN_PAR_NONNULL_ALL_ bool 662 add_parsed_post_field (struct MHD_Connection *restrict c, 663 struct mhd_PositionAndLength *restrict name, 664 struct mhd_PositionAndLength *restrict filename, 665 struct mhd_PositionAndLength *restrict content_type, 666 struct mhd_PositionAndLength *restrict transfer_encoding, 667 struct mhd_PositionAndLength *restrict value) 668 { 669 struct mhd_RequestPostField *pfield; 670 671 mhd_assert ((0 != filename->pos) || (0 == filename->len)); 672 mhd_assert ((0 != content_type->pos) || (0 == content_type->len)); 673 mhd_assert ((0 != transfer_encoding->pos) || \ 674 (0 == transfer_encoding->len)); 675 mhd_assert ((0 != value->pos) || (0 == value->len)); 676 677 pfield = (struct mhd_RequestPostField *) 678 mhd_stream_alloc_memory (c, 679 sizeof (struct mhd_RequestPostField)); 680 if (NULL == pfield) 681 return false; 682 683 pfield->field.name = *name; 684 pfield->field.value = *value; 685 pfield->field.filename = *filename; 686 pfield->field.content_type = *content_type; 687 pfield->field.transfer_encoding = *transfer_encoding; 688 689 mhd_DLINKEDL_INIT_LINKS (pfield, post_fields); 690 691 mhd_DLINKEDL_INS_LAST (&(c->rq), pfield, post_fields); 692 693 return true; 694 } 695 696 697 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ 698 MHD_FN_PAR_IN_ (1) 699 MHD_FN_PAR_OUT_ (10) MHD_FN_PAR_OUT_ (11) 700 MHD_FN_PAR_OUT_ (12) MHD_FN_PAR_OUT_ (13) void 701 make_post_strings_from_buf_and_indices (const char *restrict buf, 702 size_t name_start, 703 size_t name_len, 704 size_t filename_start, 705 size_t filename_len, 706 size_t cntn_type_start, 707 size_t cntn_type_len, 708 size_t enc_start, 709 size_t enc_len, 710 struct MHD_String *name, 711 struct MHD_StringNullable *filename, 712 struct MHD_StringNullable *content_type, 713 struct MHD_StringNullable *encoding) 714 { 715 name->len = name_len; 716 name->cstr = buf + name_start; 717 718 if (0 != filename_start) 719 { 720 filename->len = filename_len; 721 filename->cstr = buf + filename_start; 722 } 723 else 724 { 725 filename->len = 0; 726 filename->cstr = NULL; 727 } 728 if (0 != cntn_type_start) 729 { 730 content_type->len = cntn_type_len; 731 content_type->cstr = buf + cntn_type_start; 732 } 733 else 734 { 735 content_type->len = 0; 736 content_type->cstr = NULL; 737 } 738 if (0 != enc_start) 739 { 740 encoding->len = enc_len; 741 encoding->cstr = buf + enc_start; 742 } 743 else 744 { 745 encoding->len = 0; 746 encoding->cstr = NULL; 747 } 748 } 749 750 751 /** 752 * Process new full parsed POST field 753 * @param c the stream to use 754 * @param buf the buffer, where the data is 755 * @param pfield_next_pos the pointer to variable holding index of 756 * the next field to be parsed 757 * @param pdata_size the pointer to variable holding the size of the data 758 * @param field_start the start of the current field in the @a buf 759 * @param name_start the start of the name of the field in the @a buf 760 * @param name_len the length of the name, not including mandatory terminating 761 * zero 762 * @param filename_start the start of the filename of the field in the @a buf, 763 * zero if no filename is provided 764 * @param filename_len the length of the filename, not including mandatory 765 * terminating zero 766 * @param cntn_type_start the start of the Content-Type value of the field in 767 * the @a buf, zero if no Content-Type is provided 768 * @param cntn_type_len the length of the Content-Type value, not including 769 * mandatory terminating zero 770 * @param enc_start the start of the Content-Encoding value of the field in 771 * the @a buf, zero if no Content-Encoding is provided 772 * @param enc_len the length of the Content-Encoding value, not including 773 * mandatory terminating zero 774 * @param value_start the start of the field value in the @a buf, zero if 775 * no value is provided 776 * @param value_len the length of the field value, not including mandatory 777 * terminating zero 778 * @return 'true' if stream state has been changed, 779 * 'false' to continue parsing 780 */ 781 static MHD_FN_PAR_NONNULL_ALL_ bool 782 process_complete_field_all (struct MHD_Connection *restrict c, 783 char *restrict buf, 784 size_t *restrict pfield_next_pos, 785 size_t *restrict pdata_size, 786 size_t field_start, 787 size_t name_start, 788 size_t name_len, 789 size_t filename_start, 790 size_t filename_len, 791 size_t cntn_type_start, 792 size_t cntn_type_len, 793 size_t enc_start, 794 size_t enc_len, 795 size_t value_start, 796 size_t value_len) 797 { 798 struct mhd_PostParseActionData *const p_par = 799 &(c->rq.app_act.head_act.data.post_parse); 800 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 801 802 mhd_assert (mhd_ACTION_POST_PARSE == c->rq.app_act.head_act.act); 803 804 mhd_assert ((0 == filename_start) || \ 805 (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == p_data->enc)); 806 mhd_assert ((0 == cntn_type_start) || \ 807 (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == p_data->enc)); 808 mhd_assert ((0 == enc_start) || \ 809 (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == p_data->enc)); 810 811 mhd_assert (mhd_HTTP_STAGE_REQ_RECV_FINISHED >= c->stage); 812 mhd_assert (value_start + value_len <= *pfield_next_pos); 813 mhd_assert ((mhd_HTTP_STAGE_FULL_REQ_RECEIVED <= c->stage) || \ 814 (value_start + value_len < *pfield_next_pos)); 815 mhd_assert (*pfield_next_pos <= *pdata_size); 816 mhd_assert ((name_start + name_len < value_start) || \ 817 (0 == value_start)); 818 mhd_assert (value_start + value_len <= *pfield_next_pos); 819 mhd_assert ((mhd_HTTP_STAGE_FULL_REQ_RECEIVED <= c->stage) || \ 820 (name_start + name_len < *pfield_next_pos)); 821 mhd_assert ((filename_start + filename_len < value_start) || \ 822 (0 == value_start)); 823 mhd_assert (filename_start + filename_len <= *pfield_next_pos); 824 mhd_assert ((cntn_type_start + cntn_type_len < value_start) || \ 825 (0 == value_start)); 826 mhd_assert (cntn_type_start + cntn_type_len <= *pfield_next_pos); 827 mhd_assert ((enc_start + enc_len < value_start) || \ 828 (0 == value_start)); 829 mhd_assert (enc_start + enc_len <= *pfield_next_pos); 830 mhd_assert (field_start <= name_start); 831 mhd_assert ((field_start <= filename_start) || (0 == filename_start)); 832 mhd_assert ((field_start <= cntn_type_start) || (0 == cntn_type_start)); 833 mhd_assert ((field_start <= enc_start) || (0 == enc_start)); 834 mhd_assert ((field_start <= value_start) || (0 == value_start)); 835 mhd_assert ((0 != filename_start) || (0 == filename_len)); 836 mhd_assert ((0 != cntn_type_start) || (0 == cntn_type_len)); 837 mhd_assert ((0 != enc_start) || (0 == enc_len)); 838 mhd_assert ((0 != value_start) || (0 == value_len)); 839 mhd_assert (0 == buf [name_start + name_len]); 840 841 p_data->some_data_provided = true; 842 843 if (is_value_streaming_needed (c, (*pfield_next_pos - field_start))) 844 { 845 bool res; 846 const struct MHD_UploadAction *act; 847 struct MHD_String name; 848 struct MHD_StringNullable filename; 849 struct MHD_StringNullable content_type; 850 struct MHD_StringNullable encoding; 851 852 make_post_strings_from_buf_and_indices (buf, 853 name_start, 854 name_len, 855 filename_start, 856 filename_len, 857 cntn_type_start, 858 cntn_type_len, 859 enc_start, 860 enc_len, 861 &name, 862 &filename, 863 &content_type, 864 &encoding); 865 866 act = p_par->stream_reader (&(c->rq), 867 p_par->reader_cls, 868 &name, 869 &filename, 870 &content_type, 871 &encoding, 872 value_len, 873 buf + value_start, 874 p_data->value_off, 875 MHD_YES); 876 p_data->some_data_provided = true; 877 res = mhd_stream_process_upload_action (c, act, false); 878 if (c->suspended) 879 return true; 880 p_data->force_streamed = false; 881 p_data->value_off = 0; 882 if (*pdata_size > *pfield_next_pos) 883 { 884 size_t consumed_size; 885 memmove (buf + field_start, 886 buf + *pfield_next_pos, 887 *pdata_size - *pfield_next_pos); 888 consumed_size = *pfield_next_pos - field_start; 889 *pfield_next_pos = field_start; 890 *pdata_size -= consumed_size; 891 } 892 else 893 { 894 *pfield_next_pos = field_start; 895 *pdata_size = field_start; 896 } 897 return res; 898 } 899 else 900 { 901 struct mhd_PositionAndLength name_i; 902 struct mhd_PositionAndLength filename_i; 903 struct mhd_PositionAndLength content_type_i; 904 struct mhd_PositionAndLength encoding_i; 905 struct mhd_PositionAndLength value_i; 906 907 mhd_assert (! p_data->force_streamed); 908 mhd_assert (0 == p_data->value_off); 909 mhd_assert ((0 == value_start) || (0 == buf [value_start + value_len])); 910 911 name_i.pos = name_start; 912 name_i.len = name_len; 913 filename_i.pos = filename_start; 914 filename_i.len = filename_len; 915 content_type_i.pos = cntn_type_start; 916 content_type_i.len = cntn_type_len; 917 encoding_i.pos = enc_start; 918 encoding_i.len = enc_len; 919 value_i.pos = value_start; 920 value_i.len = value_len; 921 922 if (! add_parsed_post_field (c, 923 &name_i, 924 &filename_i, 925 &content_type_i, 926 &encoding_i, 927 &value_i)) 928 { 929 c->stage = mhd_HTTP_STAGE_FULL_REQ_RECEIVED; 930 mhd_LOG_MSG (c->daemon, MHD_SC_REQ_POST_PARSE_FAILED_NO_POOL_MEM, \ 931 "The request POST data cannot be parsed completely " \ 932 "because there is not enough pool memory."); 933 p_data->parse_result = MHD_POST_PARSE_RES_FAILED_NO_POOL_MEM; 934 return true; 935 } 936 937 p_data->some_data_provided = true; 938 } 939 940 return false; /* Continue parsing */ 941 } 942 943 944 /** 945 * Process new full parsed POST field 946 * @param c the stream to use 947 * @param buf the buffer, where the data is 948 * @param pfield_next_pos the pointer to variable holding index of 949 * the next field to be parsed 950 * @param pdata_size the pointer to variable holding the size of the data 951 * @param field_start the start of the current field in the @a buf 952 * @param name_start the start of the name of the field in the @a buf 953 * @param name_len the length of the name, not including mandatory terminating 954 * zero 955 * @param value_start the start of the field value in the @a buf, zero if 956 * no value is provided 957 * @param value_len the length of the field value, not including mandatory 958 * terminating zero 959 * @return 'true' if stream state has been changed, 960 * 'false' to continue parsing 961 */ 962 static MHD_FN_PAR_NONNULL_ALL_ bool 963 process_complete_field (struct MHD_Connection *restrict c, 964 char *restrict buf, 965 size_t *restrict pfield_next_pos, 966 size_t *restrict pdata_size, 967 size_t field_start, 968 size_t name_start, 969 size_t name_len, 970 size_t value_start, 971 size_t value_len) 972 { 973 mhd_assert (mhd_HTTP_STAGE_REQ_RECV_FINISHED >= c->stage); 974 mhd_assert (value_start + value_len <= *pfield_next_pos); 975 mhd_assert ((mhd_HTTP_STAGE_FULL_REQ_RECEIVED <= c->stage) || \ 976 (value_start + value_len < *pfield_next_pos)); 977 mhd_assert ((name_start + name_len < value_start) || \ 978 (0 == value_start)); 979 mhd_assert (name_start + name_len <= *pfield_next_pos); 980 mhd_assert ((mhd_HTTP_STAGE_FULL_REQ_RECEIVED <= c->stage) || \ 981 (name_start + name_len < *pfield_next_pos)); 982 mhd_assert (field_start <= name_start); 983 mhd_assert ((field_start <= value_start) || (0 == value_start)); 984 985 mhd_assert (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA != \ 986 c->rq.u_proc.post.enc); 987 988 return process_complete_field_all (c, 989 buf, 990 pfield_next_pos, 991 pdata_size, 992 field_start, 993 name_start, 994 name_len, 995 0, 0, 0, 0, 0, 0, 996 value_start, 997 value_len); 998 } 999 1000 1001 /** 1002 * Process the part of the POST value. 1003 * 1004 * The part of the value are be provided for "streaming" processing by 1005 * the application callback and removed from the buffer (the remaining of 1006 * the data in the buffer is shifted backward). 1007 * The function must be called only when streaming is the partial value is 1008 * needed. 1009 * 1010 * @param c the connection to use 1011 * @param buf the pointer to the buffer 1012 * @param pnext_pos the position of the next character to be processed 1013 * in the buffer 1014 * @param pdata_size the size of the data in the buffer 1015 * @param name_start the position of the "name", must be zero-terminated 1016 * @param name_len the length of the "name", not including zero-termination 1017 * @param filename_start the position of the filename, zero if not 1018 * provided / set 1019 * @param filename_len the length of the filename 1020 * @param cntn_type_start the position of field "Content-Type" value, zero 1021 * if not provided / set 1022 * @param cntn_type_len the length of the field "Content-Type" value 1023 * @param enc_start the position of the field "Content-Encoding" value, zero 1024 * if not provided / set 1025 * @param enc_len the length of the field "Content-Encoding" value 1026 * @param part_value_start the position of partial value data, does not 1027 * need to be zero-terminated 1028 * @param part_value_len the length of the partial value data 1029 * @return 'true' if connection/stream state has been changed, 1030 * 'false' indicates the need to continuation of POST data parsing 1031 */ 1032 static MHD_FN_PAR_NONNULL_ALL_ bool 1033 process_partial_value_all (struct MHD_Connection *restrict c, 1034 char *restrict buf, 1035 size_t *restrict pnext_pos, 1036 size_t *restrict pdata_size, 1037 size_t name_start, 1038 size_t name_len, 1039 size_t filename_start, 1040 size_t filename_len, 1041 size_t cntn_type_start, 1042 size_t cntn_type_len, 1043 size_t enc_start, 1044 size_t enc_len, 1045 size_t part_value_start, 1046 size_t part_value_len) 1047 { 1048 struct mhd_PostParseActionData *const p_par = 1049 &(c->rq.app_act.head_act.data.post_parse); 1050 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 1051 struct MHD_String name; 1052 struct MHD_StringNullable filename; 1053 struct MHD_StringNullable content_type; 1054 struct MHD_StringNullable encoding; 1055 const struct MHD_UploadAction *act; 1056 bool res; 1057 1058 mhd_assert (mhd_HTTP_STAGE_REQ_RECV_FINISHED >= c->stage); 1059 mhd_assert (*pnext_pos <= *pdata_size); 1060 mhd_assert (part_value_start + part_value_len <= *pnext_pos); 1061 mhd_assert (0 != part_value_start); 1062 mhd_assert (0 != part_value_len); 1063 mhd_assert (name_start + name_len < *pnext_pos); 1064 mhd_assert (filename_start + filename_len < part_value_start); 1065 mhd_assert (filename_start + filename_len < *pnext_pos); 1066 mhd_assert (cntn_type_start + cntn_type_len < part_value_start); 1067 mhd_assert (cntn_type_start + cntn_type_len < *pnext_pos); 1068 mhd_assert (enc_start + enc_len < part_value_start); 1069 mhd_assert (enc_start + enc_len < *pnext_pos); 1070 mhd_assert ((0 != filename_start) || (0 == filename_len)); 1071 mhd_assert ((0 != cntn_type_start) || (0 == cntn_type_len)); 1072 mhd_assert ((0 != enc_start) || (0 == enc_len)); 1073 mhd_assert (NULL != p_par->stream_reader); 1074 1075 make_post_strings_from_buf_and_indices (buf, 1076 name_start, 1077 name_len, 1078 filename_start, 1079 filename_len, 1080 cntn_type_start, 1081 cntn_type_len, 1082 enc_start, 1083 enc_len, 1084 &name, 1085 &filename, 1086 &content_type, 1087 &encoding); 1088 1089 act = p_par->stream_reader (&(c->rq), 1090 p_par->reader_cls, 1091 &name, 1092 &filename, 1093 &content_type, 1094 &encoding, 1095 part_value_len, 1096 buf + part_value_start, 1097 p_data->value_off, 1098 MHD_NO); 1099 1100 p_data->some_data_provided = true; 1101 p_data->force_streamed = true; 1102 1103 res = mhd_stream_process_upload_action (c, act, false); 1104 if (c->suspended) 1105 return true; 1106 1107 p_data->value_off += part_value_len; 1108 if (*pdata_size > *pnext_pos) 1109 { 1110 size_t consumed_size; 1111 1112 memmove (buf + part_value_start, 1113 buf + *pnext_pos, 1114 *pdata_size - *pnext_pos); 1115 consumed_size = *pnext_pos - part_value_start; 1116 *pnext_pos = part_value_start; 1117 *pdata_size -= consumed_size; 1118 } 1119 else 1120 { 1121 mhd_assert (*pdata_size == *pnext_pos); 1122 *pnext_pos = part_value_start; 1123 *pdata_size = part_value_start; 1124 } 1125 return res; 1126 } 1127 1128 1129 /** 1130 * Process the part of the POST value. 1131 * The part of the value are be provided for "streaming" processing by 1132 * the application callback and removed from the buffer (the remaining of 1133 * the data in the buffer is shifted backward). 1134 * The function must be called only when streaming is the partial value is 1135 * needed. 1136 * @param c the connection to use 1137 * @param buf the pointer to the buffer 1138 * @param pnext_pos the position of the next character to be processed 1139 * in the buffer 1140 * @param pdata_size the size of the data in the buffer 1141 * @param name_start the position of the "name", must be zero-terminated 1142 * @param name_len the length of the "name", not including zero-termination 1143 * @param part_value_start the position of partial value data, does not 1144 * need to be zero-terminated 1145 * @param part_value_len the length of the partial value data 1146 * @return 'true' if connection/stream state has been changed, 1147 * 'false' indicates the need to continuation of POST data parsing 1148 */ 1149 static MHD_FN_PAR_NONNULL_ALL_ bool 1150 process_partial_value (struct MHD_Connection *restrict c, 1151 char *restrict buf, 1152 size_t *restrict pnext_pos, 1153 size_t *restrict pdata_size, 1154 size_t name_start, 1155 size_t name_len, 1156 size_t part_value_start, 1157 size_t part_value_len) 1158 { 1159 mhd_assert (mhd_HTTP_STAGE_REQ_RECV_FINISHED >= c->stage); 1160 mhd_assert (part_value_start + part_value_len <= *pnext_pos); 1161 mhd_assert (name_start + name_len < part_value_start); 1162 mhd_assert (0 != part_value_start); 1163 mhd_assert (0 != part_value_len); 1164 mhd_assert (name_start + name_len < *pnext_pos); 1165 1166 1167 mhd_assert (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA != \ 1168 c->rq.u_proc.post.enc); 1169 1170 return process_partial_value_all (c, 1171 buf, 1172 pnext_pos, 1173 pdata_size, 1174 name_start, 1175 name_len, 1176 0, 0, 0, 0, 0, 0, 1177 part_value_start, 1178 part_value_len); 1179 } 1180 1181 1182 /** 1183 * Parse "application/x-www-form-urlencoded" data 1184 * @param c the stream to use 1185 * @param pdata_size the pointer to variable holding the size of the data in 1186 * the @a buf 1187 * @param buf the buffer with the data 1188 * @return 'true' if stream state changed, 1189 * 'false' to continue parsing 1190 */ 1191 static MHD_FN_PAR_NONNULL_ALL_ 1192 MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (3) bool 1193 parse_post_urlenc (struct MHD_Connection *restrict c, 1194 size_t *restrict pdata_size, 1195 char *restrict buf) 1196 { 1197 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 1198 struct mhd_PostParserUrlEncData *const uf = &(p_data->e_d.u_enc); /**< the current "url-enc" field */ 1199 size_t i; 1200 1201 mhd_assert (MHD_HTTP_POST_ENCODING_FORM_URLENCODED == c->rq.u_proc.post.enc); 1202 mhd_assert (MHD_POST_PARSE_RES_OK == p_data->parse_result); 1203 mhd_assert (! c->discard_request); 1204 mhd_assert (p_data->next_parse_pos < *pdata_size); 1205 1206 if ((mhd_POST_UENC_ST_VALUE == uf->st) && 1207 (0 != uf->value_len)) 1208 { 1209 /* The 'value' was partially decoded, but not processed because application 1210 * asked for 'suspend' action */ 1211 mhd_assert (NULL != c->rq.app_act.head_act.data.post_parse.stream_reader); 1212 if (process_partial_value (c, 1213 buf, 1214 &p_data->next_parse_pos, 1215 pdata_size, 1216 uf->name_idx, 1217 uf->name_len, 1218 uf->value_idx, 1219 uf->value_len)) 1220 return true; 1221 uf->value_len = 0; 1222 } 1223 1224 i = p_data->next_parse_pos; 1225 while (*pdata_size > i) 1226 { 1227 switch (uf->st) 1228 { 1229 case mhd_POST_UENC_ST_NOT_STARTED: 1230 mhd_assert (0 == p_data->field_start); 1231 mhd_assert (0 == p_data->value_off); 1232 p_data->field_start = i; 1233 uf->name_idx = i; 1234 uf->last_pct_idx = mhd_POST_INVALID_POS; 1235 uf->st = mhd_POST_UENC_ST_NAME; 1236 mhd_FALLTHROUGH; 1237 /* Intentional fallthrough */ 1238 case mhd_POST_UENC_ST_NAME: 1239 do /* Fast local loop */ 1240 { 1241 if ('+' == buf[i]) 1242 buf[i] = ' '; 1243 else if ('%' == buf[i]) 1244 uf->last_pct_idx = i; 1245 else if ('=' == buf[i]) 1246 { 1247 uf->st = mhd_POST_UENC_ST_AT_EQ; 1248 break; 1249 } 1250 else if ('&' == buf[i]) 1251 { 1252 uf->st = mhd_POST_UENC_ST_AT_AMPRSND; 1253 break; 1254 } 1255 } while (*pdata_size > ++i); 1256 mhd_assert ((*pdata_size == i) || \ 1257 (mhd_POST_UENC_ST_AT_EQ == uf->st) || \ 1258 (mhd_POST_UENC_ST_AT_AMPRSND == uf->st) ); 1259 continue; 1260 case mhd_POST_UENC_ST_AT_EQ: 1261 mhd_assert (i > uf->name_idx); 1262 mhd_assert (0 == uf->name_len); 1263 mhd_assert (uf->last_pct_idx >= p_data->field_start); 1264 mhd_assert (uf->last_pct_idx >= uf->name_idx); 1265 mhd_assert ((uf->last_pct_idx == mhd_POST_INVALID_POS) || \ 1266 (uf->last_pct_idx < i)); 1267 mhd_assert (0 == uf->value_len); 1268 if (uf->last_pct_idx != mhd_POST_INVALID_POS) 1269 uf->name_len = mhd_str_pct_decode_lenient_n (buf + uf->name_idx, 1270 i - uf->name_idx, 1271 buf + uf->name_idx, 1272 i - uf->name_idx, 1273 NULL); 1274 else 1275 uf->name_len = i - uf->name_idx; 1276 buf[uf->name_idx + uf->name_len] = 0; /* Zero-terminate the name */ 1277 1278 uf->st = mhd_POST_UENC_ST_EQ_FOUND; 1279 ++i; /* Process the next char */ 1280 continue; /* Check whether the next char is available */ 1281 case mhd_POST_UENC_ST_EQ_FOUND: 1282 mhd_assert (0 == p_data->value_off); 1283 mhd_assert (0 == uf->value_idx); 1284 mhd_assert (0 == uf->value_len); 1285 mhd_assert (0 != i && "the 'value' should follow the 'name'"); 1286 uf->last_pct_idx = mhd_POST_INVALID_POS; 1287 uf->value_idx = i; 1288 uf->st = mhd_POST_UENC_ST_VALUE; 1289 mhd_FALLTHROUGH; 1290 /* Intentional fallthrough */ 1291 case mhd_POST_UENC_ST_VALUE: 1292 do /* Fast local loop */ 1293 { 1294 if ('+' == buf[i]) 1295 buf[i] = ' '; 1296 else if ('%' == buf[i]) 1297 uf->last_pct_idx = i; 1298 else if ('&' == buf[i]) 1299 { 1300 uf->st = mhd_POST_UENC_ST_AT_AMPRSND; 1301 break; 1302 } 1303 } while (*pdata_size > ++i); 1304 mhd_assert ((*pdata_size == i) || \ 1305 (mhd_POST_UENC_ST_AT_AMPRSND == uf->st)); 1306 continue; 1307 case mhd_POST_UENC_ST_AT_AMPRSND: 1308 mhd_assert (0 == uf->value_len); 1309 mhd_assert ((uf->last_pct_idx == mhd_POST_INVALID_POS) || \ 1310 (uf->last_pct_idx < i)); 1311 mhd_assert ((uf->last_pct_idx == mhd_POST_INVALID_POS) || \ 1312 ((uf->name_idx + uf->name_len) < i)); 1313 if (0 != uf->value_idx) 1314 { 1315 /* Have 'name' and 'value' */ 1316 if (uf->last_pct_idx != mhd_POST_INVALID_POS) 1317 uf->value_len = mhd_str_pct_decode_lenient_n (buf + uf->value_idx, 1318 i - uf->value_idx, 1319 buf + uf->value_idx, 1320 i - uf->value_idx, 1321 NULL); 1322 else 1323 uf->value_len = i - uf->value_idx; 1324 buf[uf->value_idx + uf->value_len] = 0; /* Zero-terminate the value */ 1325 } 1326 else 1327 { 1328 /* Have 'name' only (without any 'value') */ 1329 if (uf->last_pct_idx != mhd_POST_INVALID_POS) 1330 uf->name_len = mhd_str_pct_decode_lenient_n (buf + uf->name_idx, 1331 i - uf->name_idx, 1332 buf + uf->name_idx, 1333 i - uf->name_idx, 1334 NULL); 1335 else 1336 uf->name_len = i - uf->name_idx; 1337 buf[uf->name_idx + uf->name_len] = 0; /* Zero-terminate the name */ 1338 } 1339 uf->st = mhd_POST_UENC_ST_FULL_FIELD_FOUND; 1340 mhd_FALLTHROUGH; 1341 /* Intentional fallthrough */ 1342 case mhd_POST_UENC_ST_FULL_FIELD_FOUND: 1343 ++i; /* Consume current character, 1344 advance to the next char to be checked */ 1345 if (process_complete_field (c, 1346 buf, 1347 &i, 1348 pdata_size, 1349 p_data->field_start, 1350 uf->name_idx, 1351 uf->name_len, 1352 uf->value_idx, 1353 uf->value_len)) 1354 { 1355 if (c->suspended) 1356 --i; /* Go back to the same position */ 1357 else 1358 reset_parse_field_data_urlenc (p_data); 1359 p_data->next_parse_pos = i; 1360 return true; 1361 } 1362 mhd_assert (*pdata_size >= i); 1363 reset_parse_field_data_urlenc (p_data); 1364 continue; /* Process the next char */ 1365 default: 1366 mhd_UNREACHABLE (); 1367 break; 1368 } 1369 mhd_assert (0 && "Should be unreachable"); 1370 mhd_UNREACHABLE (); 1371 break; 1372 } 1373 1374 mhd_assert (*pdata_size == i); 1375 1376 mhd_assert (mhd_POST_UENC_ST_AT_EQ != uf->st); 1377 mhd_assert (mhd_POST_UENC_ST_AT_AMPRSND != uf->st); 1378 mhd_assert (mhd_POST_UENC_ST_FULL_FIELD_FOUND != uf->st); 1379 mhd_assert ((mhd_POST_UENC_ST_VALUE != uf->st) || \ 1380 (0 == uf->value_len)); 1381 1382 mhd_assert (*pdata_size == i); 1383 1384 if ((mhd_POST_UENC_ST_VALUE == uf->st) && 1385 (i != uf->value_idx) && /* Encoded value position must be larger then zero */ 1386 is_value_streaming_needed (c, i - p_data->field_start)) 1387 { 1388 size_t len_of_value_part; 1389 if (uf->last_pct_idx != mhd_POST_INVALID_POS) 1390 { 1391 mhd_assert (uf->last_pct_idx < i); 1392 mhd_assert (uf->last_pct_idx >= uf->value_idx); 1393 1394 if (2 >= (i - uf->last_pct_idx)) 1395 i = uf->last_pct_idx; /* The last percent-encoded character is incomplete */ 1396 1397 len_of_value_part = 1398 mhd_str_pct_decode_lenient_n (buf + uf->value_idx, 1399 i - uf->value_idx, 1400 buf + uf->value_idx, 1401 i - uf->value_idx, 1402 NULL); 1403 } 1404 else 1405 len_of_value_part = i - uf->value_idx; 1406 1407 if (0 != len_of_value_part) 1408 { 1409 bool proc_res; 1410 1411 proc_res = 1412 process_partial_value (c, 1413 buf, 1414 &i, 1415 pdata_size, 1416 uf->name_idx, 1417 uf->name_len, 1418 uf->value_idx, 1419 len_of_value_part); 1420 1421 /* Reset position of last '%' char: it was already decoded or 1422 * 'i' points to it and it will be processed again next time */ 1423 uf->last_pct_idx = mhd_POST_INVALID_POS; 1424 1425 if (proc_res) 1426 { 1427 if (c->suspended) 1428 uf->value_len = len_of_value_part; /* Indicate that value has been 1429 partially decoded and needs 1430 to be "streamed" again */ 1431 p_data->next_parse_pos = i; 1432 return true; 1433 } 1434 } 1435 } 1436 1437 p_data->next_parse_pos = i; 1438 return false; /* Continue parsing */ 1439 } 1440 1441 1442 /** 1443 * Parse "multipart/form-data" data 1444 * @param c the stream to use 1445 * @param pdata_size the pointer to variable holding the size of the data in 1446 * the @a buf 1447 * @param buf the buffer with the data 1448 * @return 'true' if stream state changed, 1449 * 'false' to continue parsing 1450 */ 1451 static MHD_FN_PAR_NONNULL_ALL_ 1452 MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (3) bool 1453 parse_post_mpart (struct MHD_Connection *restrict c, 1454 size_t *restrict pdata_size, 1455 char *restrict buf) 1456 { 1457 const int discp_lvl = c->daemon->req_cfg.strictness; 1458 const bool bare_lf_as_crlf = (-2 >= discp_lvl); /* Bare LF termination is dangerous when used in "multipart/form-data" */ 1459 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 1460 struct mhd_PostParserMPartFormData *const mf = &(p_data->e_d.m_form); /**< the current "form-data" parsing details */ 1461 size_t i; 1462 1463 mhd_assert (NULL != mf->delim.data); 1464 mhd_assert (4 < mf->delim.size); 1465 mhd_assert (0 == memcmp (mf->delim.data, "\r\n--", 4)); 1466 mhd_assert (NULL == memchr (mf->delim.data + 4, '\r', mf->delim.size - 4)); 1467 mhd_assert (NULL == memchr (mf->delim.data + 4, '\n', mf->delim.size - 4)); 1468 mhd_assert (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == \ 1469 c->rq.u_proc.post.enc); 1470 mhd_assert (MHD_POST_PARSE_RES_OK == p_data->parse_result); 1471 mhd_assert (mhd_POST_MPART_ST_FORMAT_ERROR != mf->st); 1472 mhd_assert (! c->discard_request); 1473 mhd_assert (p_data->next_parse_pos < *pdata_size); 1474 1475 i = p_data->next_parse_pos; 1476 while (*pdata_size > i) 1477 { 1478 switch (mf->st) 1479 { 1480 case mhd_POST_MPART_ST_BACK_TO_PREAMBL: 1481 mhd_assert (mhd_POST_INVALID_POS != mf->delim_check_start); 1482 mf->line_start = mhd_POST_INVALID_POS; 1483 mf->st = mhd_POST_MPART_ST_PREAMBL; 1484 mhd_FALLTHROUGH; 1485 /* Intentional fallthrough */ 1486 case mhd_POST_MPART_ST_PREAMBL: 1487 mhd_assert (0 == p_data->value_off); 1488 mhd_assert (mhd_POST_INVALID_POS == mf->delim_check_start); 1489 mhd_assert (mhd_POST_INVALID_POS == mf->line_start); 1490 #ifdef HAVE_MEMMEM 1491 if (mf->delim.size <= *pdata_size - i) 1492 { 1493 const char *delim_ptr; 1494 if (! bare_lf_as_crlf) 1495 delim_ptr = (const char *) memmem (buf + i, 1496 *pdata_size - i, 1497 mf->delim.data, 1498 mf->delim.size); 1499 else 1500 delim_ptr = (const char *) memmem (buf + i, 1501 *pdata_size - i, 1502 mf->delim.data + 1, 1503 mf->delim.size - 1); 1504 if (NULL != delim_ptr) 1505 { 1506 size_t delim_pos; 1507 1508 mhd_assert (delim_ptr >= buf + i); 1509 mhd_assert (delim_ptr + mf->delim.size - 1 <= buf + *pdata_size); 1510 1511 delim_pos = (size_t) (delim_ptr - buf); 1512 1513 mhd_assert (i <= delim_pos); 1514 1515 if (! bare_lf_as_crlf) 1516 { 1517 mf->line_start = delim_pos + 2u; /* '2' for CRLF */ 1518 i = delim_pos + mf->delim.size; 1519 } 1520 else 1521 { 1522 mf->line_start = delim_pos + 1u; /* '1' for LF */ 1523 i = delim_pos + mf->delim.size - 1; 1524 } 1525 mf->st = mhd_POST_MPART_ST_FIRST_DELIM_FOUND; 1526 continue; 1527 } 1528 i = *pdata_size - mf->delim.size + 1u; /* '+ 1u' to move to then next position */ 1529 if (! bare_lf_as_crlf) 1530 i += 1u; 1531 } 1532 #endif /* HAVE_MEMMEM */ 1533 do /* Fast local loop */ 1534 { 1535 #ifndef MHD_FAVOR_SMALL_CODE 1536 const char *lf_ptr; 1537 size_t lf_pos; 1538 1539 lf_ptr = (const char *) memchr (buf + i, '\n', *pdata_size - i); 1540 if (NULL == lf_ptr) 1541 { 1542 if ('\r' == buf[*pdata_size - 1]) 1543 mf->st = mhd_POST_MPART_ST_PREAMBL_CR_FOUND; 1544 i = *pdata_size; 1545 break; 1546 } 1547 lf_pos = (size_t) (lf_ptr - buf); 1548 mhd_assert (i <= lf_pos); 1549 mhd_assert (*pdata_size > i); 1550 if (bare_lf_as_crlf) 1551 { 1552 i = lf_pos + 1; 1553 mf->st = mhd_POST_MPART_ST_PREAMBL_LINE_START; 1554 break; 1555 } 1556 else if ((i < lf_pos) && 1557 ('\r' == buf[lf_pos - 1])) 1558 { 1559 i = lf_pos + 1; 1560 mf->st = mhd_POST_MPART_ST_PREAMBL_LINE_START; 1561 break; 1562 } 1563 i = lf_pos; 1564 #else /* MHD_FAVOR_SMALL_CODE */ 1565 if ('\r' == buf[i]) 1566 { 1567 mf->st = mhd_POST_MPART_ST_PREAMBL_CR_FOUND; 1568 ++i; /* Go to the next char */ 1569 break; 1570 } 1571 else if ('\n' == buf[i] && bare_lf_as_crlf) 1572 { 1573 mf->st = mhd_POST_MPART_ST_PREAMBL_LINE_START; 1574 ++i; /* Go to the next char */ 1575 break; 1576 } 1577 #endif /* MHD_FAVOR_SMALL_CODE */ 1578 } while (*pdata_size > ++i); 1579 mhd_assert ((*pdata_size == i) || \ 1580 (mhd_POST_MPART_ST_PREAMBL_CR_FOUND == mf->st) || \ 1581 (mhd_POST_MPART_ST_PREAMBL_LINE_START == mf->st) ); 1582 continue; 1583 case mhd_POST_MPART_ST_PREAMBL_CR_FOUND: 1584 mhd_assert (mhd_POST_INVALID_POS != mf->delim_check_start); 1585 mhd_assert (mhd_POST_INVALID_POS == mf->line_start); 1586 if ('\n' == buf[i]) 1587 { 1588 mf->st = mhd_POST_MPART_ST_PREAMBL_LINE_START; 1589 ++i; 1590 } 1591 else 1592 mf->st = mhd_POST_MPART_ST_PREAMBL; 1593 continue; 1594 case mhd_POST_MPART_ST_NOT_STARTED: 1595 mhd_assert (0 == p_data->field_start); 1596 mhd_assert (0 == p_data->value_off); 1597 mf->delim_check_start = mhd_POST_INVALID_POS; /* Ignored for first delimiter */ 1598 p_data->field_start = i; 1599 mhd_FALLTHROUGH; 1600 /* Intentional fallthrough */ 1601 case mhd_POST_MPART_ST_PREAMBL_LINE_START: 1602 mhd_assert (mhd_POST_INVALID_POS == mf->delim_check_start); 1603 mhd_assert (mhd_POST_INVALID_POS == mf->line_start); 1604 mf->line_start = i; 1605 #ifndef MHD_FAVOR_SMALL_CODE 1606 if (*pdata_size - i >= mf->delim.size - 2) /* Exclude CRLF prefix for the first delimiter */ 1607 { /* Exclude CRLF prefix for the first delimiter */ 1608 if (0 == memcmp (buf + i, mf->delim.data + 2, mf->delim.size - 2)) 1609 { 1610 mf->st = mhd_POST_MPART_ST_FIRST_DELIM_FOUND; 1611 i += mf->delim.size - 2; 1612 } 1613 else 1614 mf->st = mhd_POST_MPART_ST_BACK_TO_PREAMBL; 1615 continue; 1616 } 1617 #endif /* ! MHD_FAVOR_SMALL_CODE */ 1618 mf->st = mhd_POST_MPART_ST_PREAMBL_CHECKING_FOR_DELIM; 1619 mhd_FALLTHROUGH; 1620 /* Intentional fallthrough */ 1621 case mhd_POST_MPART_ST_PREAMBL_CHECKING_FOR_DELIM: 1622 mhd_assert (mhd_POST_INVALID_POS == mf->delim_check_start); /* Ignored for first delimiter */ 1623 mhd_assert (i >= mf->line_start); 1624 mhd_assert (*pdata_size >= mf->line_start); 1625 mhd_assert (i < mf->line_start + (mf->delim.size - 2)); 1626 if (*pdata_size - mf->line_start >= (mf->delim.size - 2)) 1627 { 1628 /* Enough data for the delimiter */ 1629 if (0 == memcmp (buf + mf->line_start, 1630 mf->delim.data + 2, 1631 mf->delim.size - 2)) 1632 { 1633 mf->st = mhd_POST_MPART_ST_FIRST_DELIM_FOUND; 1634 i = mf->line_start + (mf->delim.size - 2); 1635 } 1636 else 1637 mf->st = mhd_POST_MPART_ST_BACK_TO_PREAMBL; 1638 } 1639 else 1640 { 1641 /* Not enough data for the delimiter */ 1642 if (0 == memcmp (buf + mf->line_start, 1643 mf->delim.data + 2, 1644 *pdata_size - mf->line_start)) 1645 i = *pdata_size; 1646 else 1647 mf->st = mhd_POST_MPART_ST_BACK_TO_PREAMBL; 1648 } 1649 mhd_assert ((*pdata_size == i) || \ 1650 (mhd_POST_MPART_ST_FIRST_DELIM_FOUND == mf->st) || \ 1651 (mhd_POST_MPART_ST_BACK_TO_PREAMBL == mf->st)); 1652 continue; 1653 case mhd_POST_MPART_ST_FIRST_DELIM_FOUND: 1654 mhd_assert (mhd_POST_INVALID_POS == mf->delim_check_start); /* Ignored for first delimiter */ 1655 mhd_assert (mhd_POST_INVALID_POS != mf->line_start); 1656 mhd_assert (i >= mf->line_start + mf->delim.size - 2); 1657 do /* Fast local loop */ 1658 { 1659 if ('\n' == buf[i]) 1660 { 1661 if (bare_lf_as_crlf || 1662 ('\r' == buf [i - 1])) 1663 { 1664 mf->st = mhd_POST_MPART_ST_FIRST_PART_START; 1665 ++i; 1666 } 1667 else 1668 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 1669 1670 break; 1671 } 1672 else if ('\r' == buf [i - 1]) 1673 { 1674 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 1675 break; 1676 } 1677 else if ((i == mf->line_start + (mf->delim.size - 2) + 1) && 1678 ('-' == buf [i - 1]) && 1679 ('-' == buf [i])) 1680 { 1681 mf->st = mhd_POST_MPART_ST_EPILOGUE; 1682 break; 1683 } 1684 } while (*pdata_size > ++i); 1685 mhd_assert ((*pdata_size == i) || \ 1686 (mhd_POST_MPART_ST_FIRST_PART_START == mf->st) || \ 1687 (mhd_POST_MPART_ST_FORMAT_ERROR == mf->st) || \ 1688 (mhd_POST_MPART_ST_EPILOGUE == mf->st)); 1689 continue; 1690 case mhd_POST_MPART_ST_FIRST_PART_START: 1691 mhd_assert (mhd_POST_INVALID_POS == mf->delim_check_start); /* Ignored for first delimiter */ 1692 mhd_assert (i > p_data->field_start); 1693 mhd_assert (*pdata_size > i); 1694 if ((c->rq.app_act.head_act.data.post_parse.max_nonstream_size < 1695 i - p_data->field_start) || 1696 (*pdata_size - i < i - p_data->field_start)) 1697 { 1698 /* Discard unused data */ 1699 memmove (buf + p_data->field_start, 1700 buf + i, 1701 *pdata_size - i); 1702 *pdata_size -= (i - p_data->field_start); 1703 i = p_data->field_start; 1704 } 1705 mf->delim_check_start = p_data->field_start; 1706 mhd_FALLTHROUGH; 1707 /* Intentional fallthrough */ 1708 case mhd_POST_MPART_ST_PART_START: 1709 mhd_assert (0 == mf->f.name_len); 1710 mhd_assert (0 == p_data->value_off); 1711 mhd_assert (mhd_POST_INVALID_POS != mf->delim_check_start); 1712 p_data->field_start = mf->delim_check_start; 1713 mf->delim_check_start = mhd_POST_INVALID_POS; 1714 mhd_FALLTHROUGH; 1715 /* Intentional fallthrough */ 1716 case mhd_POST_MPART_ST_HEADER_LINE_START: 1717 mf->line_start = i; 1718 mf->st = mhd_POST_MPART_ST_HEADER_LINE; 1719 mhd_FALLTHROUGH; 1720 /* Intentional fallthrough */ 1721 case mhd_POST_MPART_ST_HEADER_LINE: 1722 mhd_assert (i >= mf->line_start); 1723 mhd_assert (mhd_POST_INVALID_POS != mf->line_start); 1724 mhd_assert (mhd_POST_INVALID_POS != p_data->field_start); 1725 do /* Fast local loop */ 1726 { 1727 if ('\r' == buf[i]) 1728 { 1729 mf->st = mhd_POST_MPART_ST_HEADER_LINE_CR_FOUND; 1730 ++i; 1731 break; 1732 } 1733 else if ('\n' == buf[i]) 1734 { 1735 if (bare_lf_as_crlf) 1736 mf->st = mhd_POST_MPART_ST_HEADER_LINE_END; 1737 else 1738 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 1739 break; 1740 } 1741 else if (mf->line_start + (mf->delim.size - 2) == i + 1) 1742 { 1743 if (0 == memcmp (buf + mf->line_start, 1744 mf->delim.data + 2, 1745 mf->delim.size - 2)) 1746 { 1747 /* The delimiter before the end of the header */ 1748 if (2 > mf->line_start) 1749 mf->delim_check_start = mf->line_start; 1750 else if (! bare_lf_as_crlf) 1751 mf->delim_check_start = mf->line_start - 2; 1752 else 1753 mf->delim_check_start = mf->line_start - 1; /* Actually can be one char earlier */ 1754 mf->st = mhd_POST_MPART_ST_DELIM_FOUND; 1755 break; 1756 } 1757 } 1758 } while (*pdata_size > ++i); 1759 mhd_assert ((*pdata_size == i) || \ 1760 (mhd_POST_MPART_ST_HEADER_LINE_CR_FOUND == mf->st) || \ 1761 (mhd_POST_MPART_ST_HEADER_LINE_END == mf->st) || \ 1762 (mhd_POST_MPART_ST_DELIM_FOUND == mf->st) || \ 1763 (mhd_POST_MPART_ST_FORMAT_ERROR == mf->st) ); 1764 continue; 1765 case mhd_POST_MPART_ST_HEADER_LINE_CR_FOUND: 1766 if ('\n' != buf[i]) 1767 { 1768 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 1769 continue; 1770 } 1771 mf->st = mhd_POST_MPART_ST_HEADER_LINE_END; 1772 mhd_FALLTHROUGH; 1773 /* Intentional fallthrough */ 1774 case mhd_POST_MPART_ST_HEADER_LINE_END: 1775 mhd_assert (mhd_POST_INVALID_POS != p_data->field_start); 1776 mhd_assert (i >= mf->line_start); 1777 mhd_assert (mhd_POST_INVALID_POS != mf->line_start); 1778 if (1) 1779 { 1780 size_t line_len; 1781 if (i == mf->line_start) 1782 line_len = 0; 1783 else if ('\r' == buf[i - 1]) 1784 line_len = i - mf->line_start - 1; 1785 else 1786 line_len = i - mf->line_start; 1787 1788 if (0 == line_len) 1789 { 1790 ++i; 1791 mf->st = mhd_POST_MPART_ST_VALUE_START; 1792 continue; 1793 } 1794 else 1795 { 1796 static const struct MHD_String hdr = 1797 mhd_MSTR_INIT ("Content-Disposition:"); 1798 static const struct MHD_String tkn = mhd_MSTR_INIT ("form-data"); 1799 static const struct MHD_String n_par = mhd_MSTR_INIT ("name"); 1800 1801 if ((hdr.len + tkn.len + n_par.len + 2 <= line_len) && 1802 mhd_str_equal_caseless_bin_n (hdr.cstr, 1803 buf + mf->line_start, 1804 hdr.len)) 1805 { 1806 size_t hdr_val_start; 1807 struct MHD_String hdr_val; 1808 enum mhd_StingStartsWithTokenResult res; 1809 struct mhd_BufferConst name_buf; 1810 bool hdr_has_name; 1811 bool name_needs_unq; 1812 1813 buf [mf->line_start + line_len] = 0; /* Zero-terminate the header line */ 1814 hdr_val_start = mf->line_start + hdr.len; 1815 /* Skip all whitespace chars */ 1816 while ((' ' == buf[hdr_val_start]) || ('\t' == buf[hdr_val_start])) 1817 ++hdr_val_start; 1818 1819 mhd_assert (hdr_val_start <= i); 1820 1821 hdr_val.cstr = buf + hdr_val_start; 1822 hdr_val.len = mf->line_start + line_len - hdr_val_start; 1823 1824 res = mhd_str_starts_with_token_req_param (&hdr_val, 1825 &tkn, 1826 &n_par, 1827 &name_buf, 1828 &name_needs_unq); 1829 if (mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT == res) 1830 { 1831 /* Found two names for one field */ 1832 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 1833 continue; 1834 } 1835 else if (mhd_STR_STARTS_W_TOKEN_HAS_TOKEN == res) 1836 { 1837 static const struct MHD_String fn_par = 1838 mhd_MSTR_INIT ("filename"); 1839 struct mhd_BufferConst fname_buf; 1840 bool fname_needs_unq; 1841 1842 if (NULL != name_buf.data) 1843 { 1844 mhd_assert (buf < name_buf.data); 1845 if (0 != mf->f.name_idx) 1846 { 1847 /* Found two names for one field */ 1848 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 1849 continue; 1850 } 1851 mf->f.name_idx = (size_t) (name_buf.data - buf); 1852 mf->f.name_len = name_buf.size; 1853 hdr_has_name = true; 1854 1855 /* Do not process (unquote, url-decode, zero-terminate) here yet 1856 * as it may break the header format */ 1857 } 1858 else 1859 hdr_has_name = false; 1860 1861 res = mhd_str_starts_with_token_req_param (&hdr_val, 1862 &tkn, 1863 &fn_par, 1864 &fname_buf, 1865 &fname_needs_unq); 1866 if (mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT == res) 1867 { 1868 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 1869 continue; 1870 } 1871 else if (mhd_STR_STARTS_W_TOKEN_HAS_TOKEN == res) 1872 { 1873 if (NULL != fname_buf.data) 1874 { 1875 mhd_assert (buf < fname_buf.data); 1876 if (0 != mf->f.filename_idx) 1877 { 1878 /* Found two filenames for one field */ 1879 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 1880 continue; 1881 } 1882 mf->f.filename_idx = (size_t) (fname_buf.data - buf); 1883 if (! fname_needs_unq) 1884 mf->f.filename_len = fname_buf.size; 1885 else 1886 { 1887 mf->f.filename_len = 1888 mhd_str_unquote (fname_buf.data, 1889 fname_buf.size, 1890 buf + mf->f.filename_idx); 1891 if ((0 == mf->f.filename_len) && (0 != fname_buf.size)) 1892 { 1893 mhd_assert (0 && "broken quoting must be detected " \ 1894 "earlier by " \ 1895 "mhd_str_starts_with_token_req_param()"); 1896 mhd_UNREACHABLE (); 1897 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 1898 continue; 1899 } 1900 } 1901 mhd_assert (mf->f.filename_idx + mf->f.filename_len <= i); 1902 mf->f.filename_len = 1903 mhd_str_pct_decode_lenient_n (buf + mf->f.filename_idx, 1904 mf->f.filename_len, 1905 buf + mf->f.filename_idx, 1906 mf->f.filename_len, 1907 NULL); 1908 mhd_assert (mf->f.filename_idx + mf->f.filename_len <= i); 1909 1910 buf[mf->f.filename_idx + mf->f.filename_len] = 0; /* Zero-terminate the filename */ 1911 } 1912 } 1913 else 1914 { 1915 mhd_assert (mhd_STR_STARTS_W_TOKEN_NO_TOKEN == res); 1916 mhd_assert (0 && "The presence of the token was " 1917 "checked earlier"); 1918 mhd_UNREACHABLE (); 1919 } 1920 1921 if (hdr_has_name) 1922 { 1923 if (name_needs_unq) 1924 { 1925 mf->f.name_len = mhd_str_unquote (buf + mf->f.name_idx, 1926 mf->f.name_len, 1927 buf + mf->f.name_idx); 1928 if ((0 == mf->f.name_len) && (0 != name_buf.size)) 1929 { 1930 mhd_assert (0 && "broken quoting must be detected " \ 1931 "earlier by " \ 1932 "mhd_str_starts_with_token_req_param()"); 1933 mhd_UNREACHABLE (); 1934 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 1935 continue; 1936 } 1937 } 1938 mhd_assert (mf->f.name_idx + mf->f.name_len <= i); 1939 mf->f.name_len = 1940 mhd_str_pct_decode_lenient_n (buf + mf->f.name_idx, 1941 mf->f.name_len, 1942 buf + mf->f.name_idx, 1943 mf->f.name_len, 1944 NULL); 1945 mhd_assert (mf->f.name_idx + mf->f.name_len <= i); 1946 1947 buf[mf->f.name_idx + mf->f.name_len] = 0; /* Zero-terminate the name */ 1948 } 1949 } 1950 } 1951 } 1952 } 1953 ++i; 1954 mf->st = mhd_POST_MPART_ST_HEADER_LINE_START; 1955 continue; 1956 case mhd_POST_MPART_ST_VALUE_START: 1957 mhd_assert (mhd_POST_INVALID_POS == mf->delim_check_start); 1958 mhd_assert (mhd_POST_INVALID_POS != p_data->field_start); 1959 mhd_assert (0 == p_data->value_off); 1960 mhd_assert (0 == mf->f.value_idx); 1961 mhd_assert (0 == mf->f.value_len); 1962 mhd_assert (0 != i && "the 'value' should follow the 'name'"); 1963 if (0 == mf->f.name_idx) 1964 { 1965 mhd_LOG_MSG (c->daemon, \ 1966 p_data->some_data_provided ? \ 1967 MHD_SC_REQ_POST_PARSE_PARTIAL_INVALID_POST_FORMAT : \ 1968 MHD_SC_REQ_POST_PARSE_FAILED_INVALID_POST_FORMAT, \ 1969 "The request 'multipart/form-data' POST field has no " \ 1970 "name of the field."); 1971 p_data->parse_result = 1972 p_data->some_data_provided ? 1973 MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT : 1974 MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT; 1975 c->stage = mhd_HTTP_STAGE_FULL_REQ_RECEIVED; 1976 return true; /* Stop parsing the upload */ 1977 } 1978 mhd_assert (0 != mf->f.name_len); 1979 mhd_assert (i > mf->f.name_idx); 1980 mf->f.value_idx = i; 1981 mhd_FALLTHROUGH; 1982 /* Intentional fallthrough */ 1983 case mhd_POST_MPART_ST_BACK_TO_VALUE: 1984 mhd_assert (mhd_POST_INVALID_POS != p_data->field_start); 1985 mf->line_start = mhd_POST_INVALID_POS; 1986 mf->delim_check_start = mhd_POST_INVALID_POS; 1987 mf->st = mhd_POST_MPART_ST_VALUE; 1988 mhd_FALLTHROUGH; 1989 /* Intentional fallthrough */ 1990 case mhd_POST_MPART_ST_VALUE: 1991 mhd_assert (mhd_POST_INVALID_POS == mf->delim_check_start); 1992 mhd_assert (mhd_POST_INVALID_POS == mf->line_start); 1993 mhd_assert (mhd_POST_INVALID_POS != p_data->field_start); 1994 #ifdef HAVE_MEMMEM 1995 if (mf->delim.size <= *pdata_size - i) 1996 { 1997 const char *delim_ptr; 1998 if (! bare_lf_as_crlf) 1999 delim_ptr = (const char *) memmem (buf + i, 2000 *pdata_size - i, 2001 mf->delim.data, 2002 mf->delim.size); 2003 else 2004 delim_ptr = (const char *) memmem (buf + i, 2005 *pdata_size - i, 2006 mf->delim.data + 1, 2007 mf->delim.size - 1); 2008 if (NULL != delim_ptr) 2009 { 2010 size_t delim_pos; 2011 2012 mhd_assert (delim_ptr >= buf + i); 2013 mhd_assert (delim_ptr + mf->delim.size - 1 <= buf + *pdata_size); 2014 2015 delim_pos = (size_t) (delim_ptr - buf); 2016 2017 mhd_assert (i <= delim_pos); 2018 2019 if (! bare_lf_as_crlf) 2020 { 2021 mf->line_start = delim_pos + 2; 2022 i = delim_pos + mf->delim.size; 2023 } 2024 else 2025 { 2026 mf->line_start = delim_pos + 1; 2027 i = delim_pos + mf->delim.size - 1; 2028 if ((delim_pos > i) && 2029 ('\r' == buf[delim_pos - 1])) 2030 --delim_pos; 2031 } 2032 mf->delim_check_start = delim_pos; 2033 mf->st = mhd_POST_MPART_ST_DELIM_FOUND; 2034 continue; 2035 } 2036 i = *pdata_size - mf->delim.size + 1u; /* '+ 1u' to move to then next position */ 2037 if (! bare_lf_as_crlf) 2038 i += 1u; 2039 } 2040 #endif /* HAVE_MEMMEM */ 2041 do /* Fast local loop */ 2042 { 2043 #ifndef MHD_FAVOR_SMALL_CODE 2044 const char *lf_ptr; 2045 size_t lf_pos; 2046 2047 lf_ptr = (const char *) memchr (buf + i, '\n', *pdata_size - i); 2048 if (NULL == lf_ptr) 2049 { 2050 if ('\r' == buf[*pdata_size - 1]) 2051 mf->st = mhd_POST_MPART_ST_VALUE_CR_FOUND; 2052 i = *pdata_size; 2053 break; 2054 } 2055 lf_pos = (size_t) (lf_ptr - buf); 2056 mhd_assert (i <= lf_pos); 2057 mhd_assert (*pdata_size > i); 2058 if ((i < lf_pos) && 2059 ('\r' == buf[lf_pos - 1])) 2060 { 2061 mf->delim_check_start = lf_pos - 1; 2062 mf->st = mhd_POST_MPART_ST_VALUE_LINE_START; 2063 i = lf_pos + 1; 2064 break; 2065 } 2066 else if (bare_lf_as_crlf) 2067 { 2068 mf->delim_check_start = lf_pos; 2069 mf->st = mhd_POST_MPART_ST_VALUE_LINE_START; 2070 i = lf_pos + 1; 2071 break; 2072 } 2073 i = lf_pos; 2074 #else /* MHD_FAVOR_SMALL_CODE */ 2075 if ('\r' == buf[i]) 2076 { 2077 mf->delim_check_start = i; 2078 mf->st = mhd_POST_MPART_ST_VALUE_CR_FOUND; 2079 ++i; 2080 break; 2081 } 2082 else if (bare_lf_as_crlf && '\n' == buf[i]) 2083 { 2084 mf->delim_check_start = i; 2085 mf->st = mhd_POST_MPART_ST_VALUE_LINE_START; 2086 ++i; 2087 break; 2088 } 2089 #endif /* MHD_FAVOR_SMALL_CODE */ 2090 } while (*pdata_size > ++i); 2091 mhd_assert ((*pdata_size == i) || \ 2092 (mhd_POST_MPART_ST_VALUE_CR_FOUND == mf->st) || \ 2093 (mhd_POST_MPART_ST_VALUE_LINE_START == mf->st)); 2094 continue; 2095 case mhd_POST_MPART_ST_VALUE_CR_FOUND: 2096 if ('\n' != buf[i]) 2097 { 2098 mf->st = mhd_POST_MPART_ST_BACK_TO_VALUE; 2099 continue; 2100 } 2101 mf->st = mhd_POST_MPART_ST_VALUE_LINE_START; 2102 ++i; 2103 continue; 2104 case mhd_POST_MPART_ST_VALUE_LINE_START: 2105 mhd_assert (mhd_POST_INVALID_POS != mf->delim_check_start); 2106 mhd_assert (mhd_POST_INVALID_POS != p_data->field_start); 2107 mf->line_start = i; 2108 #ifndef MHD_FAVOR_SMALL_CODE 2109 if (*pdata_size - i >= mf->delim.size - 2) 2110 { 2111 if (0 == memcmp (buf + i, mf->delim.data + 2, mf->delim.size - 2)) 2112 { 2113 mf->st = mhd_POST_MPART_ST_DELIM_FOUND; 2114 i += mf->delim.size - 2; 2115 } 2116 else 2117 mf->st = mhd_POST_MPART_ST_BACK_TO_VALUE; 2118 continue; 2119 } 2120 #endif /* ! MHD_FAVOR_SMALL_CODE */ 2121 mf->st = mhd_POST_MPART_ST_VALUE_CHECKING_FOR_DELIM; 2122 mhd_FALLTHROUGH; 2123 /* Intentional fallthrough */ 2124 case mhd_POST_MPART_ST_VALUE_CHECKING_FOR_DELIM: 2125 mhd_assert (mhd_POST_INVALID_POS != p_data->field_start); 2126 mhd_assert (i >= mf->line_start); 2127 mhd_assert (*pdata_size >= mf->line_start); 2128 mhd_assert (i < mf->line_start + (mf->delim.size - 2)); 2129 if (*pdata_size - mf->line_start >= (mf->delim.size - 2)) 2130 { 2131 /* Enough data for the delimiter */ 2132 if (0 == memcmp (buf + mf->line_start, 2133 mf->delim.data + 2, 2134 mf->delim.size - 2)) 2135 { 2136 mf->st = mhd_POST_MPART_ST_DELIM_FOUND; 2137 i = mf->line_start + (mf->delim.size - 2); 2138 } 2139 else 2140 mf->st = mhd_POST_MPART_ST_BACK_TO_VALUE; 2141 } 2142 else 2143 { 2144 /* Not enough data for the delimiter */ 2145 if (0 == memcmp (buf + mf->line_start, 2146 mf->delim.data + 2, 2147 *pdata_size - mf->line_start)) 2148 i = *pdata_size; 2149 else 2150 mf->st = mhd_POST_MPART_ST_BACK_TO_VALUE; 2151 } 2152 mhd_assert ((*pdata_size == i) || \ 2153 (mhd_POST_MPART_ST_DELIM_FOUND == mf->st) || \ 2154 (mhd_POST_MPART_ST_BACK_TO_VALUE == mf->st)); 2155 continue; 2156 case mhd_POST_MPART_ST_DELIM_FOUND: 2157 mhd_assert (mhd_POST_INVALID_POS != mf->delim_check_start); 2158 mhd_assert (mhd_POST_INVALID_POS != mf->line_start); 2159 mhd_assert (mhd_POST_INVALID_POS != p_data->field_start); 2160 mhd_assert (i >= mf->line_start + mf->delim.size - 2); 2161 do /* Fast local loop */ 2162 { 2163 if ('\n' == buf[i]) 2164 { 2165 if (bare_lf_as_crlf || 2166 ('\r' == buf [i - 1])) 2167 mf->st = mhd_POST_MPART_ST_VALUE_END_FOUND; 2168 else 2169 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 2170 2171 break; 2172 } 2173 else if ('\r' == buf [i - 1]) 2174 { 2175 mf->st = mhd_POST_MPART_ST_FORMAT_ERROR; 2176 break; 2177 } 2178 else if ((i == mf->line_start + (mf->delim.size - 2) + 1) && 2179 ('-' == buf [i - 1]) && 2180 ('-' == buf [i])) 2181 { 2182 mf->st = mhd_POST_MPART_ST_VALUE_END_FOUND_FINAL; 2183 break; 2184 } 2185 } while (*pdata_size > ++i); 2186 mhd_assert ((*pdata_size == i) || \ 2187 (mhd_POST_MPART_ST_VALUE_END_FOUND == mf->st) || \ 2188 (mhd_POST_MPART_ST_VALUE_END_FOUND_FINAL == mf->st) || \ 2189 (mhd_POST_MPART_ST_FORMAT_ERROR == mf->st)); 2190 continue; 2191 case mhd_POST_MPART_ST_VALUE_END_FOUND: 2192 case mhd_POST_MPART_ST_VALUE_END_FOUND_FINAL: 2193 mhd_assert (mhd_POST_INVALID_POS != mf->delim_check_start); 2194 mhd_assert (mhd_POST_INVALID_POS != p_data->field_start); 2195 mhd_assert (mf->f.value_idx <= mf->delim_check_start); 2196 mhd_assert (0 == mf->f.value_len); 2197 mhd_assert (0 != mf->f.name_len); 2198 mhd_assert (i > mf->f.name_idx); 2199 mhd_assert (i > mf->delim_check_start); 2200 if (0 != mf->f.value_idx) 2201 { 2202 mf->f.value_len = mf->delim_check_start - mf->f.value_idx; 2203 buf[mf->f.value_idx + mf->f.value_len] = 0; /* Zero-terminate the value */ 2204 ++mf->delim_check_start; /* Shift start of the delimiter to add space for zero-termination */ 2205 } 2206 if (mhd_POST_MPART_ST_VALUE_END_FOUND == mf->st) 2207 mf->st = mhd_POST_MPART_ST_FULL_FIELD_FOUND; 2208 else 2209 mf->st = mhd_POST_MPART_ST_FULL_FIELD_FOUND_FINAL; 2210 mhd_FALLTHROUGH; 2211 /* Intentional fallthrough */ 2212 case mhd_POST_MPART_ST_FULL_FIELD_FOUND: 2213 case mhd_POST_MPART_ST_FULL_FIELD_FOUND_FINAL: 2214 mhd_assert (mhd_POST_INVALID_POS != mf->delim_check_start); 2215 mhd_assert (mhd_POST_INVALID_POS != p_data->field_start); 2216 if (1) 2217 { 2218 size_t new_delim_check_start; 2219 bool state_changed; 2220 2221 ++i; /* Consume current character */ 2222 new_delim_check_start = mf->delim_check_start; 2223 state_changed = 2224 process_complete_field_all (c, 2225 buf, 2226 &new_delim_check_start, 2227 pdata_size, 2228 p_data->field_start, 2229 mf->f.name_idx, 2230 mf->f.name_len, 2231 mf->f.filename_idx, 2232 mf->f.filename_len, 2233 mf->f.cntn_type_idx, 2234 mf->f.cntn_type_len, 2235 mf->f.enc_idx, 2236 mf->f.enc_len, 2237 mf->f.value_idx, 2238 mf->f.value_len); 2239 if (c->suspended) 2240 { 2241 mhd_assert (mf->delim_check_start == new_delim_check_start); 2242 mhd_assert (state_changed); 2243 p_data->next_parse_pos = --i; /* Restore position */ 2244 return true; 2245 } 2246 2247 if (mf->delim_check_start != new_delim_check_start) 2248 { 2249 size_t shift_size; 2250 mhd_assert (mf->delim_check_start > new_delim_check_start); 2251 2252 shift_size = mf->delim_check_start - new_delim_check_start; 2253 mf->delim_check_start = new_delim_check_start; 2254 i -= shift_size; 2255 } 2256 2257 mhd_assert (*pdata_size >= i); 2258 2259 reset_parse_field_data_mpart_cont ( 2260 p_data, 2261 mhd_POST_MPART_ST_FULL_FIELD_FOUND_FINAL == mf->st); 2262 2263 if (state_changed) 2264 { 2265 p_data->next_parse_pos = i; 2266 return true; 2267 } 2268 } 2269 continue; /* Process the next char */ 2270 case mhd_POST_MPART_ST_EPILOGUE: 2271 /* Discard the rest of the content data */ 2272 *pdata_size = i; 2273 p_data->next_parse_pos = i; 2274 return false; 2275 case mhd_POST_MPART_ST_FORMAT_ERROR: 2276 if (p_data->some_data_provided) 2277 { 2278 mhd_LOG_MSG (c->daemon, \ 2279 MHD_SC_REQ_POST_PARSE_PARTIAL_INVALID_POST_FORMAT, \ 2280 "The request POST has broken encoding or format and " \ 2281 "was parsed only partially."); 2282 p_data->parse_result = 2283 MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT; 2284 } 2285 else 2286 { 2287 mhd_LOG_MSG (c->daemon, \ 2288 MHD_SC_REQ_POST_PARSE_FAILED_INVALID_POST_FORMAT, \ 2289 "The request POST has broken encoding or format and " \ 2290 "cannot be parsed."); 2291 p_data->parse_result = 2292 MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT; 2293 } 2294 c->stage = mhd_HTTP_STAGE_FULL_REQ_RECEIVED; 2295 return true; 2296 default: 2297 mhd_UNREACHABLE (); 2298 break; 2299 } 2300 mhd_assert (0 && "Should be unreachable"); 2301 mhd_UNREACHABLE (); 2302 break; 2303 } 2304 2305 mhd_assert (*pdata_size == i); 2306 2307 mhd_assert (mhd_POST_MPART_ST_NOT_STARTED != mf->st); 2308 mhd_assert (mhd_POST_MPART_ST_BACK_TO_PREAMBL != mf->st); 2309 mhd_assert (mhd_POST_MPART_ST_PREAMBL_LINE_START != mf->st); 2310 mhd_assert (mhd_POST_MPART_ST_HEADER_LINE_END != mf->st); 2311 mhd_assert (mhd_POST_MPART_ST_BACK_TO_VALUE != mf->st); 2312 mhd_assert (mhd_POST_MPART_ST_VALUE_END_FOUND != mf->st); 2313 mhd_assert (mhd_POST_MPART_ST_VALUE_END_FOUND_FINAL != mf->st); 2314 mhd_assert ((mhd_POST_MPART_ST_VALUE != mf->st) || \ 2315 (0 == mf->f.value_len)); 2316 2317 mhd_assert (*pdata_size == i); 2318 2319 if ((0 != mf->f.value_idx) && 2320 (((mhd_POST_MPART_ST_VALUE == mf->st) && 2321 (i != mf->f.value_idx) && 2322 is_value_streaming_needed (c, i - p_data->field_start)) || 2323 (((mhd_POST_MPART_ST_VALUE_CR_FOUND == mf->st) || 2324 (mhd_POST_MPART_ST_VALUE_LINE_START == mf->st) || 2325 (mhd_POST_MPART_ST_VALUE_CHECKING_FOR_DELIM == mf->st)) && 2326 (i != mf->delim_check_start) && 2327 is_value_streaming_needed (c, i - mf->delim_check_start)))) 2328 { 2329 bool proc_res; 2330 2331 mhd_assert ((mhd_POST_MPART_ST_VALUE == mf->st) || \ 2332 (i >= mf->delim_check_start)); 2333 mhd_assert ((mhd_POST_MPART_ST_VALUE == mf->st) || \ 2334 (mhd_POST_INVALID_POS != mf->delim_check_start)); 2335 if (mhd_POST_MPART_ST_VALUE != mf->st) 2336 { 2337 i = mf->delim_check_start; /* Reset position */ 2338 mf->st = mhd_POST_MPART_ST_BACK_TO_VALUE; 2339 } 2340 2341 proc_res = 2342 process_partial_value_all (c, 2343 buf, 2344 &i, 2345 pdata_size, 2346 mf->f.name_idx, 2347 mf->f.name_len, 2348 mf->f.filename_idx, 2349 mf->f.filename_len, 2350 mf->f.cntn_type_idx, 2351 mf->f.cntn_type_len, 2352 mf->f.enc_idx, 2353 mf->f.enc_len, 2354 mf->f.value_idx, 2355 i - mf->f.value_idx); 2356 2357 p_data->next_parse_pos = i; 2358 2359 return proc_res; 2360 } 2361 2362 p_data->next_parse_pos = i; 2363 return false; /* Continue parsing */ 2364 } 2365 2366 2367 static MHD_FN_PAR_NONNULL_ALL_ 2368 MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (3) bool 2369 parse_post_text (struct MHD_Connection *restrict c, 2370 size_t *restrict pdata_size, 2371 char *restrict buf) 2372 { 2373 const int discp_lvl = c->daemon->req_cfg.strictness; 2374 /* Treat bare LF as the end of the line. 2375 The same logic used here as for parsing HTTP headers. 2376 Bare LF is processed as the end of the line or rejected as broken 2377 request. */ 2378 const bool bare_lf_as_crlf = mhd_ALLOW_BARE_LF_AS_CRLF (discp_lvl); 2379 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 2380 struct mhd_PostParserTextData *const tf = &(p_data->e_d.text); /**< the current "text" field */ 2381 size_t i; 2382 bool enc_broken; 2383 2384 mhd_assert (MHD_HTTP_POST_ENCODING_TEXT_PLAIN == c->rq.u_proc.post.enc); 2385 mhd_assert (MHD_POST_PARSE_RES_OK == p_data->parse_result); 2386 mhd_assert (! c->discard_request); 2387 mhd_assert (p_data->next_parse_pos < *pdata_size); 2388 2389 enc_broken = false; 2390 i = p_data->next_parse_pos; 2391 while (*pdata_size > i) 2392 { 2393 switch (tf->st) 2394 { 2395 case mhd_POST_TEXT_ST_NOT_STARTED: 2396 mhd_assert (0 == p_data->field_start); 2397 mhd_assert (0 == p_data->value_off); 2398 p_data->field_start = i; 2399 tf->name_idx = i; 2400 tf->st = mhd_POST_TEXT_ST_NAME; 2401 mhd_FALLTHROUGH; 2402 /* Intentional fallthrough */ 2403 case mhd_POST_TEXT_ST_NAME: 2404 do /* Fast local loop */ 2405 { 2406 if ('=' == buf[i]) 2407 { 2408 tf->st = mhd_POST_TEXT_ST_AT_EQ; 2409 break; 2410 } 2411 else if ('\r' == buf[i]) 2412 { 2413 tf->st = mhd_POST_TEXT_ST_AT_CR; 2414 break; 2415 } 2416 else if ('\n' == buf[i]) 2417 { 2418 tf->st = mhd_POST_TEXT_ST_AT_LF_BARE; 2419 break; 2420 } 2421 } while (*pdata_size > ++i); 2422 mhd_assert ((*pdata_size == i) || \ 2423 (mhd_POST_TEXT_ST_NAME != tf->st)); 2424 continue; 2425 case mhd_POST_TEXT_ST_AT_EQ: 2426 mhd_assert (i > tf->name_idx); 2427 mhd_assert (0 == tf->name_len); 2428 mhd_assert (0 == tf->value_len); 2429 buf[i] = 0; /* Zero-terminate the name */ 2430 tf->name_len = i - tf->name_idx; 2431 tf->st = mhd_POST_TEXT_ST_EQ_FOUND; 2432 ++i; /* Process the next char */ 2433 continue; 2434 case mhd_POST_TEXT_ST_EQ_FOUND: 2435 mhd_assert (0 == p_data->value_off); 2436 mhd_assert (0 == tf->value_idx); 2437 mhd_assert (0 == tf->value_len); 2438 mhd_assert (0 != i && "the 'value' should follow the 'name'"); 2439 tf->value_idx = i; 2440 tf->st = mhd_POST_TEXT_ST_VALUE; 2441 mhd_FALLTHROUGH; 2442 /* Intentional fallthrough */ 2443 case mhd_POST_TEXT_ST_VALUE: 2444 do /* Fast local loop */ 2445 { 2446 if ('\r' == buf[i]) 2447 { 2448 tf->st = mhd_POST_TEXT_ST_AT_CR; 2449 break; 2450 } 2451 else if ('\n' == buf[i]) 2452 { 2453 tf->st = mhd_POST_TEXT_ST_AT_LF_BARE; 2454 break; 2455 } 2456 } while (*pdata_size > ++i); 2457 mhd_assert ((*pdata_size == i) || \ 2458 (mhd_POST_TEXT_ST_AT_CR == tf->st) || \ 2459 (mhd_POST_TEXT_ST_AT_LF_BARE == tf->st)); 2460 continue; 2461 case mhd_POST_TEXT_ST_AT_LF_BARE: 2462 if (! bare_lf_as_crlf) 2463 { 2464 enc_broken = true; 2465 break; 2466 } 2467 mhd_FALLTHROUGH; 2468 /* Intentional fallthrough */ 2469 case mhd_POST_TEXT_ST_AT_CR: 2470 mhd_assert (0 == tf->value_len); 2471 buf[i] = 0; /* Zero-terminate the value (or the name) */ 2472 if (0 != tf->value_idx) 2473 tf->value_len = i - tf->value_idx; 2474 else 2475 tf->name_len = i - tf->name_idx; 2476 if ((0 == tf->name_len) && (0 == tf->value_len)) 2477 { /* Empty line */ 2478 ++i; /* Advance to the next char to be checked */ 2479 reset_parse_field_data_text (p_data); 2480 tf->st = mhd_POST_TEXT_ST_NOT_STARTED; 2481 } 2482 else if (mhd_POST_TEXT_ST_AT_LF_BARE == tf->st) 2483 tf->st = mhd_POST_TEXT_ST_FULL_LINE_FOUND; 2484 else 2485 { 2486 tf->st = mhd_POST_TEXT_ST_CR_FOUND; 2487 ++i; /* Process the next char */ 2488 } 2489 continue; 2490 case mhd_POST_TEXT_ST_CR_FOUND: 2491 if ('\n' != buf[i]) 2492 { 2493 enc_broken = true; 2494 break; 2495 } 2496 tf->st = mhd_POST_TEXT_ST_FULL_LINE_FOUND; 2497 mhd_FALLTHROUGH; 2498 /* Intentional fallthrough */ 2499 case mhd_POST_TEXT_ST_FULL_LINE_FOUND: 2500 ++i; /* Advance to the next char to be checked */ 2501 if (process_complete_field (c, 2502 buf, 2503 &i, 2504 pdata_size, 2505 p_data->field_start, 2506 tf->name_idx, 2507 tf->name_len, 2508 tf->value_idx, 2509 tf->value_len)) 2510 { 2511 if (c->suspended) 2512 --i; /* Go back to the same position */ 2513 else 2514 reset_parse_field_data_text (p_data); 2515 p_data->next_parse_pos = i; 2516 return true; 2517 } 2518 mhd_assert (*pdata_size >= i); 2519 reset_parse_field_data_text (p_data); 2520 continue; /* Process the next char */ 2521 default: 2522 mhd_UNREACHABLE (); 2523 enc_broken = true; 2524 break; 2525 } 2526 mhd_assert (enc_broken); 2527 break; 2528 } 2529 2530 mhd_assert ((*pdata_size == i) || enc_broken); 2531 2532 if (enc_broken) 2533 { 2534 if (p_data->some_data_provided) 2535 { 2536 mhd_LOG_MSG (c->daemon, \ 2537 MHD_SC_REQ_POST_PARSE_PARTIAL_INVALID_POST_FORMAT, \ 2538 "The request POST has broken encoding or format and " \ 2539 "was parsed only partially."); 2540 p_data->parse_result = 2541 MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT; 2542 } 2543 else 2544 { 2545 mhd_LOG_MSG (c->daemon, \ 2546 MHD_SC_REQ_POST_PARSE_FAILED_INVALID_POST_FORMAT, \ 2547 "The request POST has broken encoding or format and " \ 2548 "cannot be parsed."); 2549 p_data->parse_result = 2550 MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT; 2551 } 2552 tf->st = mhd_POST_TEXT_ST_NOT_STARTED; 2553 c->stage = mhd_HTTP_STAGE_FULL_REQ_RECEIVED; 2554 return true; 2555 } 2556 2557 mhd_assert (mhd_POST_TEXT_ST_AT_EQ != tf->st); 2558 mhd_assert (mhd_POST_TEXT_ST_AT_CR != tf->st); 2559 mhd_assert (mhd_POST_TEXT_ST_AT_LF_BARE != tf->st); 2560 mhd_assert (mhd_POST_TEXT_ST_FULL_LINE_FOUND != tf->st); 2561 2562 mhd_assert (*pdata_size == i); 2563 2564 if ((mhd_POST_TEXT_ST_VALUE == tf->st) && 2565 (i != tf->value_idx) && 2566 is_value_streaming_needed (c, i - p_data->field_start)) 2567 { 2568 if (process_partial_value (c, 2569 buf, 2570 &i, 2571 pdata_size, 2572 tf->name_idx, 2573 tf->name_len, 2574 tf->value_idx, 2575 i - tf->value_idx)) 2576 { 2577 p_data->next_parse_pos = i; 2578 return true; 2579 } 2580 } 2581 2582 p_data->next_parse_pos = i; 2583 return false; /* Continue parsing */ 2584 } 2585 2586 2587 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 2588 MHD_FN_PAR_INOUT_ (3) bool 2589 mhd_stream_post_parse (struct MHD_Connection *restrict c, 2590 size_t *restrict pdata_size, 2591 char *restrict buf) 2592 { 2593 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 2594 size_t lbuf_left; 2595 2596 mhd_assert (MHD_HTTP_POST_ENCODING_OTHER != p_data->enc); 2597 mhd_assert (c->rq.cntn.lbuf.size <= p_data->lbuf_limit); 2598 2599 if ((MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA == p_data->enc) && 2600 (mhd_POST_MPART_ST_EPILOGUE == p_data->e_d.m_form.st)) 2601 { 2602 /* No need to process the data */ 2603 *pdata_size = 0; /* All data has been "processed" */ 2604 return false; /* Continue normal processing */ 2605 } 2606 2607 // TODO: support process in the connection buffer 2608 2609 mhd_assert (c->rq.cntn.lbuf.size >= p_data->lbuf_used); 2610 lbuf_left = c->rq.cntn.lbuf.size - p_data->lbuf_used; 2611 2612 if (*pdata_size + 1 > lbuf_left) 2613 (void) extend_lbuf_up_to (c, 2614 *pdata_size + 1 - lbuf_left, 2615 &(c->rq.cntn.lbuf)); 2616 2617 while ((0 != *pdata_size) && 2618 (c->rq.cntn.lbuf.size > p_data->lbuf_used)) 2619 { 2620 size_t data_size_before_parse; 2621 size_t copy_size = *pdata_size; 2622 lbuf_left = c->rq.cntn.lbuf.size - p_data->lbuf_used; 2623 if (lbuf_left < copy_size) 2624 copy_size = lbuf_left; 2625 2626 memcpy (c->rq.cntn.lbuf.data + p_data->lbuf_used, 2627 buf, 2628 copy_size); 2629 p_data->lbuf_used += copy_size; 2630 *pdata_size -= copy_size; 2631 2632 data_size_before_parse = p_data->lbuf_used; 2633 switch (p_data->enc) 2634 { 2635 case MHD_HTTP_POST_ENCODING_FORM_URLENCODED: 2636 if (parse_post_urlenc (c, 2637 &(p_data->lbuf_used), 2638 c->rq.cntn.lbuf.data)) 2639 return true; 2640 break; 2641 case MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA: 2642 if (parse_post_mpart (c, 2643 &(p_data->lbuf_used), 2644 c->rq.cntn.lbuf.data)) 2645 return true; 2646 break; 2647 case MHD_HTTP_POST_ENCODING_TEXT_PLAIN: 2648 if (parse_post_text (c, 2649 &(p_data->lbuf_used), 2650 c->rq.cntn.lbuf.data)) 2651 return true; 2652 break; 2653 case MHD_HTTP_POST_ENCODING_OTHER: 2654 default: 2655 mhd_UNREACHABLE (); 2656 p_data->parse_result = 2657 MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT; 2658 c->stage = mhd_HTTP_STAGE_FULL_REQ_RECEIVED; 2659 return true; 2660 } 2661 if (data_size_before_parse == p_data->lbuf_used) 2662 break; /* Nothing consumed, not possible to add new data to the buffer now */ 2663 } 2664 2665 if (0 != *pdata_size) 2666 return report_low_lbuf_mem (c); 2667 2668 return false; /* Continue normal processing */ 2669 } 2670 2671 2672 /** 2673 * Check whether some unprocessed or partially processed data left in buffers 2674 * for urlencoding POST encoding. 2675 * @param c the stream to use 2676 * @param pdata_size the pointer to the size of the data in the buffer 2677 * @param buf the buffer with the data 2678 * @return 'true' if stream state was changed, 2679 * 'false' to continue normal processing 2680 */ 2681 static MHD_FN_PAR_NONNULL_ALL_ 2682 MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (3) bool 2683 check_post_leftovers_urlenc (struct MHD_Connection *restrict c, 2684 size_t *restrict pdata_size, 2685 char *restrict buf) 2686 { 2687 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 2688 struct mhd_PostParserUrlEncData *const uf = &(p_data->e_d.u_enc); /**< the current "text" field */ 2689 size_t pos; 2690 size_t name_start; 2691 size_t name_len; 2692 size_t value_start; 2693 size_t value_len; 2694 bool have_extra_space; 2695 bool need_value_stream; 2696 2697 pos = p_data->next_parse_pos; /* Points to the char AFTER the data */ 2698 mhd_assert (pos <= c->rq.cntn.lbuf.size); // TODO: support processing in connection buffer 2699 mhd_assert (*pdata_size >= pos); 2700 have_extra_space = (pos < c->rq.cntn.lbuf.size); 2701 need_value_stream = false; /**< Value cannot be zero-terminated and must be streamed */ 2702 switch (uf->st) 2703 { 2704 case mhd_POST_UENC_ST_NOT_STARTED: 2705 mhd_assert (pos == *pdata_size); 2706 return false; /* Continue processing */ 2707 case mhd_POST_UENC_ST_NAME: 2708 mhd_assert (pos == *pdata_size); 2709 /* Unfinished name */ 2710 name_start = uf->name_idx; 2711 if (uf->last_pct_idx != mhd_POST_INVALID_POS) 2712 name_len = mhd_str_pct_decode_lenient_n (buf + uf->name_idx, 2713 pos - uf->name_idx, 2714 buf + uf->name_idx, 2715 pos - uf->name_idx, 2716 NULL); 2717 else 2718 name_len = pos - uf->name_idx; 2719 mhd_assert (name_start + name_len <= pos); 2720 if (! have_extra_space && 2721 (name_start + name_len == pos)) 2722 return report_low_lbuf_mem (c); 2723 buf[name_start + name_len] = 0; /* Zero-terminate the result, an extra byte is available */ 2724 value_start = 0; 2725 value_len = 0; 2726 break; 2727 case mhd_POST_UENC_ST_EQ_FOUND: 2728 mhd_assert (pos == *pdata_size); 2729 name_start = uf->name_idx; 2730 name_len = uf->name_len; 2731 value_start = pos; 2732 value_len = 0; 2733 if (! have_extra_space) 2734 need_value_stream = true; 2735 else 2736 buf[value_start] = 0; /* Zero-terminate the result, an extra byte is available */ 2737 break; 2738 case mhd_POST_UENC_ST_VALUE: 2739 mhd_assert (0 != uf->value_idx); 2740 name_start = uf->name_idx; 2741 name_len = uf->name_len; 2742 mhd_assert (0 == buf[name_start + name_len]); 2743 if (0 != uf->value_len) 2744 { 2745 /* The value was partially decoded and then application requested stream 2746 * suspending. */ 2747 mhd_assert (pos < *pdata_size); 2748 mhd_assert (2 >= *pdata_size - pos); 2749 value_start = uf->value_idx; 2750 if (uf->value_idx + uf->value_len != pos) 2751 memmove (buf + uf->value_idx + uf->value_len, 2752 buf + pos, 2753 *pdata_size - pos); 2754 value_len = uf->value_len + *pdata_size - pos; 2755 } 2756 else 2757 { 2758 /* The value has not been decoded yet */ 2759 mhd_assert (pos == *pdata_size); 2760 value_start = uf->value_idx; 2761 if (uf->last_pct_idx != mhd_POST_INVALID_POS) 2762 value_len = mhd_str_pct_decode_lenient_n (buf + uf->value_idx, 2763 pos - uf->value_idx, 2764 buf + uf->value_idx, 2765 pos - uf->value_idx, 2766 NULL); 2767 else 2768 value_len = pos - uf->value_idx; 2769 } 2770 if (! have_extra_space && 2771 (value_start + value_len == pos)) 2772 need_value_stream = true; 2773 else 2774 buf[value_start + value_len] = 0; /* Zero-terminate the result, an extra byte is available in the buffer */ 2775 break; 2776 case mhd_POST_UENC_ST_FULL_FIELD_FOUND: 2777 /* Full value was found, but the stream has been suspended by 2778 * the application */ 2779 mhd_assert (pos + 1 == *pdata_size); 2780 mhd_assert (0 != uf->value_idx); 2781 mhd_assert (pos != uf->value_idx); 2782 name_start = uf->name_idx; 2783 name_len = uf->name_len; 2784 value_start = uf->value_idx; 2785 value_len = uf->value_len; 2786 mhd_assert (0 == buf[name_start + name_len]); 2787 mhd_assert (0 == buf[value_start + value_len]); 2788 ++pos; 2789 mhd_assert (pos == *pdata_size); 2790 break; 2791 case mhd_POST_UENC_ST_AT_EQ: 2792 case mhd_POST_UENC_ST_AT_AMPRSND: 2793 default: 2794 mhd_UNREACHABLE (); 2795 p_data->parse_result = MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT; 2796 return false; 2797 } 2798 2799 /* Have field data */ 2800 2801 p_data->next_parse_pos = pos; 2802 2803 if (need_value_stream) 2804 { 2805 if (NULL != c->rq.app_act.head_act.data.post_parse.stream_reader) 2806 p_data->force_streamed = true; 2807 else 2808 return report_low_lbuf_mem (c); 2809 } 2810 2811 if (process_complete_field (c, 2812 buf, 2813 &(p_data->next_parse_pos), 2814 pdata_size, 2815 p_data->field_start, 2816 name_start, 2817 name_len, 2818 value_start, 2819 value_len)) 2820 return true; 2821 2822 reset_parse_field_data_urlenc (p_data); 2823 2824 return false; /* Continue normal processing */ 2825 } 2826 2827 2828 /** 2829 * Check whether some unprocessed or partially processed data left in buffers 2830 * for "multipart/form-data" POST encoding. 2831 * @param c the stream to use 2832 * @param pdata_size the pointer to the size of the data in the buffer 2833 * @param buf the buffer with the data 2834 * @return 'true' if stream state was changed, 2835 * 'false' to continue normal processing 2836 */ 2837 static MHD_FN_PAR_NONNULL_ALL_ 2838 MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (3) bool 2839 check_post_leftovers_mpart (struct MHD_Connection *restrict c, 2840 size_t *restrict pdata_size, 2841 char *restrict buf) 2842 { 2843 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 2844 struct mhd_PostParserMPartFormData *const mf = &(p_data->e_d.m_form); /**< the current "form-data" parsing details */ 2845 size_t pos; 2846 bool not_terminated; 2847 bool add_field; 2848 size_t value_pos; 2849 size_t value_len; 2850 2851 pos = p_data->next_parse_pos; /* Points to the char AFTER the data, valid location as buffer is always at least one byte larger */ 2852 mhd_assert (pos <= c->rq.cntn.lbuf.size); // TODO: support processing in connection buffer 2853 mhd_assert (*pdata_size >= pos); 2854 2855 not_terminated = false; 2856 add_field = false; 2857 value_pos = 0; 2858 value_len = 0; 2859 2860 switch (mf->st) 2861 { 2862 case mhd_POST_MPART_ST_NOT_STARTED: 2863 case mhd_POST_MPART_ST_PREAMBL: 2864 case mhd_POST_MPART_ST_PREAMBL_CR_FOUND: 2865 case mhd_POST_MPART_ST_PREAMBL_CHECKING_FOR_DELIM: 2866 mhd_assert (pos == *pdata_size); 2867 return false; /* Continue processing */ 2868 case mhd_POST_MPART_ST_FIRST_DELIM_FOUND: 2869 case mhd_POST_MPART_ST_FIRST_PART_START: 2870 case mhd_POST_MPART_ST_PART_START: 2871 mhd_assert (pos == *pdata_size); 2872 not_terminated = true; 2873 break; 2874 case mhd_POST_MPART_ST_HEADER_LINE_START: 2875 case mhd_POST_MPART_ST_HEADER_LINE: 2876 case mhd_POST_MPART_ST_HEADER_LINE_CR_FOUND: 2877 case mhd_POST_MPART_ST_VALUE_START: 2878 mhd_assert (pos == *pdata_size); 2879 not_terminated = true; 2880 add_field = (0 != mf->f.name_idx); 2881 break; 2882 case mhd_POST_MPART_ST_VALUE: 2883 case mhd_POST_MPART_ST_VALUE_CR_FOUND: 2884 case mhd_POST_MPART_ST_VALUE_LINE_START: 2885 case mhd_POST_MPART_ST_VALUE_CHECKING_FOR_DELIM: 2886 mhd_assert (0 != mf->f.name_idx); 2887 mhd_assert (0 != mf->f.value_idx); 2888 not_terminated = true; 2889 add_field = true; 2890 value_pos = mf->f.value_idx; 2891 value_len = pos - value_len; 2892 break; 2893 case mhd_POST_MPART_ST_DELIM_FOUND: 2894 mhd_assert (0 != mf->f.name_idx); 2895 mhd_assert (mhd_POST_INVALID_POS != mf->delim_check_start); 2896 mhd_assert (pos > mf->delim_check_start); 2897 not_terminated = true; 2898 add_field = true; 2899 if (0 != mf->f.value_idx) 2900 { 2901 value_pos = mf->f.value_idx; 2902 value_len = mf->delim_check_start - mf->f.value_idx; 2903 } 2904 break; 2905 case mhd_POST_MPART_ST_FULL_FIELD_FOUND: 2906 not_terminated = true; 2907 mhd_FALLTHROUGH; 2908 /* Intentional fallthrough */ 2909 case mhd_POST_MPART_ST_FULL_FIELD_FOUND_FINAL: 2910 mhd_assert (0 != mf->f.name_idx); 2911 add_field = true; 2912 if (0 != mf->f.value_idx) 2913 { 2914 value_pos = mf->f.value_idx; 2915 value_len = mf->f.value_len; 2916 } 2917 break; 2918 case mhd_POST_MPART_ST_EPILOGUE: 2919 case mhd_POST_MPART_ST_FORMAT_ERROR: 2920 return false; /* Continue processing */ 2921 case mhd_POST_MPART_ST_BACK_TO_PREAMBL: 2922 case mhd_POST_MPART_ST_PREAMBL_LINE_START: 2923 case mhd_POST_MPART_ST_HEADER_LINE_END: 2924 case mhd_POST_MPART_ST_BACK_TO_VALUE: 2925 case mhd_POST_MPART_ST_VALUE_END_FOUND: 2926 case mhd_POST_MPART_ST_VALUE_END_FOUND_FINAL: 2927 default: 2928 mhd_UNREACHABLE (); 2929 p_data->parse_result = MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT; 2930 return false; 2931 } 2932 2933 if (not_terminated) 2934 report_invalid_termination (c); /* The "closing" delimiter is missing */ 2935 2936 if (add_field) 2937 { 2938 if (c->rq.cntn.lbuf.size > (value_pos + value_len)) 2939 buf [value_pos + value_len] = 0; /* Zero-terminate the value */ 2940 else if (NULL != c->rq.app_act.head_act.data.post_parse.stream_reader) 2941 p_data->force_streamed = true; 2942 else 2943 return report_low_lbuf_mem (c); 2944 2945 p_data->next_parse_pos = pos; 2946 2947 if (process_complete_field_all (c, 2948 buf, 2949 &p_data->next_parse_pos, 2950 pdata_size, 2951 p_data->field_start, 2952 mf->f.name_idx, 2953 mf->f.name_len, 2954 mf->f.filename_idx, 2955 mf->f.filename_len, 2956 mf->f.cntn_type_idx, 2957 mf->f.cntn_type_len, 2958 mf->f.enc_idx, 2959 mf->f.enc_len, 2960 value_pos, 2961 value_len)) 2962 return true; 2963 } 2964 2965 reset_parse_field_data_mpart_cont (p_data, 2966 ! not_terminated); 2967 2968 return false; /* Continue normal processing */ 2969 } 2970 2971 2972 /** 2973 * Check whether some unprocessed or partially processed data left in buffers 2974 * for "text" POST encoding. 2975 * @param c the stream to use 2976 * @param pdata_size the pointer to the size of the data in the buffer 2977 * @param buf the buffer with the data 2978 * @return 'true' if stream state was changed, 2979 * 'false' to continue normal processing 2980 */ 2981 static MHD_FN_PAR_NONNULL_ALL_ 2982 MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (3) bool 2983 check_post_leftovers_text (struct MHD_Connection *restrict c, 2984 size_t *restrict pdata_size, 2985 char *restrict buf) 2986 { 2987 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 2988 struct mhd_PostParserTextData *const tf = &(p_data->e_d.text); /**< the current "text" field */ 2989 size_t pos; 2990 size_t name_start; 2991 size_t name_len; 2992 size_t value_start; 2993 size_t value_len; 2994 2995 pos = p_data->next_parse_pos; /* Points to the char AFTER the data, valid location as buffer is always at least one byte larger */ 2996 mhd_assert (pos <= c->rq.cntn.lbuf.size); // TODO: support processing in connection buffer 2997 switch (tf->st) 2998 { 2999 case mhd_POST_TEXT_ST_NOT_STARTED: 3000 mhd_assert (pos == *pdata_size); 3001 return false; /* Continue processing */ 3002 case mhd_POST_TEXT_ST_NAME: 3003 /* Unfinished name */ 3004 mhd_assert (pos == *pdata_size); 3005 name_start = tf->name_idx; 3006 name_len = pos - name_start; 3007 if (pos == c->rq.cntn.lbuf.size) 3008 return report_low_lbuf_mem (c); 3009 buf[pos] = 0; /* Zero-terminate the result, an extra byte is available */ 3010 value_start = 0; 3011 value_len = 0; 3012 break; 3013 case mhd_POST_TEXT_ST_EQ_FOUND: 3014 mhd_assert (pos == *pdata_size); 3015 name_start = tf->name_idx; 3016 name_len = tf->name_len; 3017 value_start = pos; 3018 value_len = 0; 3019 break; 3020 case mhd_POST_TEXT_ST_VALUE: 3021 mhd_assert (pos == *pdata_size); 3022 mhd_assert (0 != tf->value_idx); 3023 mhd_assert (pos != tf->value_idx); 3024 name_start = tf->name_idx; 3025 name_len = tf->name_len; 3026 value_start = tf->value_idx; 3027 value_len = pos - value_start; 3028 break; 3029 case mhd_POST_TEXT_ST_CR_FOUND: 3030 mhd_assert (pos == *pdata_size); 3031 mhd_assert (0 != tf->value_idx); 3032 mhd_assert (pos != tf->value_idx); 3033 name_start = tf->name_idx; 3034 name_len = tf->name_len; 3035 value_start = tf->value_idx; 3036 value_len = tf->value_len; 3037 mhd_assert (value_start + value_len + 1 == pos); 3038 mhd_assert (0 == buf[value_start + value_len]); 3039 break; 3040 case mhd_POST_TEXT_ST_FULL_LINE_FOUND: 3041 /* Full value was found, but the stream has been suspended by 3042 * the application */ 3043 mhd_assert (pos + 1 == *pdata_size); 3044 mhd_assert (0 != tf->value_idx); 3045 name_start = tf->name_idx; 3046 name_len = tf->name_len; 3047 value_start = tf->value_idx; 3048 value_len = tf->value_len; 3049 mhd_assert ((value_start + value_len + 1 == pos) || \ 3050 (value_start + value_len + 2 == pos)); 3051 mhd_assert (0 == buf[value_start + value_len]); 3052 ++pos; 3053 mhd_assert (pos == *pdata_size); 3054 break; 3055 case mhd_POST_TEXT_ST_AT_EQ: 3056 case mhd_POST_TEXT_ST_AT_LF_BARE: 3057 case mhd_POST_TEXT_ST_AT_CR: 3058 default: 3059 mhd_UNREACHABLE (); 3060 p_data->parse_result = MHD_POST_PARSE_RES_FAILED_INVALID_POST_FORMAT; 3061 return false; 3062 } 3063 3064 if (tf->st != mhd_POST_TEXT_ST_FULL_LINE_FOUND) 3065 report_invalid_termination (c); /* The line must be terminated by CRLF, but it is not */ 3066 3067 if (0 != value_start) 3068 { 3069 if (c->rq.cntn.lbuf.size > (value_start + value_len)) 3070 buf [value_start + value_len] = 0; /* Zero-terminate the value */ 3071 else if (NULL != c->rq.app_act.head_act.data.post_parse.stream_reader) 3072 p_data->force_streamed = true; 3073 else 3074 return report_low_lbuf_mem (c); 3075 } 3076 3077 if (process_complete_field (c, 3078 buf, 3079 &pos, 3080 pdata_size, 3081 p_data->field_start, 3082 name_start, 3083 name_len, 3084 value_start, 3085 value_len)) 3086 return true; 3087 3088 reset_parse_field_data_text (p_data); 3089 3090 return false; /* Continue normal processing */ 3091 } 3092 3093 3094 /** 3095 * Check in leftover POST data in the buffers 3096 * @param c the stream to use 3097 * @return 'true' if stream state is changed, 3098 * 'false' to continue 3099 */ 3100 static MHD_FN_PAR_NONNULL_ALL_ bool 3101 check_post_leftovers (struct MHD_Connection *restrict c) 3102 { 3103 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 3104 // TODO: implement processing in the connection buffer 3105 if (p_data->lbuf_used == c->rq.cntn.lbuf.size) 3106 (void) extend_lbuf_up_to (c, 3107 1, 3108 &(c->rq.cntn.lbuf)); 3109 3110 switch (p_data->enc) 3111 { 3112 case MHD_HTTP_POST_ENCODING_FORM_URLENCODED: 3113 return check_post_leftovers_urlenc (c, 3114 &(p_data->lbuf_used), 3115 c->rq.cntn.lbuf.data); 3116 case MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA: 3117 return check_post_leftovers_mpart (c, 3118 &(p_data->lbuf_used), 3119 c->rq.cntn.lbuf.data); 3120 case MHD_HTTP_POST_ENCODING_TEXT_PLAIN: 3121 return check_post_leftovers_text (c, 3122 &(p_data->lbuf_used), 3123 c->rq.cntn.lbuf.data); 3124 case MHD_HTTP_POST_ENCODING_OTHER: 3125 default: 3126 mhd_UNREACHABLE (); 3127 p_data->parse_result = 3128 MHD_POST_PARSE_RES_PARTIAL_INVALID_POST_FORMAT; 3129 c->stage = mhd_HTTP_STAGE_FULL_REQ_RECEIVED; 3130 break; 3131 } 3132 return true; 3133 } 3134 3135 3136 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 3137 mhd_stream_process_post_finish (struct MHD_Connection *restrict c) 3138 { 3139 struct mhd_PostParserData *const p_data = &(c->rq.u_proc.post); 3140 const struct MHD_UploadAction *act; 3141 bool state_changed; 3142 3143 if ((MHD_POST_PARSE_RES_OK == p_data->parse_result) && 3144 ! c->discard_request) 3145 { 3146 // TODO: implement processing in the connection buffer 3147 if (check_post_leftovers (c)) 3148 return true; 3149 } 3150 3151 act = c->rq.app_act.head_act.data.post_parse.done_cb ( 3152 &(c->rq), 3153 c->rq.app_act.head_act.data.post_parse.done_cb_cls, 3154 p_data->parse_result); 3155 3156 state_changed = mhd_stream_process_upload_action (c, act, true); 3157 if (! c->suspended) 3158 mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf)); 3159 return state_changed; 3160 }