LCOV - code coverage report
Current view: top level - msus/webserver - connection-handler.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 115 161 71.4 %
Date: 2018-01-11 Functions: 14 15 93.3 %

          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             : }

Generated by: LCOV version 1.10