http-server-request.c revision 38af46387e565053adf6c47f7f6871676d685de8
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainenstatic inline void
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainenhttp_server_request_debug(struct http_server_request *req,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic inline void
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenhttp_server_request_debug(struct http_server_request *req,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *format, ...)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic inline void
2d3aac5be07b96f72cf0551fac35ac74a4f07770Timo Sirainenhttp_server_request_error(struct http_server_request *req,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic inline void
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenhttp_server_request_error(struct http_server_request *req,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen const char *format, ...)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic inline void
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenhttp_server_request_client_error(struct http_server_request *req,
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainenstatic inline void
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainenhttp_server_request_client_error(struct http_server_request *req,
fb2e0bbb7737f3223b16aa41e4b40fb0cd5f288fTimo Sirainen const char *format, ...)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenhttp_server_request_new(struct http_server_connection *conn)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen static unsigned int id_counter = 0;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen pool = pool_alloconly_create(MEMPOOL_GROWING"http_server_request", 4096);
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen req = p_new(pool, struct http_server_request, 1);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen http_server_connection_add_request(conn, req);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenvoid http_server_request_ref(struct http_server_request *req)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenbool http_server_request_unref(struct http_server_request **_req)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen struct http_server_connection *conn = req->conn;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen http_server_connection_remove_request(conn, req);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid http_server_request_destroy(struct http_server_request **_req)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* just make sure the request ends in a proper state */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen void (*callback)(void *) = req->destroy_callback;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#undef http_server_request_set_destroy_callback
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid http_server_request_set_destroy_callback(struct http_server_request *req,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen void (*callback)(void *),
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid http_server_request_abort(struct http_server_request **_req,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server_connection *conn = req->conn;
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen if (req->state >= HTTP_SERVER_REQUEST_STATE_FINISHED)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_connection_remove_request(conn, req);
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen /* send best-effort response if appropriate */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->state >= HTTP_SERVER_REQUEST_STATE_PROCESSING &&
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->state < HTTP_SERVER_REQUEST_STATE_SENT_RESPONSE) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen static const char *response =
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "HTTP/1.1 500 Internal Server Error\r\n"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "Content-Length: 0\r\n"
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen /* close the connection */
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenhttp_server_request_get(struct http_server_request *req)
58eb2cb24dbeadd94500670acad7ceb1c8b0d9b4Timo Sirainenhttp_server_request_get_pool(struct http_server_request *req)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenhttp_server_request_get_response(struct http_server_request *req)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint http_server_request_get_auth(struct http_server_request *req,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen auth = http_request_header_get(&req->req, "Authorization");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ((const unsigned char *)auth, strlen(auth), credentials) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenbool http_server_request_is_finished(struct http_server_request *req)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen req->state == HTTP_SERVER_REQUEST_STATE_ABORTED;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenbool http_server_request_is_complete(struct http_server_request *req)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return (req->failed || req->conn->input_broken ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (req->next != NULL && !http_server_request_is_new(req->next)) ||
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen !http_server_connection_pending_payload(req->conn));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid http_server_request_halt_payload(struct http_server_request *req)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(req->state <= HTTP_SERVER_REQUEST_STATE_QUEUED);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenvoid http_server_request_continue_payload(struct http_server_request *req)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(req->state <= HTTP_SERVER_REQUEST_STATE_QUEUED);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (req->req.expect_100_continue && !req->sent_100_continue)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen http_server_connection_trigger_responses(req->conn);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid http_server_request_ready_to_respond(struct http_server_request *req)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen http_server_request_debug(req, "Ready to respond");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen http_server_connection_trigger_responses(req->conn);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenvoid http_server_request_submit_response(struct http_server_request *req)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen struct http_server_connection *conn = req->conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(conn != NULL && req->response != NULL && req->response->submitted);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (conn->payload_handler != NULL && conn->payload_handler->req == req)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen http_server_payload_handler_destroy(&conn->payload_handler);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_request_debug(req, "Not ready to respond");
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_SUBMITTED_RESPONSE;
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen case HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND:
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen http_server_connection_trigger_responses(req->conn);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid http_server_request_finished(struct http_server_request *req)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server_connection *conn = req->conn;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server_response *resp = req->response;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_tunnel_callback_t tunnel_callback = resp->tunnel_callback;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_assert(req->state < HTTP_SERVER_REQUEST_STATE_FINISHED);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_FINISHED;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_connection_remove_request(conn, req);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (tunnel_callback == NULL && (req->req.connection_close || resp->close)) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen t_strdup_printf("Server closed connection: %u %s",
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "Client requested connection close");
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen http_server_connection_tunnel(&conn, tunnel_callback, tunnel_context);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_connection_trigger_responses(conn);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenhttp_server_request_create_fail_response(struct http_server_request *req,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_assert(status / 100 != 1 && status != 204 && status != 304);
bf301a34ffbfd049be583094019b2644884b6d0bTimo Sirainen resp = http_server_response_create(req, status, reason);
51ff0538ab38def8045b3f7feb43e1e069cbe037Timo Sirainen if (!http_request_method_is(&req->req, "HEAD")) {
bf301a34ffbfd049be583094019b2644884b6d0bTimo Sirainen (resp, "Content-Type", "text/plain; charset=utf-8");
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen (resp, (const unsigned char *)reason, strlen(reason));
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenhttp_server_request_fail_full(struct http_server_request *req,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen unsigned int status, const char *reason, bool close)
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen resp = http_server_request_create_fail_response(req, status, reason);
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainenvoid http_server_request_fail(struct http_server_request *req,
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen http_server_request_fail_full(req, status, reason,
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainenvoid http_server_request_fail_close(struct http_server_request *req,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen http_server_request_fail_full(req, status, reason, TRUE);
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainenvoid http_server_request_fail_auth(struct http_server_request *req,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *reason, const struct http_auth_challenge *chlng)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen resp = http_server_request_create_fail_response(req, 401, reason);
511a7ccd55cea57c9d953920b7d651720128ada9Timo Sirainenvoid http_server_request_fail_auth_basic(struct http_server_request *req,
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen http_auth_basic_challenge_init(&chlng, realm);
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen http_server_request_fail_auth(req, reason, &chlng);
511a7ccd55cea57c9d953920b7d651720128ada9Timo Sirainen * Payload input stream
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenhttp_server_istream_switch_ioloop(struct istream_private *stream)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen http_server_connection_switch_ioloop(hsristream->req->conn);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenhttp_server_istream_read_any(struct http_server_istream *hsristream)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct istream_private *stream = &hsristream->istream;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server *server = hsristream->req->server;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenhttp_server_istream_read(struct istream_private *stream)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen struct http_server_request *req = hsristream->req;
return ret;
struct istream *
bool blocking)
struct http_server_payload_handler_pump {
void (*callback)(void *);
void *context;
if (success) {
int ret;
if (ret < 0) {
struct http_server_payload_handler_raw {
void *context;