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