stream_process_states.c (21251B)
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) 2014-2024 Evgeny Grin (Karlson2k) 5 Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff 6 7 GNU libmicrohttpd is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License as published by the Free Software Foundation; either 10 version 2.1 of the License, or (at your option) any later version. 11 12 GNU libmicrohttpd is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 Alternatively, you can redistribute GNU libmicrohttpd and/or 18 modify it under the terms of the GNU General Public License as 19 published by the Free Software Foundation; either version 2 of 20 the License, or (at your option) any later version, together 21 with the eCos exception, as follows: 22 23 As a special exception, if other files instantiate templates or 24 use macros or inline functions from this file, or you compile this 25 file and link it with other works to produce a work based on this 26 file, this file does not by itself cause the resulting work to be 27 covered by the GNU General Public License. However the source code 28 for this file must still be made available in accordance with 29 section (3) of the GNU General Public License v2. 30 31 This exception does not invalidate any other reasons why a work 32 based on this file might be covered by the GNU General Public 33 License. 34 35 You should have received copies of the GNU Lesser General Public 36 License and the GNU General Public License along with this library; 37 if not, see <https://www.gnu.org/licenses/>. 38 */ 39 40 /** 41 * @file src/mhd2/stream_process_states.h 42 * @brief The definitions of internal functions for processing 43 * stream states 44 * @author Karlson2k (Evgeny Grin) 45 * 46 * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff and other 47 * contributors. 48 */ 49 50 #include "mhd_sys_options.h" 51 52 #include "sys_bool_type.h" 53 #include "sys_base_types.h" 54 55 #include "mhd_assert.h" 56 #include "mhd_unreachable.h" 57 58 #include "mhd_str_macros.h" 59 #include "mhd_socket_error_funcs.h" 60 61 #include "mhd_daemon.h" 62 #include "mhd_connection.h" 63 #include "mhd_response.h" 64 65 #include "mhd_comm_layer_state.h" 66 #ifdef MHD_SUPPORT_HTTP2 67 # include "h2/h2_comm.h" 68 #endif 69 70 #include "stream_process_states.h" 71 #include "stream_funcs.h" 72 #include "stream_process_request.h" 73 #include "stream_process_reply.h" 74 75 #include "conn_mark_ready.h" 76 77 #ifdef MHD_SUPPORT_UPGRADE 78 # include "upgrade_proc.h" 79 #endif /* MHD_SUPPORT_UPGRADE */ 80 81 #ifdef mhd_DEBUG_SUSPEND_RESUME 82 # include <stdio.h> 83 #endif /* mhd_DEBUG_SUSPEND_RESUME */ 84 85 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 86 mhd_conn_event_loop_state_update (struct MHD_Connection *restrict c) 87 { 88 #ifdef MHD_SUPPORT_HTTPS 89 mhd_assert (! mhd_C_HAS_TLS (c) || \ 90 (mhd_CONN_STATE_TLS_CONNECTED == c->conn_state)); 91 mhd_assert (mhd_C_HAS_TLS (c) || \ 92 (mhd_CONN_STATE_TCP_CONNECTED == c->conn_state)); 93 #endif /* MHD_SUPPORT_HTTPS */ 94 95 #ifdef MHD_SUPPORT_HTTP2 96 if (mhd_C_IS_HTTP2 (c)) 97 { 98 mhd_h2_conn_state_update (c); 99 return; 100 } 101 #endif /* MHD_SUPPORT_HTTP2 */ 102 103 switch (c->stage) 104 { 105 case mhd_HTTP_STAGE_INIT: 106 case mhd_HTTP_STAGE_REQ_LINE_RECEIVING: 107 c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; 108 break; 109 case mhd_HTTP_STAGE_REQ_LINE_RECEIVED: 110 mhd_assert (0 && "Impossible value"); 111 mhd_UNREACHABLE (); 112 break; 113 case mhd_HTTP_STAGE_REQ_HEADERS_RECEIVING: 114 c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; 115 break; 116 case mhd_HTTP_STAGE_HEADERS_RECEIVED: 117 case mhd_HTTP_STAGE_HEADERS_PROCESSED: 118 mhd_assert (0 && "Impossible value"); 119 mhd_UNREACHABLE (); 120 break; 121 case mhd_HTTP_STAGE_CONTINUE_SENDING: 122 c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; 123 break; 124 case mhd_HTTP_STAGE_BODY_RECEIVING: 125 c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; 126 break; 127 case mhd_HTTP_STAGE_BODY_RECEIVED: 128 mhd_assert (0 && "Impossible value"); 129 mhd_UNREACHABLE (); 130 break; 131 case mhd_HTTP_STAGE_FOOTERS_RECEIVING: 132 c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; 133 break; 134 case mhd_HTTP_STAGE_FOOTERS_RECEIVED: 135 mhd_assert (0 && "Impossible value"); 136 mhd_UNREACHABLE (); 137 break; 138 case mhd_HTTP_STAGE_FULL_REQ_RECEIVED: 139 mhd_assert (0 && "Should not be possible"); 140 c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; 141 break; 142 case mhd_HTTP_STAGE_REQ_RECV_FINISHED: 143 mhd_assert (0 && "Impossible value"); 144 mhd_UNREACHABLE (); 145 break; 146 case mhd_HTTP_STAGE_START_REPLY: 147 mhd_assert (0 && "Impossible value"); 148 mhd_UNREACHABLE (); 149 break; 150 case mhd_HTTP_STAGE_HEADERS_SENDING: 151 /* headers in buffer, keep writing */ 152 c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; 153 break; 154 case mhd_HTTP_STAGE_HEADERS_SENT: 155 mhd_assert (0 && "Impossible value"); 156 mhd_UNREACHABLE (); 157 break; 158 #ifdef MHD_SUPPORT_UPGRADE 159 case mhd_HTTP_STAGE_UPGRADE_HEADERS_SENDING: 160 c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; 161 break; 162 #endif /* MHD_SUPPORT_UPGRADE */ 163 case mhd_HTTP_STAGE_UNCHUNKED_BODY_UNREADY: 164 mhd_assert (0 && "Should not be possible"); 165 c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; 166 break; 167 case mhd_HTTP_STAGE_UNCHUNKED_BODY_READY: 168 c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; 169 break; 170 case mhd_HTTP_STAGE_CHUNKED_BODY_UNREADY: 171 mhd_assert (0 && "Should not be possible"); 172 c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; 173 break; 174 case mhd_HTTP_STAGE_CHUNKED_BODY_READY: 175 c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; 176 break; 177 case mhd_HTTP_STAGE_CHUNKED_BODY_SENT: 178 mhd_assert (0 && "Impossible value"); 179 mhd_UNREACHABLE (); 180 break; 181 case mhd_HTTP_STAGE_FOOTERS_SENDING: 182 c->event_loop_info = MHD_EVENT_LOOP_INFO_SEND; 183 break; 184 case mhd_HTTP_STAGE_FULL_REPLY_SENT: 185 mhd_assert (0 && "Impossible value"); 186 mhd_UNREACHABLE (); 187 break; 188 #ifdef MHD_SUPPORT_UPGRADE 189 case mhd_HTTP_STAGE_UPGRADING: 190 mhd_assert (0 && "Impossible value"); 191 mhd_UNREACHABLE (); 192 break; 193 case mhd_HTTP_STAGE_UPGRADED: 194 mhd_assert (0 && "Should not be possible"); 195 c->event_loop_info = MHD_EVENT_LOOP_INFO_UPGRADED; 196 break; 197 case mhd_HTTP_STAGE_UPGRADED_CLEANING: 198 mhd_assert (0 && "Should be unreachable"); 199 c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; 200 break; 201 #endif /* MHD_SUPPORT_UPGRADE */ 202 case mhd_HTTP_STAGE_PRE_CLOSING: 203 mhd_assert (0 && "Should be unreachable"); 204 c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; 205 break; 206 case mhd_HTTP_STAGE_CLOSED: 207 mhd_assert (0 && "Should be unreachable"); 208 c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; 209 break; 210 default: 211 mhd_UNREACHABLE (); 212 break; 213 } 214 } 215 216 217 /** 218 * Process HTTP communication layer states and events 219 * @param c the connection to process 220 * @return #mhd_COMM_LAYER_PROCESSING if setting up HTTP connection is 221 * in progress, 222 * #mhd_COMM_LAYER_OK if HTTP communication can be performed now, 223 * #mhd_COMM_LAYER_BROKEN if connection is broken and should be closed. 224 */ 225 mhd_static_inline enum mhd_CommLayerState 226 process_http_comm_layer (struct MHD_Connection *restrict c) 227 { 228 #ifdef MHD_SUPPORT_HTTP2 229 if (mhd_HTTP_LAYER_CONNECTED == c->h_layer.state) 230 return mhd_COMM_LAYER_OK; /* Shortcut for the most common case */ 231 232 switch (c->h_layer.state) 233 { 234 case mhd_HTTP_LAYER_PREFACE: 235 return mhd_h2_process_preface (c); 236 case mhd_HTTP_LAYER_CONNECTED: 237 mhd_UNREACHABLE (); /* Handled above */ 238 return mhd_COMM_LAYER_OK; 239 case mhd_HTTP_LAYER_CLOSING: 240 case mhd_HTTP_LAYER_CLOSED: 241 return mhd_COMM_LAYER_OK; 242 case mhd_HTTP_LAYER_BROKEN: 243 return mhd_COMM_LAYER_BROKEN; 244 default: 245 break; 246 } 247 248 mhd_UNREACHABLE (); 249 return mhd_COMM_LAYER_BROKEN; 250 251 #else /* ! MHD_SUPPORT_HTTP2 */ 252 (void) c; /* Unused in HTTP/1.x-only modes */ 253 return mhd_COMM_LAYER_OK; 254 #endif /* ! MHD_SUPPORT_HTTP2 */ 255 } 256 257 258 /** 259 * Finalise resuming of the connection 260 * @param c the connection to resume 261 */ 262 static MHD_FN_PAR_NONNULL_ALL_ void 263 finish_resume (struct MHD_Connection *restrict c) 264 { 265 mhd_assert (c->resuming); 266 c->resuming = false; 267 268 #ifdef mhd_DEBUG_SUSPEND_RESUME 269 fprintf (stderr, 270 "%%%%%% Resumed connection, FD: %2llu\n", 271 (unsigned long long) c->sk.fd); 272 #endif /* mhd_DEBUG_SUSPEND_RESUME */ 273 mhd_assert (! c->suspended); 274 mhd_assert (MHD_EVENT_LOOP_INFO_PROCESS == c->event_loop_info); 275 } 276 277 278 /** 279 * Update current processing state: need to receive, need to send. 280 * Mark stream as ready or not ready for processing. 281 * Grow the receive buffer if neccesary, close stream if no buffer space left, 282 * but connection needs to receive. 283 * @param c the connection to update 284 * @return true if connection states updated successfully, 285 * false if connection has been prepared for closing 286 */ 287 static MHD_FN_PAR_NONNULL_ALL_ bool 288 update_active_state (struct MHD_Connection *restrict c) 289 { 290 /* Do not update states of suspended connection */ 291 mhd_assert (! c->suspended); 292 293 if (0 != (c->sk.ready & mhd_SOCKET_NET_STATE_ERROR_READY)) 294 { 295 mhd_assert (0 && "Should be handled earlier"); 296 mhd_conn_start_closing_skt_err (c); 297 return false; 298 } 299 300 mhd_conn_event_loop_state_update (c); 301 302 if (! mhd_C_IS_HTTP2 (c)) 303 { 304 if (0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info)) 305 { 306 /* Check whether the space is available to receive data */ 307 if (! mhd_stream_check_and_grow_read_buffer_space (c)) 308 { 309 mhd_assert (c->discard_request); 310 return false; 311 } 312 } 313 } 314 315 /* Current MHD design assumes that data must be always processes when 316 * available. If it is not possible, connection must be suspended. */ 317 mhd_assert (MHD_EVENT_LOOP_INFO_PROCESS != c->event_loop_info); 318 319 /* Sockets errors must be already handled */ 320 mhd_assert (0 == (c->sk.ready & mhd_SOCKET_NET_STATE_ERROR_READY)); 321 322 mhd_conn_mark_ready_update (c); 323 324 return true; 325 } 326 327 328 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 329 mhd_conn_process_data (struct MHD_Connection *restrict c) 330 { 331 struct MHD_Daemon *const d = c->daemon; 332 bool daemon_closing; 333 334 if (c->suspended) 335 { 336 mhd_assert (! mhd_C_IS_HTTP2 (c)); 337 return true; 338 } 339 340 switch (process_http_comm_layer (c)) 341 { 342 case mhd_COMM_LAYER_OK: 343 break; /* Process HTTP data */ 344 case mhd_COMM_LAYER_PROCESSING: 345 mhd_assert (! c->resuming); 346 return true; /* Too early for HTTP */ 347 case mhd_COMM_LAYER_BROKEN: 348 mhd_assert (c->dbg.closing_started); 349 return false; /* Connection is broken */ 350 default: 351 mhd_UNREACHABLE (); 352 return false; 353 } 354 355 if (c->resuming) 356 { 357 mhd_assert (! mhd_C_IS_HTTP2 (c)); 358 finish_resume (c); 359 } 360 361 #ifdef MHD_SUPPORT_HTTP2 362 if (mhd_C_IS_HTTP2 (c)) 363 { 364 if (! mhd_h2_conn_process_data (c)) 365 return false; 366 update_active_state (c); 367 return true; 368 } 369 #endif /* MHD_SUPPORT_HTTP2 */ 370 371 mhd_assert (mhd_D_IS_HTTP1_ENABLED (d) || (! mhd_C_IS_HTTP2 (c)) || \ 372 c->stop_with_error); 373 374 if ((c->sk.state.rmt_shut_wr) && (mhd_HTTP_STAGE_START_REPLY > c->stage)) 375 { 376 if (0 == c->read_buffer_offset) 377 { /* Read buffer is empty, connection state is actual */ 378 mhd_conn_start_closing (c, 379 (mhd_HTTP_STAGE_INIT == c->stage) ? 380 mhd_CONN_CLOSE_HTTP_COMPLETED : 381 mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY, 382 NULL); 383 return false; 384 } 385 } 386 387 mhd_assert ((! mhd_SCKT_NET_ST_HAS_FLAG (c->sk.ready, 388 mhd_SOCKET_NET_STATE_ERROR_READY)) 389 || (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err)); 390 391 if (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err) 392 { 393 mhd_assert (mhd_SOCKET_ERR_IS_HARD (c->sk.state.discnt_err)); 394 mhd_conn_start_closing_skt_err (c); 395 return false; 396 } 397 398 daemon_closing = (mhd_DAEMON_STATE_STOPPING == d->state); 399 #ifdef MHD_SUPPORT_THREADS 400 daemon_closing = daemon_closing || d->threading.stop_requested; 401 #endif /* MHD_SUPPORT_THREADS */ 402 if (daemon_closing) 403 { 404 mhd_conn_start_closing_d_shutdown (c); 405 return false; 406 } 407 408 mhd_assert (! c->suspended); 409 410 while (! c->suspended) 411 { 412 #ifdef MHD_SUPPORT_HTTPS 413 mhd_assert (! mhd_C_HAS_TLS (c) || \ 414 (mhd_CONN_STATE_TLS_CONNECTED == c->conn_state)); 415 mhd_assert (mhd_C_HAS_TLS (c) || \ 416 (mhd_CONN_STATE_TCP_CONNECTED == c->conn_state)); 417 #endif /* MHD_SUPPORT_HTTPS */ 418 switch (c->stage) 419 { 420 case mhd_HTTP_STAGE_INIT: 421 case mhd_HTTP_STAGE_REQ_LINE_RECEIVING: 422 if (mhd_stream_get_request_line (c)) 423 { 424 mhd_assert (mhd_HTTP_STAGE_REQ_LINE_RECEIVING < c->stage); 425 mhd_assert ((MHD_HTTP_VERSION_IS_SUPPORTED (c->rq.http_ver)) \ 426 || (c->discard_request)); 427 continue; 428 } 429 mhd_assert (mhd_HTTP_STAGE_REQ_LINE_RECEIVING >= c->stage); 430 break; 431 case mhd_HTTP_STAGE_REQ_LINE_RECEIVED: 432 mhd_stream_switch_to_rq_headers_proc (c); 433 mhd_assert (mhd_HTTP_STAGE_REQ_LINE_RECEIVED != c->stage); 434 continue; 435 case mhd_HTTP_STAGE_REQ_HEADERS_RECEIVING: 436 if (mhd_stream_get_request_headers (c, false)) 437 { 438 mhd_assert (mhd_HTTP_STAGE_REQ_HEADERS_RECEIVING < c->stage); 439 mhd_assert ((mhd_HTTP_STAGE_HEADERS_RECEIVED == c->stage) || \ 440 (c->discard_request)); 441 continue; 442 } 443 mhd_assert (mhd_HTTP_STAGE_REQ_HEADERS_RECEIVING == c->stage); 444 break; 445 case mhd_HTTP_STAGE_HEADERS_RECEIVED: 446 mhd_stream_parse_request_headers (c); 447 mhd_assert (c->stage != mhd_HTTP_STAGE_HEADERS_RECEIVED); 448 continue; 449 case mhd_HTTP_STAGE_HEADERS_PROCESSED: 450 if (mhd_stream_call_app_request_cb (c)) 451 { 452 mhd_assert (mhd_HTTP_STAGE_HEADERS_PROCESSED < c->stage); 453 continue; 454 } 455 // TODO: add assert 456 break; 457 case mhd_HTTP_STAGE_CONTINUE_SENDING: 458 if (c->continue_message_write_offset == 459 mhd_SSTR_LEN (mdh_HTTP_1_1_100_CONTINUE_REPLY)) 460 { 461 #ifdef MHD_SUPPORT_UPGRADE 462 c->rp.sent_100_cntn = true; 463 #endif /* MHD_SUPPORT_UPGRADE */ 464 c->stage = mhd_HTTP_STAGE_BODY_RECEIVING; 465 continue; 466 } 467 break; 468 case mhd_HTTP_STAGE_BODY_RECEIVING: 469 mhd_assert (c->rq.cntn.recv_size < c->rq.cntn.cntn_size); 470 mhd_assert (! c->discard_request); 471 mhd_assert (NULL == c->rp.response); 472 if (0 == c->read_buffer_offset) 473 break; /* Need more data to process */ 474 475 if (mhd_stream_process_request_body (c)) 476 continue; 477 mhd_assert (! c->discard_request); 478 mhd_assert (NULL == c->rp.response); 479 break; 480 case mhd_HTTP_STAGE_BODY_RECEIVED: 481 mhd_assert (! c->discard_request); 482 mhd_assert (NULL == c->rp.response); 483 mhd_assert (c->rq.have_chunked_upload); 484 /* Reset counter variables reused for footers */ 485 c->rq.num_cr_sp_replaced = 0; 486 c->rq.skipped_broken_lines = 0; 487 mhd_stream_reset_rq_hdr_proc_state (c); 488 c->stage = mhd_HTTP_STAGE_FOOTERS_RECEIVING; 489 continue; 490 case mhd_HTTP_STAGE_FOOTERS_RECEIVING: 491 mhd_assert (c->rq.have_chunked_upload); 492 if (mhd_stream_get_request_headers (c, true)) 493 { 494 mhd_assert (mhd_HTTP_STAGE_FOOTERS_RECEIVING < c->stage); 495 mhd_assert ((mhd_HTTP_STAGE_FOOTERS_RECEIVED == c->stage) || \ 496 (c->discard_request)); 497 continue; 498 } 499 mhd_assert (mhd_HTTP_STAGE_FOOTERS_RECEIVING == c->stage); 500 break; 501 case mhd_HTTP_STAGE_FOOTERS_RECEIVED: 502 mhd_assert (c->rq.have_chunked_upload); 503 c->stage = mhd_HTTP_STAGE_FULL_REQ_RECEIVED; 504 continue; 505 case mhd_HTTP_STAGE_FULL_REQ_RECEIVED: 506 if (mhd_stream_call_app_final_upload_cb (c)) 507 { 508 mhd_assert (mhd_HTTP_STAGE_FOOTERS_RECEIVING != c->stage); 509 continue; 510 } 511 break; 512 case mhd_HTTP_STAGE_REQ_RECV_FINISHED: 513 if (mhd_stream_process_req_recv_finished (c)) 514 continue; 515 break; 516 // TODO: add stage for setup and full request buffers cleanup 517 case mhd_HTTP_STAGE_START_REPLY: 518 mhd_assert (NULL != c->rp.response); 519 mhd_stream_switch_from_recv_to_send (c); 520 if (! mhd_stream_build_header_response (c)) 521 continue; 522 mhd_assert (mhd_HTTP_STAGE_START_REPLY != c->stage); 523 break; 524 case mhd_HTTP_STAGE_HEADERS_SENDING: 525 /* no default action, wait for sending all the headers */ 526 break; 527 case mhd_HTTP_STAGE_HEADERS_SENT: 528 if (c->rp.props.send_reply_body) 529 { 530 if (c->rp.props.chunked) 531 c->stage = mhd_HTTP_STAGE_CHUNKED_BODY_UNREADY; 532 else 533 c->stage = mhd_HTTP_STAGE_UNCHUNKED_BODY_UNREADY; 534 } 535 else 536 c->stage = mhd_HTTP_STAGE_FULL_REPLY_SENT; 537 continue; 538 #ifdef MHD_SUPPORT_UPGRADE 539 case mhd_HTTP_STAGE_UPGRADE_HEADERS_SENDING: 540 if (! mhd_upgrade_try_start_upgrading (c)) 541 break; 542 continue; 543 #endif /* MHD_SUPPORT_UPGRADE */ 544 case mhd_HTTP_STAGE_UNCHUNKED_BODY_READY: 545 mhd_assert (c->rp.props.send_reply_body); 546 mhd_assert (! c->rp.props.chunked); 547 /* nothing to do here, send the data */ 548 break; 549 case mhd_HTTP_STAGE_UNCHUNKED_BODY_UNREADY: 550 mhd_assert (c->rp.props.send_reply_body); 551 mhd_assert (! c->rp.props.chunked); 552 if (0 == c->rp.response->cntn_size) 553 { /* a shortcut */ 554 c->stage = mhd_HTTP_STAGE_FULL_REPLY_SENT; 555 continue; 556 } 557 if (mhd_stream_prep_unchunked_body (c)) 558 continue; 559 break; 560 case mhd_HTTP_STAGE_CHUNKED_BODY_READY: 561 mhd_assert (c->rp.props.send_reply_body); 562 mhd_assert (c->rp.props.chunked); 563 /* nothing to do here */ 564 break; 565 case mhd_HTTP_STAGE_CHUNKED_BODY_UNREADY: 566 mhd_assert (c->rp.props.send_reply_body); 567 mhd_assert (c->rp.props.chunked); 568 if ( (0 == c->rp.response->cntn_size) || 569 (c->rp.rsp_cntn_read_pos == 570 c->rp.response->cntn_size) ) 571 { 572 c->stage = mhd_HTTP_STAGE_CHUNKED_BODY_SENT; 573 continue; 574 } 575 if (mhd_stream_prep_chunked_body (c)) 576 continue; 577 break; 578 case mhd_HTTP_STAGE_CHUNKED_BODY_SENT: 579 mhd_assert (c->rp.props.send_reply_body); 580 mhd_assert (c->rp.props.chunked); 581 mhd_assert (c->write_buffer_send_offset <= \ 582 c->write_buffer_append_offset); 583 mhd_stream_call_dcc_cleanup_if_needed (c); 584 if (mhd_stream_prep_chunked_footer (c)) 585 continue; 586 break; 587 case mhd_HTTP_STAGE_FOOTERS_SENDING: 588 mhd_assert (c->rp.props.send_reply_body); 589 mhd_assert (c->rp.props.chunked); 590 /* no default action */ 591 break; 592 case mhd_HTTP_STAGE_FULL_REPLY_SENT: 593 // FIXME: support MHD_HTTP_STATUS_PROCESSING ? 594 /* Reset connection after complete reply */ 595 mhd_stream_finish_req_serving ( \ 596 c, 597 mhd_CONN_KEEPALIVE_POSSIBLE == c->conn_reuse 598 && ! c->discard_request 599 && ! c->sk.state.rmt_shut_wr); 600 continue; 601 #ifdef MHD_SUPPORT_UPGRADE 602 case mhd_HTTP_STAGE_UPGRADING: 603 if (mhd_upgrade_finish_switch_to_upgraded (c)) 604 return true; /* Do not close connection */ 605 mhd_assert (mhd_HTTP_STAGE_PRE_CLOSING == c->stage); 606 continue; 607 case mhd_HTTP_STAGE_UPGRADED: 608 mhd_assert (0 && "Should be unreachable"); 609 mhd_UNREACHABLE (); 610 break; 611 case mhd_HTTP_STAGE_UPGRADED_CLEANING: 612 mhd_assert (0 && "Should be unreachable"); 613 mhd_UNREACHABLE (); 614 break; 615 #endif /* MHD_SUPPORT_UPGRADE */ 616 case mhd_HTTP_STAGE_PRE_CLOSING: 617 return false; 618 case mhd_HTTP_STAGE_CLOSED: 619 mhd_assert (0 && "Should be unreachable"); 620 mhd_UNREACHABLE (); 621 break; 622 default: 623 mhd_assert (0 && "Impossible value"); 624 mhd_UNREACHABLE (); 625 break; 626 } 627 break; 628 } 629 630 mhd_assert (mhd_HTTP_STAGE_CLOSED != c->stage); 631 632 if (mhd_HTTP_STAGE_PRE_CLOSING == c->stage) 633 { 634 mhd_assert (0 && "Pre-closing should be already caught in the loop"); 635 mhd_UNREACHABLE (); 636 return false; 637 } 638 639 if (c->suspended) 640 { 641 /* Do not perform any network activity while suspended */ 642 c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS; 643 644 mhd_conn_mark_unready (c, d); 645 mhd_conn_remove_from_timeout_lists (c); 646 #ifdef mhd_DEBUG_SUSPEND_RESUME 647 fprintf (stderr, 648 "%%%%%% Connection suspended, FD: %2llu\n", 649 (unsigned long long) c->sk.fd); 650 #endif /* mhd_DEBUG_SUSPEND_RESUME */ 651 return true; 652 } 653 654 if ((c->sk.state.rmt_shut_wr) && (mhd_HTTP_STAGE_START_REPLY > c->stage)) 655 { 656 mhd_conn_start_closing (c, 657 (mhd_HTTP_STAGE_INIT == c->stage) ? 658 mhd_CONN_CLOSE_HTTP_COMPLETED : 659 mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY, 660 NULL); 661 return false; 662 } 663 664 if (mhd_stream_is_timeout_expired (c)) // TODO: centralise timeout checks 665 { 666 mhd_conn_start_closing_timedout (c); 667 return false; 668 } 669 670 if (! update_active_state (c)) 671 return false; 672 673 return true; 674 }