summaryrefslogtreecommitdiffstats
path: root/src/lib-http/http-server.c
blob: dd89a168c9fb4ef9ec8ed11099f8895cf5541b7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "net.h"
#include "str.h"
#include "hash.h"
#include "array.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "connection.h"
#include "dns-lookup.h"
#include "iostream-rawlog.h"
#include "iostream-ssl.h"
#include "http-url.h"

#include "http-server-private.h"

static struct event_category event_category_http_server = {
	.name = "http-server"
};

/*
 * Server
 */

struct http_server *http_server_init(const struct http_server_settings *set)
{
	struct http_server *server;
	pool_t pool;
	size_t pool_size;

	pool_size = (set->ssl != NULL) ? 10240 : 1024; /* ca/cert/key will be >8K */
	pool = pool_alloconly_create("http server", pool_size);
	server = p_new(pool, struct http_server, 1);
	server->pool = pool;

	if (set->default_host != NULL && *set->default_host != '\0')
		server->set.default_host = p_strdup(pool, set->default_host);
	if (set->rawlog_dir != NULL && *set->rawlog_dir != '\0')
		server->set.rawlog_dir = p_strdup(pool, set->rawlog_dir);
	if (set->ssl != NULL) {
		server->set.ssl =
			ssl_iostream_settings_dup(server->pool, set->ssl);
	}
	server->set.max_client_idle_time_msecs = set->max_client_idle_time_msecs;
	server->set.max_pipelined_requests =
		(set->max_pipelined_requests > 0 ? set->max_pipelined_requests : 1);
	server->set.request_limits = set->request_limits;
	server->set.socket_send_buffer_size = set->socket_send_buffer_size;
	server->set.socket_recv_buffer_size = set->socket_recv_buffer_size;
	server->set.debug = set->debug;

	server->event = event_create(set->event);
	event_add_category(server->event, &event_category_http_server);
	event_set_forced_debug(server->event, set->debug);
	event_set_append_log_prefix(server->event, "http-server: ");

	server->conn_list = http_server_connection_list_init();

	p_array_init(&server->resources, pool, 4);
	p_array_init(&server->locations, pool, 4);

	return server;
}

void http_server_deinit(struct http_server **_server)
{
	struct http_server *server = *_server;
	struct http_server_resource *res;

	*_server = NULL;

	connection_list_deinit(&server->conn_list);

	array_foreach_elem(&server->resources, res)
		http_server_resource_free(&res);
	i_assert(array_count(&server->locations) == 0);

	if (server->ssl_ctx != NULL)
		ssl_iostream_context_unref(&server->ssl_ctx);
	event_unref(&server->event);
	pool_unref(&server->pool);
}

void http_server_switch_ioloop(struct http_server *server)
{
	struct connection *_conn = server->conn_list->connections;

	/* move connections */
	/* FIXME: we wouldn't necessarily need to switch all of them
	   immediately, only those that have requests now. but also connections
	   that get new requests before ioloop is switched again.. */
	for (; _conn != NULL; _conn = _conn->next) {
		struct http_server_connection *conn =
			(struct http_server_connection *)_conn;

		http_server_connection_switch_ioloop(conn);
	}
}

void http_server_shut_down(struct http_server *server)
{
	struct connection *_conn, *_next;

	server->shutting_down = TRUE;

	for (_conn = server->conn_list->connections;
		_conn != NULL; _conn = _next) {
		struct http_server_connection *conn =
			(struct http_server_connection *)_conn;

		_next = _conn->next;
		(void)http_server_connection_shut_down(conn);
	}
}

int http_server_init_ssl_ctx(struct http_server *server, const char **error_r)
{
	const char *error;

	if (server->set.ssl == NULL || server->ssl_ctx != NULL)
		return 0;

	if (ssl_iostream_server_context_cache_get(server->set.ssl,
		&server->ssl_ctx, &error) < 0) {
		*error_r = t_strdup_printf("Couldn't initialize SSL context: %s",
					   error);
		return -1;
	}
	return 0;
}