From 4b8c67e2300205200f4f846400d73a03cb3da854 Mon Sep 17 00:00:00 2001 From: ipknHama Date: Tue, 1 Apr 2014 01:51:50 +0900 Subject: accept connections, print http request parsed information --- .gitmodules | 3 +++ Makefile | 8 ++++-- example.cpp | 10 ++++++- flask.h | 31 ++++++++++++++++++++++ http-parser | 1 + http_connection.h | 48 +++++++++++++++++++++++++++++++++ http_server.h | 48 +++++++++++++++++++++++++++++++++ parser.h | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ test.py | 3 +++ 9 files changed, 228 insertions(+), 3 deletions(-) create mode 100644 .gitmodules create mode 160000 http-parser create mode 100644 http_connection.h create mode 100644 http_server.h create mode 100644 parser.h create mode 100644 test.py diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..95da8a7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "http-parser"] + path = http-parser + url = https://github.com/joyent/http-parser diff --git a/Makefile b/Makefile index bc09577..66d35d5 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,7 @@ all: example -example: example.cpp - g++ -o example example.cpp +example: example.cpp flask.h http_server.h http_connection.h parser.h + g++ -g -std=c++11 -o example example.cpp http-parser/http_parser.c -pthread -lboost_system -lboost_thread -I http-parser/ +test: example + ./example & + test.py + pkill example diff --git a/example.cpp b/example.cpp index 3b07d61..904e1ff 100644 --- a/example.cpp +++ b/example.cpp @@ -1,8 +1,16 @@ #include "flask.h" +#include + flask::Flask app; int main() { - app.run(); + app.route("/", + []{ + return "Hello World!"; + }); + + app.port(8080) + .run(); } diff --git a/flask.h b/flask.h index ff134f7..c694de1 100644 --- a/flask.h +++ b/flask.h @@ -1,3 +1,15 @@ +#pragma once +#include +#include +#include +#include +#include + +#include "http_server.h" + +// TEST +#include + namespace flask { class Flask @@ -7,8 +19,27 @@ namespace flask { } + void handle() + { + } + + void route(const std::string& url, std::function f) + { + } + + Flask& port(std::uint16_t port) + { + port_ = port; + return *this; + } + void run() { + Server server(this, port_); + server.run(); } + private: + uint16_t port_ = 80; }; }; + diff --git a/http-parser b/http-parser new file mode 160000 index 0000000..d19e129 --- /dev/null +++ b/http-parser @@ -0,0 +1 @@ +Subproject commit d19e12911a1b523885bdf0d82f1f3e91df90711d diff --git a/http_connection.h b/http_connection.h new file mode 100644 index 0000000..92b06e1 --- /dev/null +++ b/http_connection.h @@ -0,0 +1,48 @@ +#pragma once +#include +#include +#include "parser.h" + +namespace flask +{ + using namespace boost; + using tcp = asio::ip::tcp; + template + class Connection + { + public: + Connection(tcp::socket&& socket, Handler* handler) : socket_(std::move(socket)), handler_(handler) + { + } + + void start() + { + do_read(); + } + + private: + void do_read() + { + socket_.async_read_some(boost::asio::buffer(buffer_), + [this](boost::system::error_code ec, std::size_t bytes_transferred) + { + if (!ec) + { + parser_.feed(buffer_.data(), bytes_transferred); + } + else + { + parser_.done(); + } + }); + } + + private: + tcp::socket socket_; + Handler* handler_; + + std::array buffer_; + + HTTPParser parser_; + }; +} diff --git a/http_server.h b/http_server.h new file mode 100644 index 0000000..002eec6 --- /dev/null +++ b/http_server.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +#include "http_connection.h" + +// TEST +#include + +namespace flask +{ + using namespace boost; + using tcp = asio::ip::tcp; + template + class Server + { + public: + Server(Handler* handler, uint16_t port) + : acceptor_(io_service_, tcp::endpoint(asio::ip::address(), port)), socket_(io_service_), handler_(handler) + { + do_accept(); + } + + void run() + { + auto _ = std::async(std::launch::async, [this]{io_service_.run();}); + } + + private: + void do_accept() + { + acceptor_.async_accept(socket_, + [this](boost::system::error_code ec) + { + if (!ec) + (new Connection(std::move(socket_), handler_))->start(); + do_accept(); + }); + } + + private: + asio::io_service io_service_; + tcp::acceptor acceptor_; + tcp::socket socket_; + Handler* handler_; + }; +} diff --git a/parser.h b/parser.h new file mode 100644 index 0000000..2f2626d --- /dev/null +++ b/parser.h @@ -0,0 +1,79 @@ +#include +#include +namespace flask +{ + struct HTTPParser : public http_parser + { + static int on_message_begin(http_parser* self_) + { + HTTPParser* self = static_cast(self_); + return 0; + } + static int on_url(http_parser* self_, const char* at, size_t length) + { + HTTPParser* self = static_cast(self_); + std::cout << std::string(at, at+length) << std::endl; + return 0; + } + static int on_status(http_parser* self_, const char* at, size_t length) + { + HTTPParser* self = static_cast(self_); + std::cout << std::string(at, at+length) << std::endl; + return 0; + } + static int on_header_field(http_parser* self_, const char* at, size_t length) + { + HTTPParser* self = static_cast(self_); + std::cout << std::string(at, at+length) << std::endl; + return 0; + } + static int on_header_value(http_parser* self_, const char* at, size_t length) + { + HTTPParser* self = static_cast(self_); + std::cout << std::string(at, at+length) << std::endl; + return 0; + } + static int on_headers_complete(http_parser* self_) + { + HTTPParser* self = static_cast(self_); + return 0; + } + static int on_body(http_parser* self_, const char* at, size_t length) + { + HTTPParser* self = static_cast(self_); + std::cout << std::string(at, at+length) << std::endl; + return 0; + } + static int on_message_complete(http_parser* self_) + { + HTTPParser* self = static_cast(self_); + return 0; + } + HTTPParser() : + settings_ { + on_message_begin, + on_url, + on_status, + on_header_field, + on_header_value, + on_headers_complete, + on_body, + on_message_complete, + } + { + http_parser_init(this, HTTP_REQUEST); + } + + void feed(const char* buffer, int length) + { + int nparsed = http_parser_execute(this, &settings_, buffer, length); + } + + void done() + { + int nparsed = http_parser_execute(this, &settings_, nullptr, 0); + } + + http_parser_settings settings_; + }; +} diff --git a/test.py b/test.py new file mode 100644 index 0000000..49b7368 --- /dev/null +++ b/test.py @@ -0,0 +1,3 @@ +import urllib +d = urllib.urlopen('http://localhost:8080').read() +print d -- cgit v1.2.3-54-g00ecf