http-server-request.c revision 23bdbb7b1831785c6ba6df190f6369da882d2b9d
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter/* Copyright (c) 2013-2016 Dovecot authors, see the included COPYING file */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "lib.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "ioloop.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "ostream.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "istream-private.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "http-server-private.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter/*
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter * Logging
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstatic inline void
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterhttp_server_request_debug(struct http_server_request *req,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter const char *format, ...) ATTR_FORMAT(2, 3);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstatic inline void
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterhttp_server_request_debug(struct http_server_request *req,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter const char *format, ...)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter struct http_server *server = req->server;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter va_list args;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (server->set.debug) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter va_start(args, format);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_debug("http-server: request %s: %s",
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter http_server_request_label(req),
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter t_strdup_vprintf(format, args));
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter va_end(args);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter/*
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter * Request
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstruct http_server_request *
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterhttp_server_request_new(struct http_server_connection *conn)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter static unsigned int id_counter = 0;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter pool_t pool;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter struct http_server_request *req;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter pool = pool_alloconly_create(MEMPOOL_GROWING"http_server_request", 4096);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req = p_new(pool, struct http_server_request, 1);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->pool = pool;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->refcount = 1;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->conn = conn;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->server = conn->server;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->id = ++id_counter;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter http_server_connection_add_request(conn, req);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return req;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid http_server_request_ref(struct http_server_request *req)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(req->refcount > 0);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->refcount++;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterbool http_server_request_unref(struct http_server_request **_req)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter struct http_server_request *req = *_req;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter struct http_server_connection *conn = req->conn;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(req->refcount > 0);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter *_req = NULL;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (--req->refcount > 0)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return TRUE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter http_server_request_debug(req, "Free");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter http_server_connection_remove_request(conn, req);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (req->destroy_callback != NULL) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->destroy_callback(req->destroy_context);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->destroy_callback = NULL;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (req->response != NULL)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter http_server_response_free(req->response);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter pool_unref(&req->pool);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid http_server_request_destroy(struct http_server_request **_req)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter struct http_server_request *req = *_req;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter struct http_server *server = req->server;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter http_server_request_debug(req, "Destroy");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* just make sure the request ends in a proper state */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (server->ioloop != NULL)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter io_loop_stop(server->ioloop);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (req->delay_destroy) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->destroy_pending = TRUE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter } else if (req->destroy_callback != NULL) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter void (*callback)(void *) = req->destroy_callback;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->destroy_callback = NULL;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter callback(req->destroy_context);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter http_server_request_unref(_req);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter}
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Waltervoid http_server_request_set_destroy_callback(struct http_server_request *req,
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter void (*callback)(void *),
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter void *context)
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter{
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter req->destroy_callback = callback;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter req->destroy_context = context;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter}
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Waltervoid http_server_request_abort(struct http_server_request **_req,
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter const char *reason)
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter{
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter struct http_server_request *req = *_req;
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter struct http_server_connection *conn = req->conn;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter if (req->state >= HTTP_SERVER_REQUEST_STATE_FINISHED)
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter return;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter http_server_request_debug(req, "Abort");
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter req->conn = NULL;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) {
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter if (conn != NULL) {
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter http_server_connection_remove_request(conn, req);
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter if (!conn->closed) {
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter /* send best-effort response if appropriate */
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter if (!conn->output_locked &&
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter req->state >= HTTP_SERVER_REQUEST_STATE_PROCESSING &&
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter req->state < HTTP_SERVER_REQUEST_STATE_SENT_RESPONSE) {
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter static const char *response =
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter "HTTP/1.1 500 Internal Server Error\r\n"
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter "Content-Length: 0\r\n"
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter "\r\n";
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter (void)o_stream_send(conn->conn.output,
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter response, strlen(response));
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter }
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter /* close the connection */
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter http_server_connection_close(&conn, reason);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter }
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter }
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter }
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter if (req->response != NULL &&
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter !req->response->payload_blocking) {
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter http_server_response_free(req->response);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter req->response = NULL;
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter }
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter http_server_request_destroy(_req);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter}
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walterconst struct http_request *
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walterhttp_server_request_get(struct http_server_request *req)
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter{
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter return &req->req;
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter}
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter
c2cc119de8eac712c040b3993f41c967ff2278deStef Walterpool_t
c2cc119de8eac712c040b3993f41c967ff2278deStef Walterhttp_server_request_get_pool(struct http_server_request *req)
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter{
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter return req->pool;
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter}
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter
c2cc119de8eac712c040b3993f41c967ff2278deStef Walterstruct http_server_response *
c2cc119de8eac712c040b3993f41c967ff2278deStef Walterhttp_server_request_get_response(struct http_server_request *req)
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter{
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter return req->response;
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterint http_server_request_get_auth(struct http_server_request *req,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter struct http_auth_credentials *credentials)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter const char *auth;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth = http_request_header_get(&req->req, "Authorization");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (auth == NULL)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return 0;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (http_auth_parse_credentials
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter ((const unsigned char *)auth, strlen(auth), credentials) < 0)
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter return -1;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return 1;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterbool http_server_request_is_finished(struct http_server_request *req)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return req->response != NULL ||
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->state == HTTP_SERVER_REQUEST_STATE_ABORTED;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid http_server_request_halt_payload(struct http_server_request *req)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(req->state <= HTTP_SERVER_REQUEST_STATE_QUEUED);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->payload_halted = TRUE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid http_server_request_continue_payload(struct http_server_request *req)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(req->state <= HTTP_SERVER_REQUEST_STATE_QUEUED);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->payload_halted = FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (req->req.expect_100_continue && !req->sent_100_continue)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter http_server_connection_trigger_responses(req->conn);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid http_server_request_ready_to_respond(struct http_server_request *req)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter http_server_request_debug(req, "Ready to respond");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter req->state = HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter http_server_connection_trigger_responses(req->conn);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid http_server_request_submit_response(struct http_server_request *req)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter struct http_server_connection *conn = req->conn;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(conn != NULL && req->response != NULL && req->response->submitted);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter switch (req->state) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter case HTTP_SERVER_REQUEST_STATE_NEW:
case HTTP_SERVER_REQUEST_STATE_QUEUED:
case HTTP_SERVER_REQUEST_STATE_PAYLOAD_IN:
case HTTP_SERVER_REQUEST_STATE_PROCESSING:
if (!http_server_request_is_complete(req)) {
http_server_request_debug(req, "Not ready to respond");
req->state = HTTP_SERVER_REQUEST_STATE_SUBMITTED_RESPONSE;
break;
}
http_server_request_ready_to_respond(req);
break;
case HTTP_SERVER_REQUEST_STATE_ABORTED:
break;
default:
i_unreached();
}
}
void http_server_request_finished(struct http_server_request *req)
{
struct http_server_connection *conn = req->conn;
struct http_server_response *resp = req->response;
http_server_tunnel_callback_t tunnel_callback = resp->tunnel_callback;
void *tunnel_context = resp->tunnel_context;
http_server_request_debug(req, "Finished");
i_assert(req->state < HTTP_SERVER_REQUEST_STATE_FINISHED);
req->state = HTTP_SERVER_REQUEST_STATE_FINISHED;
http_server_connection_remove_request(conn, req);
conn->stats.response_count++;
if (tunnel_callback == NULL && (req->req.connection_close || resp->close)) {
if (resp->close) {
http_server_connection_close(&conn,
t_strdup_printf("Server closed connection: %u %s",
resp->status, resp->reason));
} else {
http_server_connection_close(&conn,
"Client requested connection close");
}
http_server_request_destroy(&req);
return;
}
http_server_request_destroy(&req);
if (tunnel_callback != NULL) {
http_server_connection_tunnel(&conn, tunnel_callback, tunnel_context);
return;
}
http_server_connection_trigger_responses(conn);
}
static struct http_server_response *
http_server_request_create_fail_response(struct http_server_request *req,
unsigned int status, const char *reason)
{
struct http_server_response *resp;
req->failed = TRUE;
resp = http_server_response_create(req, status, reason);
http_server_response_add_header
(resp, "Content-Type", "text/plain; charset=utf-8");
reason = t_strconcat(reason, "\r\n", NULL);
http_server_response_set_payload_data
(resp, (const unsigned char *)reason, strlen(reason));
return resp;
}
static void
http_server_request_fail_full(struct http_server_request *req,
unsigned int status, const char *reason, bool close)
{
struct http_server_response *resp;
req->failed = TRUE;
resp = http_server_request_create_fail_response(req, status, reason);
if (close)
http_server_response_submit_close(resp);
else
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);
}
void http_server_request_fail_auth(struct http_server_request *req,
const char *reason, const struct http_auth_challenge *chlng)
{
struct http_server_response *resp;
req->failed = TRUE;
if (reason == NULL)
reason = "Unauthenticated";
resp = http_server_request_create_fail_response(req, 401, reason);
http_server_response_add_auth(resp, chlng);
http_server_response_submit(resp);
}
void http_server_request_fail_auth_basic(struct http_server_request *req,
const char *reason, const char *realm)
{
struct http_auth_challenge chlng;
http_auth_basic_challenge_init(&chlng, realm);
http_server_request_fail_auth(req, reason, &chlng);
}
/*
* Payload input stream
*/
struct http_server_istream {
struct istream_private istream;
struct http_server_request *req;
ssize_t read_status;
};
static void
http_server_istream_switch_ioloop(struct istream_private *stream)
{
struct http_server_istream *hsristream =
(struct http_server_istream *)stream;
if (hsristream->istream.istream.blocking)
return;
http_server_connection_switch_ioloop(hsristream->req->conn);
}
static void
http_server_istream_read_any(struct http_server_istream *hsristream)
{
struct istream_private *stream = &hsristream->istream;
struct http_server *server = hsristream->req->server;
ssize_t ret;
if ((ret=i_stream_read_copy_from_parent
(&stream->istream)) > 0) {
hsristream->read_status = ret;
io_loop_stop(server->ioloop);
}
}
static ssize_t
http_server_istream_read(struct istream_private *stream)
{
struct http_server_istream *hsristream =
(struct http_server_istream *)stream;
struct http_server_request *req = hsristream->req;
struct http_server *server;
struct http_server_connection *conn;
bool blocking = stream->istream.blocking;
ssize_t ret;
if (req == NULL) {
/* request already gone (we shouldn't get here) */
stream->istream.stream_errno = EINVAL;
return -1;
}
i_stream_seek(stream->parent, stream->parent_start_offset +
stream->istream.v_offset);
server = hsristream->req->server;
conn = hsristream->req->conn;
ret = i_stream_read_copy_from_parent(&stream->istream);
if (ret == 0 && blocking) {
struct ioloop *prev_ioloop = current_ioloop;
struct io *io;
http_server_connection_ref(conn);
http_server_request_ref(req);
i_assert(server->ioloop == NULL);
server->ioloop = io_loop_create();
http_server_connection_switch_ioloop(conn);
if (blocking && req->req.expect_100_continue &&
!req->sent_100_continue)
http_server_connection_trigger_responses(conn);
hsristream->read_status = 0;
io = io_add_istream(&stream->istream,
http_server_istream_read_any, hsristream);
while (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED &&
hsristream->read_status == 0) {
io_loop_run(server->ioloop);
}
io_remove(&io);
io_loop_set_current(prev_ioloop);
http_server_connection_switch_ioloop(conn);
io_loop_set_current(server->ioloop);
io_loop_destroy(&server->ioloop);
ret = hsristream->read_status;
if (!http_server_request_unref(&req))
hsristream->req = NULL;
http_server_connection_unref(&conn);
}
return ret;
}
static void
http_server_istream_destroy(struct iostream_private *stream)
{
struct http_server_istream *hsristream =
(struct http_server_istream *)stream;
uoff_t v_offset;
v_offset = hsristream->istream.parent_start_offset +
hsristream->istream.istream.v_offset;
if (hsristream->istream.parent->seekable ||
v_offset > hsristream->istream.parent->v_offset) {
/* get to same position in parent stream */
i_stream_seek(hsristream->istream.parent, v_offset);
}
}
struct istream *
http_server_request_get_payload_input(struct http_server_request *req,
bool blocking)
{
struct http_server_istream *hsristream;
struct istream *payload = req->req.payload;
i_assert(req->payload_input == NULL);
hsristream = i_new(struct http_server_istream, 1);
hsristream->req = req;
hsristream->istream.max_buffer_size =
payload->real_stream->max_buffer_size;
hsristream->istream.stream_size_passthrough = TRUE;
hsristream->istream.read = http_server_istream_read;
hsristream->istream.switch_ioloop = http_server_istream_switch_ioloop;
hsristream->istream.iostream.destroy = http_server_istream_destroy;
hsristream->istream.istream.readable_fd = FALSE;
hsristream->istream.istream.blocking = blocking;
hsristream->istream.istream.seekable = FALSE;
req->payload_input = i_stream_create
(&hsristream->istream, payload, i_stream_get_fd(payload));
i_stream_unref(&req->req.payload);
return req->payload_input;
}