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/connection-handler.h"
21 : #include "logging.h"
22 : #include "webserver/sslops.h"
23 : #include "webserver/socketops.h"
24 : #include "webserver/dbops.h"
25 : #include "webserver/regex.h"
26 : #include "webserver/request_parser.h"
27 : #include "connection-handler.h"
28 : #include <unistd.h>
29 :
30 : #ifdef __GNUC__
31 : #define UNUSED __attribute__ ((unused))
32 : #else
33 : #define UNUSED
34 : #endif
35 :
36 438 : void init_connection(struct connection *conn, int fd) {
37 438 : conn->fd = fd;
38 438 : conn->ssl = NULL;
39 438 : conn->status = CON_ACCEPTED;
40 438 : }
41 :
42 151 : void init_read_state(struct read_state *state, struct connection *conn) {
43 151 : state->conn = *conn;
44 151 : state->req[0] = '\0';
45 151 : state->req_len = 0;
46 151 : }
47 :
48 144 : void init_http_state(struct http_state *state, struct connection *conn) {
49 144 : state->conn = *conn;
50 144 : init_parser_state(&state->parser);
51 144 : bzero(&state->db, sizeof(state->db));
52 144 : }
53 :
54 141 : void init_response_state(struct response_state *state, struct connection *conn) {
55 141 : state->conn = *conn;
56 141 : state->url[0] = '\0';
57 141 : state->path[0] = '\0';
58 141 : state->header[0] = '\0';
59 141 : state->header_len = 0;
60 141 : state->body[0] = '\0';
61 141 : state->body_len = 0;
62 141 : }
63 :
64 294 : int accept_connection(struct connection *conn, int use_ssl) {
65 294 : if (!use_ssl) {
66 0 : log(LOG_CONNECTION_INFO,"Not implemented, assuming connection is already accepted");
67 0 : return WS_COMPLETE;
68 : }
69 :
70 294 : if (conn->ssl == NULL) {
71 148 : conn->ssl = init_ssl_connection(conn->fd);
72 : }
73 :
74 294 : int rtn = accept_ssl(conn->ssl);
75 294 : if (rtn == WS_COMPLETE) {
76 146 : log(LOG_CONNECTION_INFO, "Accepted SSL connection on fd %d", conn->fd);
77 146 : return WS_COMPLETE;
78 148 : } else if (rtn == -1) {
79 : //log_error("Error accepting SSL (fd: %d)", conn->fd);
80 0 : return WS_ERROR;
81 : } else {
82 148 : log(LOG_CONNECTION_INFO, "SSL accept incomplete (fd: %d)", conn->fd);
83 148 : return rtn;
84 : }
85 : }
86 :
87 293 : int read_request(struct read_state *state) {
88 293 : int use_ssl = (state->conn.ssl != NULL);
89 :
90 : int rtn;
91 293 : int bytes = MAX_RECV_LEN;
92 293 : if (use_ssl) {
93 293 : rtn = read_ssl(state->conn.ssl, state->req, &bytes);
94 : } else {
95 0 : rtn = read_socket(state->conn.fd, state->req, &bytes);
96 : }
97 :
98 293 : switch (rtn) {
99 : case WS_INCOMPLETE_READ:
100 : case WS_INCOMPLETE_WRITE:
101 148 : log(LOG_CONNECTION_INFO, "Read incomplete (fd: %d)", state->conn.fd);
102 148 : return rtn;
103 : case WS_COMPLETE:
104 144 : state->req_len = bytes;
105 144 : log(LOG_CONNECTION_INFO, "Completed reading %d bytes (fd: %d)",
106 : bytes, state->conn.fd);
107 144 : return WS_COMPLETE;
108 : case WS_ERROR:
109 1 : log(LOG_WS_ERRORS, "Error reading (fd: %d)", state->conn.fd);
110 1 : return WS_ERROR;
111 : default:
112 0 : log_error("Unknown return code: %d (fd: %d)", rtn, state->conn.fd);
113 0 : return WS_ERROR;
114 : }
115 : }
116 :
117 144 : int parse_request(char *req, int req_len, struct http_state *state) {
118 144 : int status = parse_http(&state->parser, req, req_len);
119 :
120 144 : switch (status) {
121 : case WS_COMPLETE:
122 140 : log(LOG_CONNECTION_INFO, "Request complete (fd: %d)", state->conn.fd);
123 140 : return WS_COMPLETE;
124 : case WS_INCOMPLETE_READ:
125 3 : log(LOG_CONNECTION_INFO, "Partial request received (fd: %d)", state->conn.fd);
126 3 : return WS_INCOMPLETE_READ;
127 : case WS_ERROR:
128 1 : log_error("Error parsing request (fd: %d)", state->conn.fd);
129 1 : return WS_ERROR;
130 : default:
131 0 : log_error("Unknown status %d returned from parrser (fd: %d)", status, state->conn.fd);
132 0 : return WS_ERROR;
133 : }
134 : }
135 :
136 : #define REGEX_KEY "regex="
137 :
138 142 : int has_regex(char *url) {
139 142 : char *regex_loc = strstr(url, REGEX_KEY);
140 142 : if (regex_loc == NULL) {
141 138 : log(LOG_CONNECTION_INFO, "Found no %s in %s", REGEX_KEY, url);
142 138 : return 0;
143 : } else {
144 4 : log(LOG_CONNECTION_INFO, "Found regex");
145 4 : return 1;
146 : }
147 : }
148 : #define MAX_REGEX_VALUE_LEN 64
149 :
150 2 : static int get_regex_value(char *url, char *regex) {
151 2 : char *regex_start = strstr(url, REGEX_KEY);
152 2 : if (regex_start == NULL)
153 0 : return -1;
154 2 : regex_start += strlen(REGEX_KEY);
155 2 : int start_i = (regex_start - url);
156 8 : for (int i=start_i; (i-start_i)<MAX_REGEX_VALUE_LEN; i++) {
157 8 : switch (url[i]) {
158 : case '?':
159 : case '&':
160 : case '\0':
161 : case ' ':
162 2 : strncpy(regex, &url[start_i], i - start_i);
163 2 : regex[i-start_i] = '\0';
164 2 : return 0;
165 : default:
166 6 : continue;
167 : }
168 : }
169 0 : log_error("Requested regex value (%s) too long", regex_start);
170 0 : return -1;
171 : }
172 :
173 140 : int access_database(char *url, struct db_state *state) {
174 140 : if ( strstr(url, "database") == NULL ) {
175 140 : return WS_COMPLETE;
176 : }
177 0 : int rtn = query_db(state);
178 0 : switch (rtn) {
179 : case WS_COMPLETE:
180 0 : log(LOG_CONNECTION_INFO, "Successfully queried db");
181 0 : return WS_COMPLETE;
182 : case WS_INCOMPLETE_READ:
183 : case WS_INCOMPLETE_WRITE:
184 0 : log(LOG_CONNECTION_INFO, "Partial DB query");
185 0 : return rtn;
186 : case WS_ERROR:
187 0 : log_error("Error querying database");
188 0 : return WS_ERROR;
189 : default:
190 0 : log_error("Unknown return %d from database query", rtn);
191 0 : return WS_ERROR;
192 : }
193 : }
194 :
195 : #define DEFAULT_HTTP_HEADER\
196 : "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n" \
197 :
198 : #define DEFAULT_HTTP_BODY\
199 : "<!DOCTYPE html>\n<html>\n<body>\n<h1>Dedos New Runtime</h1>\n</body>\n</html>"
200 :
201 : #define ERROR_HTTP_HEADER\
202 : "HTTP/1.1 418 IM A TEAPOT\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n"
203 :
204 : #define ERROR_HTTP_BODY\
205 : "<!DOCTYPE html>\n<html>\n<body>\n<h1>418 I am a teapot</h1>\n</body>\n</html>"
206 :
207 1 : int craft_error_response(char UNUSED *url, char *response) {
208 1 : int n = sprintf(response, ERROR_HTTP_HEADER ERROR_HTTP_BODY,
209 : (int)strlen(ERROR_HTTP_BODY));
210 1 : return n;
211 : }
212 :
213 0 : int craft_nonregex_response(char UNUSED *url, char *response) {
214 0 : int n = sprintf(response, DEFAULT_HTTP_HEADER DEFAULT_HTTP_BODY,
215 : (int)strlen(DEFAULT_HTTP_BODY));
216 0 : log(LOG_CONNECTION_INFO, "Crafted non-regex response");
217 0 : return n;
218 : }
219 :
220 2 : int craft_regex_response(char *url, char *response) {
221 : char regex_value[MAX_REGEX_VALUE_LEN];
222 2 : int rtn = get_regex_value(url, regex_value);
223 2 : if (rtn != 0) {
224 0 : log_error("Non-regex URL passed to craft_regex_response!");
225 0 : return -1;
226 : } else {
227 : char html[4096];
228 2 : rtn = regex_html(regex_value, html);
229 2 : if (rtn < 0) {
230 0 : log_error("Error crafting regex response");
231 0 : return -1;
232 : }
233 2 : sprintf(response, DEFAULT_HTTP_HEADER "%s", (int)strlen(html), html);
234 2 : log(LOG_CONNECTION_INFO, "Crafted regex response");
235 2 : return strlen(response);
236 : }
237 : }
238 :
239 141 : int write_response(struct response_state *state) {
240 141 : if (state->body[0] == '\0' && state->header[0] == '\0') {
241 0 : log_error("Attempted to write empty response");
242 0 : return WS_ERROR;
243 : }
244 :
245 141 : int use_ssl = (state->conn.ssl != NULL);
246 141 : int bytes = state->header_len;
247 : int rtn;
248 141 : if (use_ssl) {
249 141 : rtn = write_ssl(state->conn.ssl, state->header, &bytes);
250 : } else {
251 0 : rtn = write_socket(state->conn.fd, state->header, &bytes);
252 : }
253 :
254 141 : switch (rtn) {
255 : case WS_INCOMPLETE_READ:
256 : case WS_INCOMPLETE_WRITE:
257 0 : log(LOG_CONNECTION_INFO, "Header write incomplete (fd: %d)", state->conn.fd);
258 0 : return rtn;
259 : case WS_COMPLETE:
260 140 : log(LOG_CONNECTION_INFO, "Completed writing headers (fd: %d)", state->conn.fd);
261 140 : break;
262 : case WS_ERROR:
263 1 : log_error("Error writing headers (fd: %d)", state->conn.fd);
264 1 : return WS_ERROR;
265 : default:
266 0 : log_error("Unknown return %d from call to write (fd: %d)", rtn, state->conn.fd);
267 0 : return WS_ERROR;
268 : }
269 :
270 140 : if (state->body_len > 0) {
271 140 : bytes = state->body_len;
272 140 : if (use_ssl) {
273 140 : rtn = write_ssl(state->conn.ssl, state->body, &bytes);
274 : } else {
275 0 : rtn = write_socket(state->conn.fd, state->body, &bytes);
276 : }
277 :
278 140 : switch (rtn) {
279 : case WS_INCOMPLETE_READ:
280 : case WS_INCOMPLETE_WRITE:
281 0 : log(LOG_CONNECTION_INFO, "Write incomplete (fd: %d)", state->conn.fd);
282 0 : return rtn;
283 : case WS_COMPLETE:
284 140 : log(LOG_CONNECTION_INFO, "Completed writing response (fd: %d)", state->conn.fd);
285 140 : return WS_COMPLETE;
286 : case WS_ERROR:
287 0 : log_error("Error writing response (fd: %d)", state->conn.fd);
288 0 : return WS_ERROR;
289 : default:
290 0 : log_error("Unknown return %d from call to write (fd: %d)", rtn, state->conn.fd);
291 0 : return WS_ERROR;
292 : }
293 : } else {
294 0 : return rtn;
295 : }
296 : }
297 :
298 142 : int close_connection(struct connection *conn) {
299 142 : log(LOG_CONNECTION_INFO, "Closing connection (fd: %d)", conn->fd);
300 142 : if (conn->ssl != NULL) {
301 142 : close_ssl(conn->ssl);
302 : }
303 :
304 142 : int rtn = close(conn->fd);
305 142 : if (rtn != 0) {
306 0 : log_perror("Error closing connection (fd: %d)", conn->fd);
307 0 : return WS_ERROR;
308 : }
309 142 : log(LOG_CONNECTION_INFO, "Closed connection (fd: %d)", conn->fd);
310 142 : return WS_COMPLETE;
311 : }
|