Line data Source code
1 : /*
2 : START OF LICENSE STUB
3 : DeDOS: Declarative Dispersion-Oriented Software
4 : Copyright (C) 2017 University of Pennsylvania, Georgetown University
5 :
6 : This program is free software: you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation, either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : END OF LICENSE STUB
19 : */
20 : #include "webserver/http_msu.h"
21 : #include "webserver/connection-handler.h"
22 : #include "webserver/dbops.h"
23 : #include "webserver/cache_msu.h"
24 : #include "webserver/write_msu.h"
25 : #include "webserver/read_msu.h"
26 : #include "socket_msu.h"
27 : #include "msu_calls.h"
28 : #include "logging.h"
29 : #include "epollops.h"
30 : #include "msu_state.h"
31 : #include "unused_def.h"
32 : #include "local_msu.h"
33 : #include "webserver/regex_routing_msu.h"
34 :
35 3 : static int send_error(struct local_msu *self, struct http_state *http_state,
36 : struct msu_msg_hdr *hdr) {
37 3 : struct response_state *resp = malloc(sizeof(*resp));
38 3 : init_response_state(resp, &http_state->conn);
39 3 : resp->body_len = craft_error_response(resp->url, resp->body);
40 3 : return call_msu_type(self, &WEBSERVER_WRITE_MSU_TYPE, hdr, sizeof(*resp), resp);
41 : }
42 :
43 144 : static int handle_db(struct http_state *http_state,
44 : struct local_msu *self,
45 : struct msu_msg *msg) {
46 :
47 144 : http_state->db.data = self->msu_state;
48 144 : int rtn = access_database(http_state->parser.url, &http_state->db);
49 :
50 144 : if (rtn & WS_ERROR) {
51 1 : log_warn("Could not access database!");
52 1 : msu_error(self, &msg->hdr, 0);
53 :
54 1 : send_error(self, http_state, &msg->hdr);
55 1 : msu_free_state(self, &msg->hdr.key);
56 1 : return -1;
57 143 : } else if (rtn & (WS_INCOMPLETE_READ | WS_INCOMPLETE_WRITE)) {
58 1 : log(LOG_HTTP_MSU, "Partial db access, requeuing state %p", http_state);
59 1 : http_state->conn.status = CON_DB_REQUEST;
60 1 : return msu_monitor_fd(http_state->db.db_fd, RTN_TO_EVT(rtn), self, &msg->hdr);
61 :
62 142 : } else if (rtn & WS_COMPLETE) {
63 142 : struct response_state *resp = malloc(sizeof(*resp));
64 142 : init_response_state(resp, &http_state->conn);
65 142 : strcpy(resp->url, http_state->parser.url);
66 142 : msu_free_state(self, &msg->hdr.key);
67 :
68 142 : if (!has_regex(resp->url)) {
69 140 : log(LOG_HTTP_MSU, "Crafting response for url %s", resp->url);
70 140 : return call_msu_type(self, &WEBSERVER_CACHE_MSU_TYPE, &msg->hdr, sizeof(*resp), resp);
71 : }
72 :
73 2 : return call_msu_type(self, &WEBSERVER_REGEX_ROUTING_MSU_TYPE, &msg->hdr, sizeof(*resp), resp);
74 : }
75 0 : log_error("Unknown return code from database access: %d", rtn);
76 0 : msu_error(self, &msg->hdr, 0);
77 0 : return -1;
78 : }
79 :
80 1 : static int clear_state(struct local_msu *self, struct msu_msg *msg) {
81 1 : log(LOG_HTTP_MSU, "Clearing state due to received error message");
82 1 : msu_free_state(self, &msg->hdr.key);
83 1 : return 0;
84 : }
85 :
86 149 : static int handle_parsing(struct read_state *read_state,
87 : struct http_state *http_state,
88 : struct local_msu *self,
89 : struct msu_msg *msg) {
90 149 : if (read_state->req_len == -1) {
91 0 : log(LOG_HTTP_MSU, "Clearing state (fd: %d)", read_state->conn.fd);
92 0 : msu_free_state(self, &msg->hdr.key);
93 0 : return 0;
94 : }
95 149 : log(LOG_HTTP_MSU, "Parsing request: %s (fd: %d)", read_state->req, read_state->conn.fd);
96 149 : int rtn = parse_request(read_state->req, read_state->req_len, http_state);
97 :
98 149 : if (rtn & WS_COMPLETE) {
99 143 : free(read_state);
100 143 : return handle_db(http_state, self, msg);
101 6 : } else if (rtn & WS_ERROR) {
102 2 : send_error(self, http_state, &msg->hdr);
103 2 : msu_free_state(self, &msg->hdr.key);
104 2 : return 0;
105 : } else {
106 4 : http_state->conn.status = CON_READING;
107 4 : log(LOG_PARTIAL_READS, "Got partial request %.*s (fd: %d)",
108 : read_state->req_len, read_state->req, read_state->conn.fd);
109 4 : return call_msu_type(self, &WEBSERVER_READ_MSU_TYPE, &msg->hdr, msg->data_size, msg->data);
110 : }
111 : }
112 :
113 150 : static int craft_http_response(struct local_msu *self,
114 : struct msu_msg *msg) {
115 150 : struct read_state *read_state = msg->data;
116 :
117 150 : size_t size = 0;
118 150 : struct http_state *http_state = msu_get_state(self, &msg->hdr.key, &size);
119 150 : int retrieved = 0;
120 150 : if (http_state == NULL) {
121 149 : http_state = msu_init_state(self, &msg->hdr.key, sizeof(*http_state));
122 149 : read_state->conn.status = CON_READING;
123 149 : init_http_state(http_state, &read_state->conn);
124 149 : memcpy(&http_state->conn, &read_state->conn, sizeof(read_state->conn));
125 : } else {
126 :
127 1 : log(LOG_HTTP_MSU, "Retrieved state %p (status %d)",
128 : http_state, http_state->conn.status);
129 1 : retrieved = 1;
130 1 : if (http_state->conn.status != CON_DB_REQUEST) {
131 0 : log(LOG_PARTIAL_READS, "Recovering partial read state ID: %u",
132 : msg->hdr.key.id);
133 : }
134 : }
135 150 : if (msg->data_size == sizeof(*read_state) && read_state->req_len == -1) {
136 0 : if (http_state->conn.status == CON_DB_REQUEST) {
137 0 : http_state->conn.status = NO_CONNECTION;
138 0 : return 0;
139 : } else {
140 0 : msu_free_state(self, &msg->hdr.key);
141 0 : return 0;
142 : }
143 : }
144 :
145 :
146 : int rtn;
147 150 : switch (http_state->conn.status) {
148 : case NIL:
149 : case CON_READING:
150 149 : log(LOG_HTTP_MSU, "got CON_READING");
151 149 : rtn = handle_parsing(read_state, http_state, self, msg);
152 149 : if (rtn < 0) {
153 1 : log_error("Error processing fd %d, ID %u, retrieved %d", read_state->conn.fd,
154 : (msg->hdr.key.id), retrieved);
155 : }
156 149 : return rtn;
157 : case CON_DB_REQUEST:
158 1 : log(LOG_HTTP_MSU, "got CON_DB_REQUEST");
159 1 : free(read_state);
160 1 : return handle_db(http_state, self, msg);
161 : case NO_CONNECTION:
162 0 : msu_free_state(self, &msg->hdr.key);
163 0 : return 0;
164 : default:
165 0 : log_error("Received unknown packet status: %d", read_state->conn.status);
166 0 : return -1;
167 : }
168 : }
169 :
170 29 : static int http_init(struct local_msu *self, struct msu_init_data *data) {
171 29 : self->msu_state = allocate_db_memory();
172 :
173 29 : char *init_data = data->init_data;
174 :
175 : char *ip, *saveptr;
176 :
177 29 : if ((ip = strtok_r(init_data, " ", &saveptr)) == NULL) {
178 0 : log_error("Did not provide IP for DB initialization to http MSU");
179 0 : return -1;
180 : }
181 : char *port_str;
182 29 : if ((port_str = strtok_r(NULL, " ", &saveptr)) == NULL) {
183 0 : log_error("Did not provide port for DB initialization to http MSU");
184 0 : return -1;
185 : }
186 29 : int port = atoi(port_str);
187 : char *n_files_str;
188 29 : if ((n_files_str = strtok_r(NULL, " ", &saveptr)) == NULL) {
189 0 : log_error("Did not provide n_files for DB initialization to http MSU");
190 0 : return -1;
191 : }
192 29 : int n_files = atoi(n_files_str);
193 :
194 29 : init_db(ip, port, n_files);
195 29 : return 0;
196 : }
197 :
198 29 : static void http_destroy(struct local_msu *self) {
199 29 : free_db_memory(self->msu_state);
200 29 : }
201 :
202 : struct msu_type WEBSERVER_HTTP_MSU_TYPE = {
203 : .name = "Webserver_HTTP_MSU",
204 : .id = WEBSERVER_HTTP_MSU_TYPE_ID,
205 : .init = http_init,
206 : .destroy = http_destroy,
207 : .receive = craft_http_response,
208 : .receive_error = clear_state
209 : };
|