http-server-request.c revision 38af46387e565053adf6c47f7f6871676d685de8
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen#include "http-server-private.h"
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen/*
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen * Logging
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen */
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainenstatic inline void
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainenhttp_server_request_debug(struct http_server_request *req,
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen const char *format, ...) ATTR_FORMAT(2, 3);
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic inline void
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenhttp_server_request_debug(struct http_server_request *req,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *format, ...)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct http_server *server = req->server;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen va_list args;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (server->set.debug) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen va_start(args, format);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_debug("http-server: request %s: %s",
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen http_server_request_label(req),
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen t_strdup_vprintf(format, args));
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen va_end(args);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen}
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic inline void
2d3aac5be07b96f72cf0551fac35ac74a4f07770Timo Sirainenhttp_server_request_error(struct http_server_request *req,
2d3aac5be07b96f72cf0551fac35ac74a4f07770Timo Sirainen const char *format, ...) ATTR_FORMAT(2, 3);
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic inline void
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenhttp_server_request_error(struct http_server_request *req,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen const char *format, ...)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen{
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen va_list args;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen
a205d315b0978985ba77d871f44e4a98273612e6Timo Sirainen va_start(args, format);
a205d315b0978985ba77d871f44e4a98273612e6Timo Sirainen i_error("http-server: request %s: %s",
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen http_server_request_label(req),
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen t_strdup_vprintf(format, args));
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen va_end(args);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen}
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic inline void
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenhttp_server_request_client_error(struct http_server_request *req,
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen const char *format, ...) ATTR_FORMAT(2, 3);
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainen
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainenstatic inline void
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainenhttp_server_request_client_error(struct http_server_request *req,
fb2e0bbb7737f3223b16aa41e4b40fb0cd5f288fTimo Sirainen const char *format, ...)
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen{
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen va_list args;
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen va_start(args, format);
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen i_info("http-server: request %s: %s",
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen http_server_request_label(req),
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen t_strdup_vprintf(format, args));
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen va_end(args);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen}
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen/*
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen * Request
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstruct http_server_request *
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenhttp_server_request_new(struct http_server_connection *conn)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen static unsigned int id_counter = 0;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen pool_t pool;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen struct http_server_request *req;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen pool = pool_alloconly_create(MEMPOOL_GROWING"http_server_request", 4096);
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen req = p_new(pool, struct http_server_request, 1);
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen req->pool = pool;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen req->refcount = 1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen req->conn = conn;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen req->server = conn->server;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen req->id = ++id_counter;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen http_server_connection_add_request(conn, req);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return req;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenvoid http_server_request_ref(struct http_server_request *req)
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen i_assert(req->refcount > 0);
e5759add4dc24b96606dccc4a989838e260f2a12Timo Sirainen req->refcount++;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenbool http_server_request_unref(struct http_server_request **_req)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen{
4efba37e4f27b93832f6147c3a353d6d22c855c7Timo Sirainen struct http_server_request *req = *_req;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen struct http_server_connection *conn = req->conn;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen i_assert(req->refcount > 0);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen *_req = NULL;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (--req->refcount > 0)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return TRUE;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen http_server_request_debug(req, "Free");
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen http_server_connection_remove_request(conn, req);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen if (req->destroy_callback != NULL) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen req->destroy_callback(req->destroy_context);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen req->destroy_callback = NULL;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen if (req->response != NULL)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen http_server_response_free(req->response);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen pool_unref(&req->pool);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen return FALSE;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen}
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid http_server_request_destroy(struct http_server_request **_req)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen{
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct http_server_request *req = *_req;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server *server = req->server;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_request_debug(req, "Destroy");
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* just make sure the request ends in a proper state */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (server->ioloop != NULL)
197ad81605dc0f6d2ebc9ad99994db5ca6d76699Timo Sirainen io_loop_stop(server->ioloop);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (req->delay_destroy) {
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen req->destroy_pending = TRUE;
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen } else if (req->destroy_callback != NULL) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen void (*callback)(void *) = req->destroy_callback;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->destroy_callback = NULL;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen callback(req->destroy_context);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_request_unref(_req);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#undef http_server_request_set_destroy_callback
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid http_server_request_set_destroy_callback(struct http_server_request *req,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen void (*callback)(void *),
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen void *context)
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->destroy_callback = callback;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen req->destroy_context = context;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid http_server_request_abort(struct http_server_request **_req,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const char *reason)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server_request *req = *_req;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server_connection *conn = req->conn;
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen if (req->state >= HTTP_SERVER_REQUEST_STATE_FINISHED)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_request_debug(req, "Abort");
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->conn = NULL;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (conn != NULL) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_connection_remove_request(conn, req);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (!conn->closed) {
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen /* send best-effort response if appropriate */
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen if (!conn->output_locked &&
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->state >= HTTP_SERVER_REQUEST_STATE_PROCESSING &&
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->state < HTTP_SERVER_REQUEST_STATE_SENT_RESPONSE) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen static const char *response =
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "HTTP/1.1 500 Internal Server Error\r\n"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "Content-Length: 0\r\n"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "\r\n";
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen (void)o_stream_send(conn->conn.output,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen response, strlen(response));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen /* close the connection */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen http_server_connection_close(&conn, reason);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen }
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen }
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen if (req->response != NULL &&
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen !req->response->payload_blocking) {
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen http_server_response_free(req->response);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen req->response = NULL;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen http_server_request_destroy(_req);
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen}
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainenconst struct http_request *
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenhttp_server_request_get(struct http_server_request *req)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return &req->req;
bf301a34ffbfd049be583094019b2644884b6d0bTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenpool_t
58eb2cb24dbeadd94500670acad7ceb1c8b0d9b4Timo Sirainenhttp_server_request_get_pool(struct http_server_request *req)
bf301a34ffbfd049be583094019b2644884b6d0bTimo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return req->pool;
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct http_server_response *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenhttp_server_request_get_response(struct http_server_request *req)
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen{
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen return req->response;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint http_server_request_get_auth(struct http_server_request *req,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct http_auth_credentials *credentials)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen const char *auth;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen auth = http_request_header_get(&req->req, "Authorization");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (auth == NULL)
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (http_auth_parse_credentials
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ((const unsigned char *)auth, strlen(auth), credentials) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenbool http_server_request_is_finished(struct http_server_request *req)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return req->response != NULL ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen req->state == HTTP_SERVER_REQUEST_STATE_ABORTED;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenbool http_server_request_is_complete(struct http_server_request *req)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return (req->failed || req->conn->input_broken ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (req->next != NULL && !http_server_request_is_new(req->next)) ||
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen !http_server_connection_pending_payload(req->conn));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid http_server_request_halt_payload(struct http_server_request *req)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(req->state <= HTTP_SERVER_REQUEST_STATE_QUEUED);
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen req->payload_halted = TRUE;
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenvoid http_server_request_continue_payload(struct http_server_request *req)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(req->state <= HTTP_SERVER_REQUEST_STATE_QUEUED);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen req->payload_halted = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (req->req.expect_100_continue && !req->sent_100_continue)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen http_server_connection_trigger_responses(req->conn);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid http_server_request_ready_to_respond(struct http_server_request *req)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen http_server_request_debug(req, "Ready to respond");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen http_server_connection_trigger_responses(req->conn);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenvoid http_server_request_submit_response(struct http_server_request *req)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen struct http_server_connection *conn = req->conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(conn != NULL && req->response != NULL && req->response->submitted);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen http_server_request_ref(req);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (conn->payload_handler != NULL && conn->payload_handler->req == req)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen http_server_payload_handler_destroy(&conn->payload_handler);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (req->state) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case HTTP_SERVER_REQUEST_STATE_NEW:
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen case HTTP_SERVER_REQUEST_STATE_QUEUED:
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen case HTTP_SERVER_REQUEST_STATE_PAYLOAD_IN:
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen case HTTP_SERVER_REQUEST_STATE_PROCESSING:
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (!http_server_request_is_complete(req)) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_request_debug(req, "Not ready to respond");
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_SUBMITTED_RESPONSE;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen break;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen }
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen http_server_request_ready_to_respond(req);
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen break;
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen case HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND:
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen http_server_connection_trigger_responses(req->conn);
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen break;
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen case HTTP_SERVER_REQUEST_STATE_ABORTED:
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen break;
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen default:
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen i_unreached();
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen }
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen http_server_request_unref(&req);
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen}
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid http_server_request_finished(struct http_server_request *req)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server_connection *conn = req->conn;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server_response *resp = req->response;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_tunnel_callback_t tunnel_callback = resp->tunnel_callback;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen void *tunnel_context = resp->tunnel_context;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_request_debug(req, "Finished");
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_assert(req->state < HTTP_SERVER_REQUEST_STATE_FINISHED);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen req->state = HTTP_SERVER_REQUEST_STATE_FINISHED;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_connection_remove_request(conn, req);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen conn->stats.response_count++;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (tunnel_callback == NULL && (req->req.connection_close || resp->close)) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (resp->close) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_connection_close(&conn,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen t_strdup_printf("Server closed connection: %u %s",
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen resp->status, resp->reason));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainen } else {
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainen http_server_connection_close(&conn,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "Client requested connection close");
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen http_server_request_destroy(&req);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen return;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_request_destroy(&req);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (tunnel_callback != NULL) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen http_server_connection_tunnel(&conn, tunnel_callback, tunnel_context);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen http_server_connection_trigger_responses(conn);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenstatic struct http_server_response *
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenhttp_server_request_create_fail_response(struct http_server_request *req,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen unsigned int status, const char *reason)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen struct http_server_response *resp;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen req->failed = TRUE;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_assert(status / 100 != 1 && status != 204 && status != 304);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
bf301a34ffbfd049be583094019b2644884b6d0bTimo Sirainen resp = http_server_response_create(req, status, reason);
51ff0538ab38def8045b3f7feb43e1e069cbe037Timo Sirainen if (!http_request_method_is(&req->req, "HEAD")) {
58eb2cb24dbeadd94500670acad7ceb1c8b0d9b4Timo Sirainen http_server_response_add_header
bf301a34ffbfd049be583094019b2644884b6d0bTimo Sirainen (resp, "Content-Type", "text/plain; charset=utf-8");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen reason = t_strconcat(reason, "\r\n", NULL);
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen http_server_response_set_payload_data
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen (resp, (const unsigned char *)reason, strlen(reason));
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen return resp;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen}
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenstatic void
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenhttp_server_request_fail_full(struct http_server_request *req,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen unsigned int status, const char *reason, bool close)
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen{
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen struct http_server_response *resp;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen req->failed = TRUE;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen resp = http_server_request_create_fail_response(req, status, reason);
a60c1c1fca85402e6fccbf3ae0784b7179ae186cTimo Sirainen if (close)
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen http_server_response_submit_close(resp);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen http_server_response_submit(resp);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainenvoid http_server_request_fail(struct http_server_request *req,
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen unsigned int status, const char *reason)
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen{
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen http_server_request_fail_full(req, status, reason,
08fa343b3aace9343da3195686c65c5326eda207Timo Sirainen req->conn->input_broken);
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainen}
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainen
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainenvoid http_server_request_fail_close(struct http_server_request *req,
dc049c5e83d947aaf1b97c26ae819cc9577e0475Timo Sirainen unsigned int status, const char *reason)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen{
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen http_server_request_fail_full(req, status, reason, TRUE);
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainen}
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainenvoid http_server_request_fail_auth(struct http_server_request *req,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *reason, const struct http_auth_challenge *chlng)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen{
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen struct http_server_response *resp;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen req->failed = TRUE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (reason == NULL)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen reason = "Unauthenticated";
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen resp = http_server_request_create_fail_response(req, 401, reason);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen http_server_response_add_auth(resp, chlng);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen http_server_response_submit(resp);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
511a7ccd55cea57c9d953920b7d651720128ada9Timo Sirainen
511a7ccd55cea57c9d953920b7d651720128ada9Timo Sirainenvoid http_server_request_fail_auth_basic(struct http_server_request *req,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen const char *reason, const char *realm)
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen struct http_auth_challenge chlng;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen http_auth_basic_challenge_init(&chlng, realm);
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen http_server_request_fail_auth(req, reason, &chlng);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
511a7ccd55cea57c9d953920b7d651720128ada9Timo Sirainen/*
511a7ccd55cea57c9d953920b7d651720128ada9Timo Sirainen * Payload input stream
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstruct http_server_istream {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen struct istream_private istream;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server_request *req;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ssize_t read_status;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen};
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic void
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenhttp_server_istream_switch_ioloop(struct istream_private *stream)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server_istream *hsristream =
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen (struct http_server_istream *)stream;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (hsristream->istream.istream.blocking)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen http_server_connection_switch_ioloop(hsristream->req->conn);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic void
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenhttp_server_istream_read_any(struct http_server_istream *hsristream)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct istream_private *stream = &hsristream->istream;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct http_server *server = hsristream->req->server;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen ssize_t ret;
dc52b16795b56589923ff586e5cdd0c0f1fd5931Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if ((ret=i_stream_read_copy_from_parent
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen (&stream->istream)) > 0) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen hsristream->read_status = ret;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen io_loop_stop(server->ioloop);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic ssize_t
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenhttp_server_istream_read(struct istream_private *stream)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen struct http_server_istream *hsristream =
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen (struct http_server_istream *)stream;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen struct http_server_request *req = hsristream->req;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen 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;
}
/*
* Payload handling
*/
static void
http_server_payload_handler_init(
struct http_server_payload_handler *handler ,
struct http_server_request *req)
{
struct http_server_connection *conn = req->conn;
i_assert(conn->payload_handler == NULL);
i_assert(conn->in_req_callback);
conn->payload_handler = handler;
handler->req = req;
}
void http_server_payload_handler_destroy(
struct http_server_payload_handler **_handler)
{
struct http_server_payload_handler *handler = *_handler;
struct http_server_connection *conn = handler->req->conn;
if (handler->in_callback) {
/* don't destroy handler while in callback */
return;
}
*_handler = NULL;
i_assert(conn->payload_handler == NULL);
if (handler->destroy != NULL)
handler->destroy(handler);
}
void http_server_payload_handler_switch_ioloop(
struct http_server_payload_handler *handler)
{
if (handler->switch_ioloop != NULL)
handler->switch_ioloop(handler);
}
/* pump-based */
struct http_server_payload_handler_pump {
struct http_server_payload_handler handler;
struct iostream_pump *pump;
void (*callback)(void *);
void *context;
};
static void
payload_handler_pump_destroy(
struct http_server_payload_handler *handler)
{
struct http_server_payload_handler_pump *phandler =
(struct http_server_payload_handler_pump *)handler;
iostream_pump_unref(&phandler->pump);
}
static void
payload_handler_pump_switch_ioloop(
struct http_server_payload_handler *handler)
{
struct http_server_payload_handler_pump *phandler =
(struct http_server_payload_handler_pump *)handler;
iostream_pump_switch_ioloop(phandler->pump);
}
static void
payload_handler_pump_callback(bool success,
struct http_server_payload_handler_pump *phandler)
{
struct http_server_payload_handler *handler = &phandler->handler;
struct http_server_request *req = handler->req;
struct http_server_connection *conn = req->conn;
struct istream *input = iostream_pump_get_input(phandler->pump);
struct ostream *output = iostream_pump_get_output(phandler->pump);
if (success) {
if (!i_stream_is_eof(conn->incoming_payload)) {
http_server_request_fail_close(req,
413, "Payload Too Large");
} else {
unsigned int old_refcount = req->refcount;
handler->in_callback = TRUE;
phandler->callback(phandler->context);
req->callback_refcount += req->refcount - old_refcount;
handler->in_callback = FALSE;
i_assert(req->callback_refcount > 0 ||
(req->response != NULL && req->response->submitted));
}
} else if (input->stream_errno != 0) {
http_server_request_client_error(req,
"iostream_pump: read(%s) failed: %s",
i_stream_get_name(input),
i_stream_get_error(input));
http_server_request_fail_close(req,
400, "Bad Request");
} else {
if (output->stream_errno != 0) {
http_server_request_error(req,
"iostream_pump: write(%s) failed: %s",
o_stream_get_name(output),
o_stream_get_error(output));
}
http_server_request_fail_close(req,
500, "Internal Server Error");
}
if (conn->payload_handler != NULL)
http_server_payload_handler_destroy(&conn->payload_handler);
}
#undef http_server_request_forward_payload
void http_server_request_forward_payload(struct http_server_request *req,
struct ostream *output, uoff_t max_size,
void (*callback)(void *), void *context)
{
struct http_server_connection *conn = req->conn;
struct istream *input = conn->incoming_payload;
struct http_server_payload_handler_pump *phandler;
uoff_t payload_size;
int ret;
i_assert(req->req.payload != NULL);
if (max_size == (uoff_t)-1) {
i_stream_ref(input);
} else {
if ((ret = i_stream_get_size(input, TRUE, &payload_size)) != 0) {
if (ret < 0) {
http_server_request_error(req,
"i_stream_get_size(%s) failed: %s",
i_stream_get_name(input), i_stream_get_error(input));
http_server_request_fail_close(req,
500, "Internal Server Error");
return;
}
if (payload_size > max_size) {
http_server_request_fail_close(req,
413, "Payload Too Large");
return;
}
}
input = i_stream_create_limit(input, max_size);
}
phandler = p_new(req->pool, struct http_server_payload_handler_pump, 1);
http_server_payload_handler_init(&phandler->handler, req);
phandler->handler.switch_ioloop = payload_handler_pump_switch_ioloop;
phandler->handler.destroy = payload_handler_pump_destroy;
phandler->callback = callback;
phandler->context = context;
phandler->pump = iostream_pump_create(input, output);
iostream_pump_set_completion_callback(phandler->pump,
payload_handler_pump_callback, phandler);
iostream_pump_start(phandler->pump);
i_stream_unref(&input);
}
#undef http_server_request_buffer_payload
void http_server_request_buffer_payload(struct http_server_request *req,
buffer_t *buffer, uoff_t max_size,
void (*callback)(void *), void *context)
{
struct ostream *output;
output = o_stream_create_buffer(buffer);
http_server_request_forward_payload(req,
output, max_size, callback, context);
o_stream_unref(&output);
}
/* raw */
struct http_server_payload_handler_raw {
struct http_server_payload_handler handler;
struct io *io;
void (*callback)(void *context);
void *context;
};
static void
payload_handler_raw_destroy(
struct http_server_payload_handler *handler)
{
struct http_server_payload_handler_raw *rhandler =
(struct http_server_payload_handler_raw *)handler;
io_remove(&rhandler->io);
}
static void
payload_handler_raw_switch_ioloop(
struct http_server_payload_handler *handler)
{
struct http_server_payload_handler_raw *rhandler =
(struct http_server_payload_handler_raw *)handler;
rhandler->io = io_loop_move_io(&rhandler->io);
}
static void
payload_handler_raw_input(
struct http_server_payload_handler_raw *rhandler)
{
struct http_server_payload_handler *handler = &rhandler->handler;
struct http_server_request *req = handler->req;
struct http_server_connection *conn = req->conn;
struct istream *input = conn->incoming_payload;
unsigned int old_refcount = req->refcount;
handler->in_callback = TRUE;
rhandler->callback(rhandler->context);
req->callback_refcount += req->refcount - old_refcount;
handler->in_callback = FALSE;
if (input != NULL && input->stream_errno != 0) {
if (req->response == NULL) {
http_server_request_client_error(req,
"read(%s) failed: %s",
i_stream_get_name(input),
i_stream_get_error(input));
http_server_request_fail_close(req,
400, "Bad Request");
}
} else if (input == NULL ||
!i_stream_have_bytes_left(input)) {
i_assert(req->callback_refcount > 0 ||
(req->response != NULL && req->response->submitted));
} else {
return;
}
if (conn->payload_handler != NULL)
http_server_payload_handler_destroy(&conn->payload_handler);
}
#undef http_server_request_handle_payload
void http_server_request_handle_payload(struct http_server_request *req,
void (*callback)(void *context), void *context)
{
struct http_server_payload_handler_raw *rhandler;
struct http_server_connection *conn = req->conn;
rhandler = p_new(req->pool, struct http_server_payload_handler_raw, 1);
http_server_payload_handler_init(&rhandler->handler, req);
rhandler->handler.switch_ioloop = payload_handler_raw_switch_ioloop;
rhandler->handler.destroy = payload_handler_raw_destroy;
rhandler->callback = callback;
rhandler->context = context;
rhandler->io = io_add_istream(conn->incoming_payload,
payload_handler_raw_input, rhandler);
i_stream_set_input_pending(conn->incoming_payload, TRUE);
}