LCOV - code coverage report
Current view: top level - msus/webserver - http_msu.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 81 103 78.6 %
Date: 2018-01-11 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.10