Skip to content

schung507/Team-KBBQ

 
 

Repository files navigation

Team KBBQ

Webserver API

Request

To create a request object call auto request = Request::Parse(request). Other functions return information on the parsed request.

static std::unique_ptr<Request> Parse(const std::string& raw_request);
std::string raw_request() const;
std::string method() const;
std::string uri() const;
std::string version() const;
using Headers = std::vector<std::pair<std::string, std::string>>;
Headers headers() const;
std::string body() const;

Response

The response class defines response codes and simple functions to set status, headers, and body of response which can be outputted in ToString().

enum ResponseCode {
        OK = 200,
        BAD_REQUEST = 400,
        NOT_FOUND = 404,
        NOT_IMPLEMENTED = 501
};
void SetStatus(const ResponseCode response_code);
void AddHeader(const std::string& header_name, const std::string& header_value);
void SetBody(const std::string& body);
std::string ToString();

Request Handler

enum Status {
        OK = 0,
        INVALID_CONFIG = 1,
        INVALID_URI = 2,
        FILE_NOT_FOUND = 3
    };
virtual Status Init(const std::string& uri_prefix, const NginxConfig& config) = 0;
virtual Status HandleRequest(const Request& request, Response* response) = 0;
static RequestHandler* CreateByName(const char* type);
  • Init initializes the handler. The uri_prefix is the value in the config file specified for the current handler. The config must be the child block for this handler ONLY.
  • HandleRequest handles an HTTP request, and generates a response.
  • Use CreateByName to generate a pointer to the handler specified in the argument (eg. auto handler = RequestHandler::CreateByName("EchoHandler")).

EchoHandler

Gives the same request back to server.

StaticFileHandler

Returns specified file to the server. get_content_type returns the type of file based on the extension. get_file attempts to open file and returns a corresponding response code. Both functions are called in HandleRequest.

std::string get_content_type(const std::string &filename);
Response::ResponseCode get_file(const std::string& file_path, std::string* contents);

NotFoundHandler

Returns a 404 response.

Server

parse_config parses the config file while load_configs and stores all the information. Any errors during parsing will result in syntax_error. add_handler initializes the specified handler and stores the handler pointer in a handler map (prefix -> handler).

bool parse_config(const char* file_name);
bool load_configs(NginxConfig config);
bool syntax_error(std::shared_ptr<NginxConfigStatement> parent_statement);
bool add_handler(std::string attribute, NginxConfig child_config, const char* handler_name);

get_handler calls find_prefix which will return the longest matching uri prefix if it exists. Then get_handler goes through the handler map and returns the corresponding handler pointer. get_port returns the port number.

virtual RequestHandler* get_handler(std::string uri);
std::string find_prefix(std::string uri);
unsigned short get_port();

Main calls run_server which calls session internally, creating a socket and accepting requests. Most dispatch is handled in session.

void run_server(boost::asio::io_service& io_service);
void session(boost::asio::ip::tcp::socket sock);

Dispatch

In Webserver_main.cc:
bool parse_config(const char* file_name) parses config file.

  • Ignore comments
  • Save the port number
  • For each handler block:
    • Parse first line
    • RequestHandler* handler = RequestHandler::CreatebyName(<handler_name>)
    • handler->Init(uri, child_block)
    • Put handler into map (uri -> handler). Duplicate paths are illegal.

void run_server(boost::asio::io_service& io_service) creates socket and calls void session(boost::asio::ip::tcp::socket sock).

In Webserver.cc:
void session(boost::asio::ip::tcp::socket sock)

  • Read request from the socket
  • Parse into Request class with Request::Parse(&request)
  • Call get_handler(uri) which will return appropriate handler
  • handler->HandleRequest(*request, &response)
  • Write response to socket

Build

Config File Format

Specify a handler for each block. If there is no root folder, leave the block empty.

#comments

port <number>;

#specify uri for each type of handler
path /<uri> <handler-name> {
    root /<directory>;
}

#specify a default handler if no handler matches
default <handler-name>{
    
}

Run server

make Webserver
./Webserver <config-file>

Test

make test //runs integration test
make coverage //runs all unit tests

Database Handler Dependencies

The database handler requires a MySQL server installed and mysqlclient and mysqlcppconn libraries. These can be installed with

sudo apt-get install mysql-server mysql-client libmysqlclient-dev libmysqlcppconn-dev

The directory containing mysqld needs to be added to the $PATH variable to run thr server.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C++ 80.1%
  • CSS 12.0%
  • HTML 3.8%
  • Makefile 2.4%
  • Python 1.7%