| 28 | namespace DB |
| 29 | { |
| 30 | HTTPServerRequest::HTTPServerRequest(HTTPContextPtr context, HTTPServerResponse & response, Poco::Net::HTTPServerSession & session, const ProfileEvents::Event & read_event) |
| 31 | : max_uri_size(context->getMaxUriSize()) |
| 32 | , max_fields_number(context->getMaxFields()) |
| 33 | , max_field_name_size(context->getMaxFieldNameSize()) |
| 34 | , max_field_value_size(context->getMaxFieldValueSize()) |
| 35 | , max_request_header_size(context->getMaxRequestHeaderSize()) |
| 36 | { |
| 37 | response.attachRequest(this); |
| 38 | |
| 39 | /// Now that we know socket is still connected, obtain addresses |
| 40 | client_address = session.clientAddress(); |
| 41 | server_address = session.serverAddress(); |
| 42 | secure = session.socket().secure(); |
| 43 | |
| 44 | auto receive_timeout = context->getReceiveTimeout(); |
| 45 | auto send_timeout = context->getSendTimeout(); |
| 46 | auto headers_read_timeout = context->getHeadersReadTimeout(); |
| 47 | |
| 48 | /// Use the smaller of headers_read_timeout and receive_timeout during header parsing |
| 49 | /// to enforce a total deadline on the entire handshake phase. |
| 50 | auto effective_timeout = (headers_read_timeout > Poco::Timespan(0) && |
| 51 | (receive_timeout <= Poco::Timespan(0) || headers_read_timeout < receive_timeout)) |
| 52 | ? headers_read_timeout : receive_timeout; |
| 53 | |
| 54 | session.socket().setReceiveTimeout(effective_timeout); |
| 55 | session.socket().setSendTimeout(send_timeout); |
| 56 | |
| 57 | auto socket_in = std::make_unique<ReadBufferFromPocoSocket>(session.socket(), read_event); |
| 58 | socket = session.socket().impl(); |
| 59 | |
| 60 | /// Wrap the socket buffer with a deadline check if configured. |
| 61 | /// The deadline is enforced in DeadlineReadBuffer::nextImpl on every buffer refill, |
| 62 | /// which protects all parsing (request line, URI, headers) automatically. |
| 63 | if (headers_read_timeout > Poco::Timespan(0)) |
| 64 | { |
| 65 | auto deadline = std::chrono::steady_clock::now() |
| 66 | + std::chrono::microseconds(headers_read_timeout.totalMicroseconds()); |
| 67 | DeadlineReadBuffer deadline_in(*socket_in, deadline); |
| 68 | readRequest(deadline_in); /// Try parse according to RFC7230 |
| 69 | } |
| 70 | else |
| 71 | { |
| 72 | readRequest(*socket_in); /// Try parse according to RFC7230 |
| 73 | } |
| 74 | |
| 75 | /// Restore the original receive timeout for body reads. |
| 76 | session.socket().setReceiveTimeout(receive_timeout); |
| 77 | |
| 78 | /// Build the body stream from the underlying socket buffer (not the deadline wrapper). |
| 79 | auto in = std::move(socket_in); |
| 80 | |
| 81 | /// If a client crashes, most systems will gracefully terminate the connection with FIN just like it's done on close(). |
| 82 | /// So we will get 0 from recv(...) and will not be able to understand that something went wrong (well, we probably |
| 83 | /// will get RST later on attempt to write to the socket that closed on the other side, but it will happen when the query is finished). |
| 84 | /// If we are extremely unlucky and data format is TSV, for example, then we may stop parsing exactly between rows |
| 85 | /// and decide that it's EOF (but it is not). It may break deduplication, because clients cannot control it |
| 86 | /// and retry with exactly the same (incomplete) set of rows. |
| 87 | /// That's why we have to check body size if it's provided. |
nothing calls this directly
no test coverage detected