Skip to content

Commit

Permalink
First implementation of HTTPS
Browse files Browse the repository at this point in the history
  • Loading branch information
Lunderberg committed Oct 26, 2017
1 parent e10ff57 commit 813cbd9
Show file tree
Hide file tree
Showing 12 changed files with 392 additions and 225 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
*~
build
bin
.sconsign.dblite
.sconsign.dblite
server.pem
2 changes: 2 additions & 0 deletions SConscript
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Import('env')

env.Append(LIBS=['ssl','crypto'])

env.CompileFolderDWIM('.', requires='asio')
21 changes: 21 additions & 0 deletions build-keys.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

set -euo pipefail

# Make a key
openssl genrsa -des3 -out server.key 1024

# Make a signing request
openssl req -new -key server.key -out server.csr

# Fulfill the signing request, with own key
openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt

# Make a Diffie-Hallman pair
openssl dhparam -out dh1024.pem 1024

# Merge files
cat server.key > server.pem
cat server.crt >> server.pem
cat dh1024.pem >> server.pem
rm -f server.key dh1024.pem server.csr
39 changes: 27 additions & 12 deletions example-server.cc
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
#include <iostream>

#include "server.hh"
#include "http_server.hh"
#include "https_server.hh"
#include "FileServer.hh"

int main(int argc, char** argv) {
try {
if(argc != 4) {
std::cerr << "Usage: example-server <address> <port> <root>\n"
<< " For IPv4, try\n"
<< " example-server 0.0.0.0 80 .\n"
<< " For IPv6, try\n"
<< " example-server 0::0 80 .\n";
return 1;
}

http::server server(argv[1], argv[2], argv[3]);
server.run();
// if(argc != 4) {
// std::cerr << "Usage: example-server <address> <port> <root>\n"
// << " For IPv4, try\n"
// << " example-server 0.0.0.0 80 .\n"
// << " For IPv6, try\n"
// << " example-server 0::0 80 .\n";
// return 1;
// }

asio::io_service io_service;

http::http_server http_server(io_service, "localhost", "12345", http::FileServer("."));
http::https_server https_server(io_service, "localhost", "12346", http::FileServer("."));

asio::signal_set signals(io_service);
signals.add(SIGINT);
signals.add(SIGTERM);
signals.async_wait(
[&](std::error_code /*ec*/, int /*signo*/) {
http_server.close();
https_server.close();
});

io_service.run();

} catch (std::exception& e) {
std::cerr << "exception: " << e.what() << std::endl;
Expand Down
92 changes: 72 additions & 20 deletions include/Connection.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,89 @@

#include "asio.hpp"

#include "CommonReplies.hh"
#include "Reply.hh"
#include "Request.hh"
#include "RequestParser.hh"

namespace http {
class Connection : public std::enable_shared_from_this<Connection> {
public:
Connection(const Connection&) = delete;
Connection& operator=(const Connection&) = delete;

Connection(asio::ip::tcp::socket socket,
std::function<Reply(Request)> generate_reply);
template<typename SocketType>
class Connection : public std::enable_shared_from_this<Connection<SocketType> > {
public:
Connection(std::unique_ptr<SocketType> socket,
std::function<Reply(Request)> generate_reply)
: socket(std::move(socket)), generate_reply(generate_reply) { }

void start();
void stop();
void start() { init(); }
void stop() { socket->lowest_layer().close(); }

void set_on_close(std::function<void(Connection*)> callback) {
on_close = callback;
}
void set_on_close(std::function<void()> callback) {
on_close = callback;
}

private:
void do_read();
void do_write();
private:
void init() {
do_read();
}

asio::ip::tcp::socket socket;
void do_read() {
auto keep_alive = this->shared_from_this();
socket->async_read_some(
asio::buffer(buffer),
[this, keep_alive](std::error_code ec, std::size_t bytes_transferred) {
if(!ec) {

std::function<void(Connection*)> on_close;
std::function<Reply(Request)> generate_reply;
std::string data_received(buffer.data(), bytes_transferred);
Request request = parse_request(buffer.data(), buffer.data()+bytes_transferred);

if(request.parse_result != good and request.parse_result != bad) {
do_read();
return;
}

if(request.parse_result == good) {
reply = generate_reply(request);
} else if(request.parse_result == bad) {
reply = common_reply(Reply::bad_request);
}

reply.headers["Content-Length"] = std::to_string(reply.content.size());
do_write();

} else if (ec != asio::error::operation_aborted && on_close) {
on_close();
}
});
}


void do_write() {
auto keep_alive = this->shared_from_this();
asio::async_write(
*socket, reply.asio_buffers(),
[this, keep_alive](std::error_code ec, std::size_t /*bytes_transferred*/) {
if(!ec) {
std::error_code ignored_ec;
socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both,
ignored_ec);
}

if(ec != asio::error::operation_aborted && on_close) {
on_close();
}
});
}

std::unique_ptr<SocketType> socket;

std::function<void()> on_close;
std::function<Reply(Request)> generate_reply;

std::array<char, 8192> buffer;
Reply reply;
};

std::array<char, 8192> buffer;
Reply reply;
};
}

#endif /* _CONNECTION_H_ */
43 changes: 43 additions & 0 deletions include/http_server.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef _HTTP_SERVER_H_
#define _HTTP_SERVER_H_

#include <functional>
#include <set>
#include <string>

#include <asio.hpp>

#include "Connection.hh"
#include "Reply.hh"
#include "Request.hh"

namespace http {
class http_server {
typedef asio::ip::tcp::socket socket_t;
//typedef asio::ssl::stream<asio::ip::tcp::socket> ssl_socket;

public:
http_server(asio::io_service& io_service,
std::string address, std::string port,
std::function<Reply(Request)> generator);

void run();
void stop_all();
void close();

private:
void do_wait_for_signal();
void do_accept();

void setup_new_conn();

asio::io_service& io_service;
asio::ip::tcp::acceptor acceptor;
std::unique_ptr<socket_t> socket;

std::function<Reply(Request)> generator;
std::set<std::shared_ptr<Connection<socket_t> > > connections;
};
}

#endif /* _HTTP_SERVER_H_ */
48 changes: 48 additions & 0 deletions include/https_server.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#ifndef _HTTPS_SERVER_H_
#define _HTTPS_SERVER_H_

#include <functional>
#include <set>
#include <string>

#include <asio.hpp>
#include <asio/ssl.hpp>

#include "Connection.hh"
#include "Reply.hh"
#include "Request.hh"

namespace http {
class https_server {
public:
typedef asio::ssl::stream<asio::ip::tcp::socket> socket_t;

https_server(asio::io_service& io_service,
std::string address, std::string port,
std::function<Reply(Request)> generator);

void run();
void stop_all();
void close();

private:
void do_wait_for_signal();
void do_accept();

void setup_new_conn();

std::string get_password();

asio::ssl::context& generate_context();

asio::io_service& io_service;
asio::ip::tcp::acceptor acceptor;
asio::ssl::context context;
std::unique_ptr<socket_t> socket;

std::function<Reply(Request)> generator;
std::set<std::shared_ptr<Connection<socket_t> > > connections;
};
}

#endif /* _HTTPS_SERVER_H_ */
44 changes: 0 additions & 44 deletions include/server.hh

This file was deleted.

Loading

0 comments on commit 813cbd9

Please sign in to comment.