Commit 61728942 authored by James Allenby's avatar James Allenby
Browse files

Various changes

parent e6d8a85f
......@@ -2,4 +2,4 @@ cmake_minimum_required(VERSION 2.8)
project(JAMP)
set(CMAKE_CXX_STANDARD "17")
add_executable(${PROJECT_NAME} "main.cc" "httpresponse.cc")
add_executable(${PROJECT_NAME} "main.cc" "httpresponse.cc" "httprequest.cc")
#ifndef HTTPCOMMON_H
#define HTTPCOMMON_H
#include <map>
namespace JAMP
{
enum class Method {
......@@ -62,6 +64,92 @@ namespace JAMP
HTTP_504, // 504 Gateway Timeout
HTTP_505, // 505 HTTP Version Not Supported
};
const static std::map<JAMP::Code, std::string> StringCode = {
{ Code::HTTP_100, "100" },
{ Code::HTTP_101, "101" },
{ Code::HTTP_200, "200" },
{ Code::HTTP_201, "201" },
{ Code::HTTP_202, "202" },
{ Code::HTTP_203, "203" },
{ Code::HTTP_204, "204" },
{ Code::HTTP_205, "205" },
{ Code::HTTP_300, "300" },
{ Code::HTTP_301, "301" },
{ Code::HTTP_302, "302" },
{ Code::HTTP_303, "303" },
{ Code::HTTP_305, "305" },
{ Code::HTTP_306, "306" },
{ Code::HTTP_307, "307" },
{ Code::HTTP_400, "400" },
{ Code::HTTP_402, "402" },
{ Code::HTTP_403, "403" },
{ Code::HTTP_404, "404" },
{ Code::HTTP_405, "405" },
{ Code::HTTP_406, "406" },
{ Code::HTTP_408, "408" },
{ Code::HTTP_409, "409" },
{ Code::HTTP_410, "410" },
{ Code::HTTP_411, "411" },
{ Code::HTTP_413, "413" },
{ Code::HTTP_414, "414" },
{ Code::HTTP_415, "415" },
{ Code::HTTP_417, "417" },
{ Code::HTTP_426, "426" },
{ Code::HTTP_500, "500" },
{ Code::HTTP_501, "501" },
{ Code::HTTP_502, "502" },
{ Code::HTTP_503, "503" },
{ Code::HTTP_504, "504" },
{ Code::HTTP_505, "505" },
};
const static std::map<JAMP::Code, std::string> ReasonPhrase = {
{ Code::HTTP_100, "Continue" },
{ Code::HTTP_101, "Switching Protocols" },
{ Code::HTTP_200, "OK" },
{ Code::HTTP_201, "Created" },
{ Code::HTTP_202, "Accepted" },
{ Code::HTTP_203, "Non-Authoritative Information" },
{ Code::HTTP_204, "No Content" },
{ Code::HTTP_205, "Reset Content" },
{ Code::HTTP_300, "Multiple Choices" },
{ Code::HTTP_301, "Moved Permanently" },
{ Code::HTTP_302, "Found" },
{ Code::HTTP_303, "See Other" },
{ Code::HTTP_305, "Use Proxy" },
{ Code::HTTP_306, "(Unused)" },
{ Code::HTTP_307, "Temporary Redirect" },
{ Code::HTTP_400, "Bad Request" },
{ Code::HTTP_402, "Payment Required" },
{ Code::HTTP_403, "Forbidden" },
{ Code::HTTP_404, "Not Found" },
{ Code::HTTP_405, "Method Not Allowed" },
{ Code::HTTP_406, "Not Acceptable" },
{ Code::HTTP_408, "Request Timeout" },
{ Code::HTTP_409, "Conflict" },
{ Code::HTTP_410, "Gone" },
{ Code::HTTP_411, "Length Required" },
{ Code::HTTP_413, "Payload Too Large" },
{ Code::HTTP_414, "URI Too Long" },
{ Code::HTTP_415, "Unsupported Media Type" },
{ Code::HTTP_417, "Expectation Failed" },
{ Code::HTTP_426, "Upgrade Required" },
{ Code::HTTP_500, "Internal Server Error" },
{ Code::HTTP_501, "Not Implemented" },
{ Code::HTTP_502, "Bad Gateway" },
{ Code::HTTP_503, "Service Unavailable" },
{ Code::HTTP_504, "Gateway Timeout" },
{ Code::HTTP_505, "HTTP Version Not Supported" },
};
}
#endif // HTTPCOMMON_H
#include "httprequest.hh"
#include <iostream>
#include <algorithm>
namespace JAMP
{
void HTTPRequest::Deserialize(std::string in_request)
{
JAMP::Method method;
std::string uri;
std::string http_version;
std::multimap<std::string, std::string> fields;
std::string message;
constexpr size_t header_start = 0;
const size_t start_line_end = in_request.find("\r\n");
const size_t header_fields_start = start_line_end + 2;
const size_t header_end = in_request.find("\r\n\r\n", header_start);
const size_t message_body_start = header_end + 4;
const size_t message_body_end = in_request.size();
// A HTTP request MUST have a header end position
if (header_end == std::string::npos)
throw "Invalid HTTP request";
// A HTTP request MUST have at least 1 header provided
if (start_line_end == header_end)
throw "Invalid HTTP request";
{ // Process HTTP Start Line
// Copy the entire start line into a string
std::string start_line = in_request.substr(0, start_line_end);
// Find the position of the end of method
size_t method_end_position = start_line.find(" ", 0);
if (method_end_position == std::string::npos)
throw "Malformed start line";
// Find the position of the end of URI
size_t uri_end_position = start_line.find(" ", method_end_position + 1);
if (uri_end_position == std::string::npos)
throw "Malformed start line";
// Store the request method as string
std::string in_method = start_line.substr(0, method_end_position);
// Copy the request method
if (in_method == "GET") method = JAMP::Method::GET;
else if (in_method == "HEAD") method = JAMP::Method::HEAD;
else if (in_method == "POST") method = JAMP::Method::POST;
else if (in_method == "PUT") method = JAMP::Method::PUT;
else if (in_method == "DELETE") method = JAMP::Method::DELETE;
else if (in_method == "CONNECT") method = JAMP::Method::CONNECT;
else if (in_method == "OPTIONS") method = JAMP::Method::OPTIONS;
else if (in_method == "TRACE") method = JAMP::Method::TRACE;
else throw "Unknown request method";
// Copy the request URI
uri = start_line.substr(method_end_position + 1, start_line.size() - 9 - method_end_position);
// Copy the HTTP version
http_version = start_line.substr(uri_end_position + 1, start_line.size() - uri_end_position);
}
// Store vector of other header fields and set the current position correctly
// Set current_position to (start_line_end + 2), accounting for CRLF sequence
size_t current_position = header_fields_start;
// Process the header fields and store them into an array while we are not
// past the header end position.
while (current_position < header_end)
{
// Find the next line break sequence and store
size_t header_field_end = in_request.find("\r\n", current_position);
// Store the current header field as a string
std::string header_field = in_request.substr(current_position, header_field_end - current_position);
std::string key = "";
std::string value = "";
size_t key_end_pos = header_field.find(":", 0);
if (key_end_pos == std::string::npos)
throw "Bad header field";
key = header_field.substr(0, key_end_pos);
size_t value_start_pos = key_end_pos + 1;
if (header_field[key_end_pos + 1] == ' ')
value_start_pos++;
value = header_field.substr(value_start_pos, header_field.size() - value_start_pos);
fields.emplace(key, value);
// Set current position to field length + 2 to account for CRLF sequence
current_position = header_field_end + 2;
}
this->m_method = method;
this->m_uri = uri;
this->m_http_version = http_version;
this->m_fields = fields;
}
}
#ifndef HTTPREQUEST_HH
#define HTTPREQUEST_HH
#include <string>
#include <vector>
#include <map>
#include "httpcommon.h"
namespace JAMP
{
class HTTPRequest
{
private:
// Start line variables
JAMP::Method m_method;
std::string m_uri;
std::string m_http_version;
// Header field key-value pairs
std::multimap<std::string, std::string> m_fields;
// Message
std::string m_message;
public:
// Returns string version of this request
std::string Serialize();
// Takes in a string and converts into correct types
void Deserialize(std::string);
};
}
#endif // HTTPREQUEST_HH
#include "httpresponse.h"
namespace HTTPResponse
#include <string>
namespace JAMP
{
void HTTPResponse::SetResponseCode(JAMP::Code response_code)
{
this->m_response_code = response_code;
this->m_reason_phrase = JAMP::ReasonPhrase.at(response_code);
return;
}
void HTTPResponse::SetMessageBody(std::string message_body)
{
m_message_body = message_body;
return;
}
std::string HTTPResponse::Serialize()
{
std::string CRLF = "\r\n";
std::string result;
{
result += "HTTP/1.1 " + JAMP::StringCode.at(this->m_response_code) + " " + JAMP::ReasonPhrase.at(this->m_response_code) + CRLF;
} // Craft Start Line
result += "Return-Code: GOOD" + CRLF + CRLF;
result += this->m_message_body;
return result;
}
}
......@@ -5,14 +5,21 @@
#include "httpcommon.h"
namespace HTTPResponse
namespace JAMP
{
struct HTTPResponse
{
std::string http_version;
HTTP::Code status_code;
std::string reason_phrase;
};
class HTTPResponse
{
private:
JAMP::Code m_response_code;
std::string m_reason_phrase;
std::string m_message_body;
public:
void SetResponseCode(JAMP::Code response_code);
void SetMessageBody(std::string message_body);
std::string Serialize();
};
}
#endif // HTTPRESPONSE_H
......@@ -12,105 +12,8 @@
#include <netinet/in.h>
#include "httpcommon.h"
struct HTTPRequest
{
HTTP::Method method;
std::string uri;
std::string http_version;
std::vector<std::string> fields;
std::string message;
};
int ConvertToHTTPRequest(std::string input, HTTPRequest* output = nullptr)
{
// Store the position of request header end
// Complies with RFC7230 Section 3
size_t header_end_position = input.find("\r\n\r\n");
// Fail if unable to find request header end
if (header_end_position == std::string::npos)
{
std::cerr << "Could not find end of request header" << std::endl;
return -1;
}
// Store the start_line of the HTTP request
size_t start_line_end = input.find("\r\n", 0);
std::string start_line = input.substr(0, start_line_end);
// Store vector of other header fields and set the current position correctly
// Set current_position to (start_line_end + 2), accounting for CRLF sequence
std::vector<std::string> header_fields;
size_t current_position = start_line_end + 2;
// Process the header fields and store them into an array while we are not
// past the header end position.
while (current_position < header_end_position)
{
// Find the next line break sequence and store
size_t header_field_length = input.find("\r\n", current_position);
header_fields.push_back(input.substr(current_position, header_field_length - current_position));
// Set current position to field length + 2 to account for CRLF sequence
current_position = header_field_length + 2;
}
if (output)
{
// Process method
size_t method_end_position = start_line.find(" ", 0);
if (method_end_position == std::string::npos)
{
std::cerr << "Malformed start line" << std::endl;
return -1;
}
size_t uri_end_position = start_line.find(" ", method_end_position + 1);
if (uri_end_position == std::string::npos)
{
std::cerr << "Malformed start line" << std::endl;
return -1;
}
std::string method_string = start_line.substr(0, method_end_position);
if (method_string == "GET")
output->method = HTTP::Method::GET;
else if (method_string == "HEAD")
output->method = HTTP::Method::HEAD;
else if (method_string == "POST")
output->method = HTTP::Method::POST;
else if (method_string == "PUT")
output->method = HTTP::Method::PUT;
else if (method_string == "DELETE")
output->method = HTTP::Method::DELETE;
else if (method_string == "CONNECT")
output->method = HTTP::Method::CONNECT;
else if (method_string == "OPTIONS")
output->method = HTTP::Method::OPTIONS;
else if (method_string == "TRACE")
output->method = HTTP::Method::TRACE;
else
{
std::cerr << "Unknown request method" << std::endl;
return -1;
}
// Process URI
std::string uri_string = start_line.substr(method_end_position + 1, start_line.size() - 9 - method_end_position);
// Process HTTP version
std::string http_version_string = start_line.substr(uri_end_position + 1, start_line.size() - uri_end_position);
output->uri = uri_string;
output->http_version = http_version_string;
output->fields = header_fields;
}
return 0;
}
#include "httprequest.hh"
#include "httpresponse.h"
void SendIndexPage(int connectionfd)
{
......@@ -124,11 +27,6 @@ void SendIndexPage(int connectionfd)
int main()
{
// std::string payload_test = "GET /fucked/dsfdsiuhfsd/sdfsd/sdfsd%20 HTTP/1.1\r\n"
// "Host: CurlSomething\r\n"
// "\r\n"
// "dsfsdiojfiodsjsdfojsdoif_dspijfids";
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
......@@ -162,19 +60,20 @@ int main()
char incoming_data_buffer[8192];
ssize_t buffer_len = read(connectionfd, &incoming_data_buffer, 8192);
std::string incoming_request(incoming_data_buffer, buffer_len);
std::string incoming_request(incoming_data_buffer, static_cast<size_t>(buffer_len));
HTTPRequest req;
ConvertToHTTPRequest(incoming_request, &req);
JAMP::HTTPRequest request;
request.Deserialize(incoming_request);
std::cout << "Client requested URI: " << req.uri << std::endl;
std::for_each(req.fields.begin(), req.fields.end(), [](std::string field){
std::cout << field << std::endl;
});
JAMP::HTTPResponse response;
response.SetResponseCode(JAMP::Code::HTTP_413);
response.SetMessageBody("<html><body><h1>Hello, world!</h1><hr></body></html>");
SendIndexPage(connectionfd);
std::string response_str = response.Serialize();
write(connectionfd, response_str.c_str(), response_str.size());
usleep(100000);
SendIndexPage(connectionfd);
close(connectionfd);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment