http-server-request.c revision 95e0b82fdff1bb511067d703bb8b67c22f242c38
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen/* Copyright (c) 2013-2014 Dovecot authors, see the included COPYING file */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "llist.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "http-server-private.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstruct http_server_request *
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenhttp_server_request_new(struct http_server_connection *conn)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen pool_t pool;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct http_server_request *req;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen pool = pool_alloconly_create("http_message", 4096);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req = p_new(pool, struct http_server_request, 1);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->pool = pool;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->refcount = 1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->conn = conn;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->server = conn->server;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen DLLIST2_APPEND(&conn->request_queue_head, &conn->request_queue_tail, req);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen conn->request_queue_count++;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return req;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid http_server_request_ref(struct http_server_request *req)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->refcount++;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
4ea6c43a08b37f270bd54b5809142246fd118263Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid http_server_request_unref(struct http_server_request **_req)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct http_server_request *req = *_req;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct http_server_connection *conn = req->conn;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen i_assert(req->refcount > 0);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (--req->refcount > 0)
4ea6c43a08b37f270bd54b5809142246fd118263Timo Sirainen return;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen DLLIST2_REMOVE(&conn->request_queue_head, &conn->request_queue_tail, req);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen conn->request_queue_count--;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (req->destroy_callback != NULL) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->destroy_callback(req->destroy_context);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->destroy_callback = NULL;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (req->response != NULL)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_response_free(req->response);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen pool_unref(&req->pool);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen *_req = NULL;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid http_server_request_set_destroy_callback(struct http_server_request *req,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen void (*callback)(void *),
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen void *context)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->destroy_callback = callback;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->destroy_context = context;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid http_server_request_abort(struct http_server_request **_req)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct http_server_request *req = *_req;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct http_server_connection *conn = req->conn;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen DLLIST2_REMOVE(&conn->request_queue_head, &conn->request_queue_tail, req);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen conn->request_queue_count--;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (req->response != NULL)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_response_free(req->response);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->response = NULL;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->conn = conn;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_request_unref(_req);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenconst struct http_request *
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenhttp_server_request_get(struct http_server_request *req)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return &req->req;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenpool_t
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenhttp_server_request_get_pool(struct http_server_request *req)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return req->pool;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid http_server_request_halt_payload(struct http_server_request *req)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen i_assert(req->state <= HTTP_SERVER_REQUEST_STATE_QUEUED);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen req->payload_halted = TRUE;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid http_server_request_continue_payload(struct http_server_request *req)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen i_assert(req->state <= HTTP_SERVER_REQUEST_STATE_QUEUED);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen req->payload_halted = FALSE;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (req->req.expect_100_continue && !req->sent_100_continue)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_connection_send_responses(req->conn);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid http_server_request_ready_to_respond(struct http_server_request *req)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_connection_send_responses(req->conn);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid http_server_request_submit_response(struct http_server_request *req)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct http_server_connection *conn = req->conn;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen i_assert(conn != NULL && req->response != NULL && req->response->submitted);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen switch (req->state) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen case HTTP_SERVER_REQUEST_STATE_NEW:
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen case HTTP_SERVER_REQUEST_STATE_QUEUED:
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen case HTTP_SERVER_REQUEST_STATE_PAYLOAD_IN:
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen case HTTP_SERVER_REQUEST_STATE_PROCESSING:
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (!http_server_request_is_complete(req)) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_SUBMITTED_RESPONSE;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen break;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_request_ready_to_respond(req);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen break;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen case HTTP_SERVER_REQUEST_STATE_ABORTED:
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen break;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen default:
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen i_unreached();
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid http_server_request_finished(struct http_server_request *req)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct http_server_connection *conn = req->conn;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct http_server_response *resp = req->response;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_tunnel_callback_t tunnel_callback = resp->tunnel_callback;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen void *tunnel_context = resp->tunnel_context;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen i_assert(req->state < HTTP_SERVER_REQUEST_STATE_FINISHED);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_FINISHED;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen DLLIST2_REMOVE(&conn->request_queue_head, &conn->request_queue_tail, req);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen conn->request_queue_count--;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen conn->stats.response_count++;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (tunnel_callback == NULL && (req->req.connection_close || resp->close)) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (resp->close) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_connection_close(&conn,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen t_strdup_printf("Server closed connection: %u %s",
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen resp->status, resp->reason));
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen } else {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_connection_close(&conn,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen "Client requested connection close");
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_request_unref(&req);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_request_unref(&req);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (tunnel_callback != NULL) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_connection_tunnel(&conn, tunnel_callback, tunnel_context);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_connection_send_responses(conn);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic void
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenhttp_server_request_fail_full(struct http_server_request *req,
f8da06de93e28b5d3e039a427cdde7e1e15daec8Timo Sirainen unsigned int status, const char *reason, bool close)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct http_server_response *resp;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen resp = http_server_response_create(req, status, reason);
378d924da5853145a6df9a299074f04be69986c7Timo Sirainen http_server_response_add_header
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen (resp, "Content-Type", "text/plain; charset=utf-8");
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen reason = t_strconcat(reason, "\r\n", NULL);
f8da06de93e28b5d3e039a427cdde7e1e15daec8Timo Sirainen http_server_response_set_payload_data
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen (resp, (const unsigned char *)reason, strlen(reason));
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (close)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_response_submit_close(resp);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen else
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen http_server_response_submit(resp);
}
void http_server_request_fail(struct http_server_request *req,
unsigned int status, const char *reason)
{
http_server_request_fail_full(req, status, reason,
req->conn->input_broken);
}
void http_server_request_fail_close(struct http_server_request *req,
unsigned int status, const char *reason)
{
http_server_request_fail_full(req, status, reason, TRUE);
}