http-server-request.c revision 38af46387e565053adf6c47f7f6871676d685de8
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "ioloop.h"
65cca8364f483126b396aeb2036dc879ad45ab8dTimo Sirainen#include "ostream.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "istream-private.h"
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen#include "http-server-private.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen/*
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen * Logging
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainenstatic inline void
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainenhttp_server_request_debug(struct http_server_request *req,
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen const char *format, ...) ATTR_FORMAT(2, 3);
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenstatic inline void
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainenhttp_server_request_debug(struct http_server_request *req,
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen const char *format, ...)
13d98ffa534f2e7d04a832c9d0153fc9c568b878Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct http_server *server = req->server;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen va_list args;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (server->set.debug) {
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen va_start(args, format);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_debug("http-server: request %s: %s",
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen http_server_request_label(req),
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen t_strdup_vprintf(format, args));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen va_end(args);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic inline void
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenhttp_server_request_error(struct http_server_request *req,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *format, ...) ATTR_FORMAT(2, 3);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic inline void
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainenhttp_server_request_error(struct http_server_request *req,
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen const char *format, ...)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen va_list args;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen va_start(args, format);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen i_error("http-server: request %s: %s",
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen http_server_request_label(req),
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen t_strdup_vprintf(format, args));
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen va_end(args);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen}
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic inline void
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenhttp_server_request_client_error(struct http_server_request *req,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *format, ...) ATTR_FORMAT(2, 3);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic inline void
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenhttp_server_request_client_error(struct http_server_request *req,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *format, ...)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen va_list args;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen va_start(args, format);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_info("http-server: request %s: %s",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen http_server_request_label(req),
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen t_strdup_vprintf(format, args));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen va_end(args);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen/*
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen * Request
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen */
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstruct http_server_request *
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenhttp_server_request_new(struct http_server_connection *conn)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen static unsigned int id_counter = 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool_t pool;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct http_server_request *req;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool = pool_alloconly_create(MEMPOOL_GROWING"http_server_request", 4096);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen req = p_new(pool, struct http_server_request, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen req->pool = pool;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen req->refcount = 1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen req->conn = conn;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen req->server = conn->server;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen req->id = ++id_counter;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen http_server_connection_add_request(conn, req);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return req;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenvoid http_server_request_ref(struct http_server_request *req)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen{
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen i_assert(req->refcount > 0);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen req->refcount++;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen}
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenbool http_server_request_unref(struct http_server_request **_req)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen{
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct http_server_request *req = *_req;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct http_server_connection *conn = req->conn;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen i_assert(req->refcount > 0);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen *_req = NULL;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen if (--req->refcount > 0)
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen return TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen http_server_request_debug(req, "Free");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen http_server_connection_remove_request(conn, req);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (req->destroy_callback != NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen req->destroy_callback(req->destroy_context);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen req->destroy_callback = NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (req->response != NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen http_server_response_free(req->response);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool_unref(&req->pool);
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen return FALSE;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen}
63e207529879438e9f4412d97cdc34bdc82a3702Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenvoid http_server_request_destroy(struct http_server_request **_req)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen{
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen struct http_server_request *req = *_req;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen struct http_server *server = req->server;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen http_server_request_debug(req, "Destroy");
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* just make sure the request ends in a proper state */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (server->ioloop != NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen io_loop_stop(server->ioloop);
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (req->delay_destroy) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen req->destroy_pending = TRUE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen } else if (req->destroy_callback != NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen void (*callback)(void *) = req->destroy_callback;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen req->destroy_callback = NULL;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen callback(req->destroy_context);
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen http_server_request_unref(_req);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen#undef http_server_request_set_destroy_callback
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainenvoid http_server_request_set_destroy_callback(struct http_server_request *req,
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen void (*callback)(void *),
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen void *context)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen{
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen req->destroy_callback = callback;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen req->destroy_context = context;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen}
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainenvoid http_server_request_abort(struct http_server_request **_req,
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen const char *reason)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct http_server_request *req = *_req;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct http_server_connection *conn = req->conn;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen if (req->state >= HTTP_SERVER_REQUEST_STATE_FINISHED)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen http_server_request_debug(req, "Abort");
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen req->conn = NULL;
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) {
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen if (conn != NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen http_server_connection_remove_request(conn, req);
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!conn->closed) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* send best-effort response if appropriate */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!conn->output_locked &&
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen req->state >= HTTP_SERVER_REQUEST_STATE_PROCESSING &&
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen req->state < HTTP_SERVER_REQUEST_STATE_SENT_RESPONSE) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen static const char *response =
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "HTTP/1.1 500 Internal Server Error\r\n"
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "Content-Length: 0\r\n"
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen "\r\n";
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen (void)o_stream_send(conn->conn.output,
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen response, strlen(response));
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen }
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen /* close the connection */
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen http_server_connection_close(&conn, reason);
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk }
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen if (req->response != NULL &&
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk !req->response->payload_blocking) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk http_server_response_free(req->response);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk req->response = NULL;
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen }
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen http_server_request_destroy(_req);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen}
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainenconst struct http_request *
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainenhttp_server_request_get(struct http_server_request *req)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen return &req->req;
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen}
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainenpool_t
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenhttp_server_request_get_pool(struct http_server_request *req)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return req->pool;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen}
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstruct http_server_response *
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenhttp_server_request_get_response(struct http_server_request *req)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen{
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return req->response;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen}
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenint http_server_request_get_auth(struct http_server_request *req,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen struct http_auth_credentials *credentials)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen{
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen const char *auth;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen auth = http_request_header_get(&req->req, "Authorization");
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (auth == NULL)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return 0;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (http_auth_parse_credentials
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen ((const unsigned char *)auth, strlen(auth), credentials) < 0)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return -1;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return 1;
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen}
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenbool http_server_request_is_finished(struct http_server_request *req)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen{
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return req->response != NULL ||
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen req->state == HTTP_SERVER_REQUEST_STATE_ABORTED;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen}
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenbool http_server_request_is_complete(struct http_server_request *req)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen{
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return (req->failed || req->conn->input_broken ||
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen (req->next != NULL && !http_server_request_is_new(req->next)) ||
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen !http_server_connection_pending_payload(req->conn));
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainen}
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenvoid http_server_request_halt_payload(struct http_server_request *req)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen{
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen i_assert(req->state <= HTTP_SERVER_REQUEST_STATE_QUEUED);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen req->payload_halted = TRUE;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen}
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenvoid http_server_request_continue_payload(struct http_server_request *req)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen{
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen i_assert(req->state <= HTTP_SERVER_REQUEST_STATE_QUEUED);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen req->payload_halted = FALSE;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (req->req.expect_100_continue && !req->sent_100_continue)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen http_server_connection_trigger_responses(req->conn);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen}
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenvoid http_server_request_ready_to_respond(struct http_server_request *req)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen http_server_request_debug(req, "Ready to respond");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND;
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen http_server_connection_trigger_responses(req->conn);
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen}
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid http_server_request_submit_response(struct http_server_request *req)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen struct http_server_connection *conn = req->conn;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen i_assert(conn != NULL && req->response != NULL && req->response->submitted);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen http_server_request_ref(req);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen if (conn->payload_handler != NULL && conn->payload_handler->req == req)
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen http_server_payload_handler_destroy(&conn->payload_handler);
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen switch (req->state) {
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen case HTTP_SERVER_REQUEST_STATE_NEW:
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen case HTTP_SERVER_REQUEST_STATE_QUEUED:
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen case HTTP_SERVER_REQUEST_STATE_PAYLOAD_IN:
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen case HTTP_SERVER_REQUEST_STATE_PROCESSING:
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (!http_server_request_is_complete(req)) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen http_server_request_debug(req, "Not ready to respond");
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_SUBMITTED_RESPONSE;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen break;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen }
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen http_server_request_ready_to_respond(req);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen break;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen case HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND:
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen http_server_connection_trigger_responses(req->conn);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen break;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen case HTTP_SERVER_REQUEST_STATE_ABORTED:
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen break;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen default:
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen i_unreached();
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen http_server_request_unref(&req);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen}
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenvoid http_server_request_finished(struct http_server_request *req)
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen{
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen struct http_server_connection *conn = req->conn;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen struct http_server_response *resp = req->response;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen http_server_tunnel_callback_t tunnel_callback = resp->tunnel_callback;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen void *tunnel_context = resp->tunnel_context;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen http_server_request_debug(req, "Finished");
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen i_assert(req->state < HTTP_SERVER_REQUEST_STATE_FINISHED);
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_FINISHED;
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen http_server_connection_remove_request(conn, req);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen conn->stats.response_count++;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (tunnel_callback == NULL && (req->req.connection_close || resp->close)) {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (resp->close) {
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen http_server_connection_close(&conn,
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen t_strdup_printf("Server closed connection: %u %s",
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen resp->status, resp->reason));
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen } else {
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen http_server_connection_close(&conn,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen "Client requested connection close");
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen http_server_request_destroy(&req);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen }
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen http_server_request_destroy(&req);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (tunnel_callback != NULL) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen http_server_connection_tunnel(&conn, tunnel_callback, tunnel_context);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen return;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen http_server_connection_trigger_responses(conn);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen}
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenstatic struct http_server_response *
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenhttp_server_request_create_fail_response(struct http_server_request *req,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen unsigned int status, const char *reason)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen{
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen struct http_server_response *resp;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen req->failed = TRUE;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_assert(status / 100 != 1 && status != 204 && status != 304);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen resp = http_server_response_create(req, status, reason);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (!http_request_method_is(&req->req, "HEAD")) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen http_server_response_add_header
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen (resp, "Content-Type", "text/plain; charset=utf-8");
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen reason = t_strconcat(reason, "\r\n", NULL);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen http_server_response_set_payload_data
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen (resp, (const unsigned char *)reason, strlen(reason));
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen }
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen return resp;
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen}
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic void
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenhttp_server_request_fail_full(struct http_server_request *req,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen unsigned int status, const char *reason, bool close)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct http_server_response *resp;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen req->failed = TRUE;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen resp = http_server_request_create_fail_response(req, status, reason);
4a514fb20e04df397842cde11cc9ea92abfe9728Timo Sirainen if (close)
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen http_server_response_submit_close(resp);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen else
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen http_server_response_submit(resp);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenvoid http_server_request_fail(struct http_server_request *req,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen unsigned int status, const char *reason)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen http_server_request_fail_full(req, status, reason,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen req->conn->input_broken);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenvoid http_server_request_fail_close(struct http_server_request *req,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen unsigned int status, const char *reason)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen http_server_request_fail_full(req, status, reason, TRUE);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenvoid http_server_request_fail_auth(struct http_server_request *req,
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen const char *reason, const struct http_auth_challenge *chlng)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen{
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct http_server_response *resp;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen req->failed = TRUE;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen if (reason == NULL)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen reason = "Unauthenticated";
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen resp = http_server_request_create_fail_response(req, 401, reason);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen http_server_response_add_auth(resp, chlng);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen http_server_response_submit(resp);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen}
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenvoid http_server_request_fail_auth_basic(struct http_server_request *req,
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen const char *reason, const char *realm)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct http_auth_challenge chlng;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen http_auth_basic_challenge_init(&chlng, realm);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen http_server_request_fail_auth(req, reason, &chlng);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen/*
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen * Payload input stream
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstruct http_server_istream {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct istream_private istream;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct http_server_request *req;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ssize_t read_status;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen};
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstatic void
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenhttp_server_istream_switch_ioloop(struct istream_private *stream)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct http_server_istream *hsristream =
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen (struct http_server_istream *)stream;
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (hsristream->istream.istream.blocking)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen http_server_connection_switch_ioloop(hsristream->req->conn);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstatic void
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenhttp_server_istream_read_any(struct http_server_istream *hsristream)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct istream_private *stream = &hsristream->istream;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct http_server *server = hsristream->req->server;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ssize_t ret;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if ((ret=i_stream_read_copy_from_parent
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen (&stream->istream)) > 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hsristream->read_status = ret;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen io_loop_stop(server->ioloop);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic ssize_t
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenhttp_server_istream_read(struct istream_private *stream)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_istream *hsristream =
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen (struct http_server_istream *)stream;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_request *req = hsristream->req;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server *server;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_connection *conn;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen bool blocking = stream->istream.blocking;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ssize_t ret;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (req == NULL) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* request already gone (we shouldn't get here) */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen stream->istream.stream_errno = EINVAL;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return -1;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_stream_seek(stream->parent, stream->parent_start_offset +
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen stream->istream.v_offset);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen server = hsristream->req->server;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen conn = hsristream->req->conn;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ret = i_stream_read_copy_from_parent(&stream->istream);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (ret == 0 && blocking) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct ioloop *prev_ioloop = current_ioloop;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct io *io;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen http_server_connection_ref(conn);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen http_server_request_ref(req);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_assert(server->ioloop == NULL);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen server->ioloop = io_loop_create();
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen http_server_connection_switch_ioloop(conn);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (blocking && req->req.expect_100_continue &&
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen !req->sent_100_continue)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen http_server_connection_trigger_responses(conn);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hsristream->read_status = 0;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen io = io_add_istream(&stream->istream,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen http_server_istream_read_any, hsristream);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen while (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED &&
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen hsristream->read_status == 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen io_loop_run(server->ioloop);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen io_remove(&io);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen io_loop_set_current(prev_ioloop);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen http_server_connection_switch_ioloop(conn);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen io_loop_set_current(server->ioloop);
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen io_loop_destroy(&server->ioloop);
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen ret = hsristream->read_status;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (!http_server_request_unref(&req))
494a5de15db3b2806ab31d5ecc3e1c306ae14d06Timo Sirainen hsristream->req = NULL;
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen http_server_connection_unref(&conn);
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen return ret;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen}
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
9d4c027e7de01ab948d6221bc27c9b45d32d1ea5Timo Sirainenstatic void
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenhttp_server_istream_destroy(struct iostream_private *stream)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen struct http_server_istream *hsristream =
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen (struct http_server_istream *)stream;
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen uoff_t v_offset;
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen v_offset = hsristream->istream.parent_start_offset +
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen hsristream->istream.istream.v_offset;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (hsristream->istream.parent->seekable ||
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen v_offset > hsristream->istream.parent->v_offset) {
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen /* get to same position in parent stream */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen i_stream_seek(hsristream->istream.parent, v_offset);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen }
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen}
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainenstruct istream *
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainenhttp_server_request_get_payload_input(struct http_server_request *req,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen bool blocking)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct http_server_istream *hsristream;
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen struct istream *payload = req->req.payload;
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen i_assert(req->payload_input == NULL);
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen hsristream = i_new(struct http_server_istream, 1);
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen hsristream->req = req;
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen hsristream->istream.max_buffer_size =
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen payload->real_stream->max_buffer_size;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hsristream->istream.stream_size_passthrough = TRUE;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hsristream->istream.read = http_server_istream_read;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hsristream->istream.switch_ioloop = http_server_istream_switch_ioloop;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hsristream->istream.iostream.destroy = http_server_istream_destroy;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hsristream->istream.istream.readable_fd = FALSE;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hsristream->istream.istream.blocking = blocking;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hsristream->istream.istream.seekable = FALSE;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen req->payload_input = i_stream_create
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen (&hsristream->istream, payload, i_stream_get_fd(payload));
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen i_stream_unref(&req->req.payload);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return req->payload_input;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen/*
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen * Payload handling
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic void
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenhttp_server_payload_handler_init(
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct http_server_payload_handler *handler ,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct http_server_request *req)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct http_server_connection *conn = req->conn;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_assert(conn->payload_handler == NULL);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_assert(conn->in_req_callback);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen conn->payload_handler = handler;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen handler->req = req;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenvoid http_server_payload_handler_destroy(
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct http_server_payload_handler **_handler)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct http_server_payload_handler *handler = *_handler;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct http_server_connection *conn = handler->req->conn;
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen if (handler->in_callback) {
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen /* don't destroy handler while in callback */
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen return;
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen *_handler = NULL;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen i_assert(conn->payload_handler == NULL);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (handler->destroy != NULL)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen handler->destroy(handler);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenvoid http_server_payload_handler_switch_ioloop(
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct http_server_payload_handler *handler)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (handler->switch_ioloop != NULL)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen handler->switch_ioloop(handler);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen/* pump-based */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstruct http_server_payload_handler_pump {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct http_server_payload_handler handler;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct iostream_pump *pump;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen void (*callback)(void *);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen void *context;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen};
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic void
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenpayload_handler_pump_destroy(
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_payload_handler *handler)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_payload_handler_pump *phandler =
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen (struct http_server_payload_handler_pump *)handler;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen iostream_pump_unref(&phandler->pump);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic void
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenpayload_handler_pump_switch_ioloop(
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_payload_handler *handler)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_payload_handler_pump *phandler =
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen (struct http_server_payload_handler_pump *)handler;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen iostream_pump_switch_ioloop(phandler->pump);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic void
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenpayload_handler_pump_callback(bool success,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_payload_handler_pump *phandler)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
1f4399a277b861419b82758ab0462e90c00a4c41Timo Sirainen struct http_server_payload_handler *handler = &phandler->handler;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_request *req = handler->req;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_connection *conn = req->conn;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct istream *input = iostream_pump_get_input(phandler->pump);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct ostream *output = iostream_pump_get_output(phandler->pump);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (success) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (!i_stream_is_eof(conn->incoming_payload)) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen http_server_request_fail_close(req,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen 413, "Payload Too Large");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen unsigned int old_refcount = req->refcount;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen handler->in_callback = TRUE;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen phandler->callback(phandler->context);
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen req->callback_refcount += req->refcount - old_refcount;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen handler->in_callback = FALSE;
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen i_assert(req->callback_refcount > 0 ||
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen (req->response != NULL && req->response->submitted));
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if (input->stream_errno != 0) {
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen http_server_request_client_error(req,
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen "iostream_pump: read(%s) failed: %s",
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen i_stream_get_name(input),
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen i_stream_get_error(input));
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen http_server_request_fail_close(req,
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen 400, "Bad Request");
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen } else {
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen if (output->stream_errno != 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen http_server_request_error(req,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen "iostream_pump: write(%s) failed: %s",
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen o_stream_get_name(output),
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen o_stream_get_error(output));
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen http_server_request_fail_close(req,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen 500, "Internal Server Error");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (conn->payload_handler != NULL)
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen http_server_payload_handler_destroy(&conn->payload_handler);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen#undef http_server_request_forward_payload
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainenvoid http_server_request_forward_payload(struct http_server_request *req,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct ostream *output, uoff_t max_size,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen void (*callback)(void *), void *context)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct http_server_connection *conn = req->conn;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct istream *input = conn->incoming_payload;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct http_server_payload_handler_pump *phandler;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen uoff_t payload_size;
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen int ret;
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen i_assert(req->req.payload != NULL);
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen if (max_size == (uoff_t)-1) {
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen i_stream_ref(input);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if ((ret = i_stream_get_size(input, TRUE, &payload_size)) != 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (ret < 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen http_server_request_error(req,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen "i_stream_get_size(%s) failed: %s",
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen i_stream_get_name(input), i_stream_get_error(input));
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen http_server_request_fail_close(req,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen 500, "Internal Server Error");
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (payload_size > max_size) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen http_server_request_fail_close(req,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen 413, "Payload Too Large");
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen input = i_stream_create_limit(input, max_size);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen phandler = p_new(req->pool, struct http_server_payload_handler_pump, 1);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen http_server_payload_handler_init(&phandler->handler, req);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen phandler->handler.switch_ioloop = payload_handler_pump_switch_ioloop;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen phandler->handler.destroy = payload_handler_pump_destroy;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen phandler->callback = callback;
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen phandler->context = context;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen phandler->pump = iostream_pump_create(input, output);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen iostream_pump_set_completion_callback(phandler->pump,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen payload_handler_pump_callback, phandler);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen iostream_pump_start(phandler->pump);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen i_stream_unref(&input);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen}
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#undef http_server_request_buffer_payload
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainenvoid http_server_request_buffer_payload(struct http_server_request *req,
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen buffer_t *buffer, uoff_t max_size,
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen void (*callback)(void *), void *context)
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen{
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen struct ostream *output;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen output = o_stream_create_buffer(buffer);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen http_server_request_forward_payload(req,
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen output, max_size, callback, context);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen o_stream_unref(&output);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen/* raw */
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainenstruct http_server_payload_handler_raw {
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen struct http_server_payload_handler handler;
e36574dadcac802d6780fa94ee45951e75594c96Timo Sirainen
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen struct io *io;
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen void (*callback)(void *context);
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen void *context;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen};
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainenstatic void
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenpayload_handler_raw_destroy(
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen struct http_server_payload_handler *handler)
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen{
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen struct http_server_payload_handler_raw *rhandler =
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen (struct http_server_payload_handler_raw *)handler;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen io_remove(&rhandler->io);
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen}
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainenstatic void
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainenpayload_handler_raw_switch_ioloop(
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen struct http_server_payload_handler *handler)
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen{
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen struct http_server_payload_handler_raw *rhandler =
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen (struct http_server_payload_handler_raw *)handler;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rhandler->io = io_loop_move_io(&rhandler->io);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic void
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenpayload_handler_raw_input(
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen struct http_server_payload_handler_raw *rhandler)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen{
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen struct http_server_payload_handler *handler = &rhandler->handler;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen struct http_server_request *req = handler->req;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen struct http_server_connection *conn = req->conn;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen struct istream *input = conn->incoming_payload;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen unsigned int old_refcount = req->refcount;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen handler->in_callback = TRUE;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen rhandler->callback(rhandler->context);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen req->callback_refcount += req->refcount - old_refcount;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen handler->in_callback = FALSE;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (input != NULL && input->stream_errno != 0) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (req->response == NULL) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen http_server_request_client_error(req,
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen "read(%s) failed: %s",
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen i_stream_get_name(input),
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen i_stream_get_error(input));
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen http_server_request_fail_close(req,
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen 400, "Bad Request");
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen }
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen } else if (input == NULL ||
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen !i_stream_have_bytes_left(input)) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen i_assert(req->callback_refcount > 0 ||
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen (req->response != NULL && req->response->submitted));
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen } else {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen return;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (conn->payload_handler != NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen http_server_payload_handler_destroy(&conn->payload_handler);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen#undef http_server_request_handle_payload
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainenvoid http_server_request_handle_payload(struct http_server_request *req,
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen void (*callback)(void *context), void *context)
4809537f0c5a2e1cee9559ec842cc869884d2cb7Timo Sirainen{
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen struct http_server_payload_handler_raw *rhandler;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen struct http_server_connection *conn = req->conn;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen rhandler = p_new(req->pool, struct http_server_payload_handler_raw, 1);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen http_server_payload_handler_init(&rhandler->handler, req);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen rhandler->handler.switch_ioloop = payload_handler_raw_switch_ioloop;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen rhandler->handler.destroy = payload_handler_raw_destroy;
8709b2fe6ec2b5ca1d90a63490f8371472062efdTimo Sirainen rhandler->callback = callback;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen rhandler->context = context;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen rhandler->io = io_add_istream(conn->incoming_payload,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen payload_handler_raw_input, rhandler);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_stream_set_input_pending(conn->incoming_payload, TRUE);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen