tgbot-cpp
Loading...
Searching...
No Matches
HttpServer.h
Go to the documentation of this file.
1#ifndef TGBOT_HTTPSERVER_H
2#define TGBOT_HTTPSERVER_H
3
5
6#include <boost/asio.hpp>
7
8#include <cstddef>
9#include <exception>
10#include <functional>
11#include <iostream>
12#include <memory>
13#include <string>
14#include <unordered_map>
15#include <utility>
16
17namespace TgBot {
18
24template<typename Protocol>
26
27protected:
28 class Connection;
29
30public:
31 typedef std::function<std::string (const std::string&, const std::unordered_map<std::string, std::string>&)> ServerHandler;
32
33 HttpServer(const typename boost::asio::basic_socket_acceptor<Protocol>::endpoint_type& endpoint, ServerHandler handler)
34 : _ioService(), _acceptor(_ioService, endpoint), _socket(_ioService), _handler(std::move(handler)), _httpParser()
35 {
36 }
37
41 void start() {
43 _ioService.run();
44 }
45
49 void stop() {
50 _ioService.stop();
51 }
52
53protected:
54 class Connection : public std::enable_shared_from_this<Connection> {
55
56 public:
57 Connection(boost::asio::basic_stream_socket<Protocol> socket, ServerHandler handler, const HttpParser& httpParser)
58 : _socket(std::move(socket)), _handler(std::move(handler)), _httpParser(httpParser)
59 {
60 }
61
62 void start() {
64 }
65
66 protected:
67 boost::asio::basic_stream_socket<Protocol> _socket;
70
71 void _readHeader() {
72 auto self(this->shared_from_this());
73
74 auto data(std::make_shared<boost::asio::streambuf>());
75 data->prepare(1024);
76
77 boost::asio::async_read_until(
78 _socket,
79 *data,
80 "\r\n\r\n",
81 [self, data](const boost::system::error_code& e, std::size_t n) {
82 if (e) {
83 std::cout << "error in HttpServer::Connection#_readHeader: " << e << std::endl;
84 return;
85 }
86
87 boost::asio::streambuf::const_buffers_type bufs = data->data();
88 std::string dataAsString(boost::asio::buffers_begin(bufs), boost::asio::buffers_begin(bufs) + n);
89
90 auto headers(std::make_shared<std::unordered_map<std::string, std::string>>(self->_httpParser.parseHeader(dataAsString, true)));
91
92 unsigned long long size;
93 auto contentLengthIter = headers->find("Content-Length");
94 if (contentLengthIter != headers->end()) {
95 size = std::stoull(contentLengthIter->second);
96 } else {
97 size = 0;
98 }
99
100 if (size == 0) {
101 std::string answer = self->_httpParser.generateResponse("Bad request", "text/plain", 400, "Bad request", false);
102 boost::asio::async_write(
103 self->_socket,
104 boost::asio::buffer(answer),
105 [](const boost::system::error_code&, std::size_t) { });
106 return;
107 }
108
109 data->consume(n);
110 self->_readBody(data, size, headers);
111 });
112 }
113
114 void _readBody(std::shared_ptr<boost::asio::streambuf> data, unsigned long long size, std::shared_ptr<std::unordered_map<std::string, std::string>> headers) {
115 auto self(this->shared_from_this());
116
117 data->prepare(size);
118
119 boost::asio::async_read(_socket,
120 *data,
121 boost::asio::transfer_exactly(size - data->size()),
122 [self, data, size, headers](const boost::system::error_code& e, std::size_t) {
123 if (e) {
124 std::cout << "error in HttpServer::Connection#_readBody: " << e << std::endl;
125 return;
126 }
127
128 boost::asio::streambuf::const_buffers_type bufs = data->data();
129 std::string dataAsString(boost::asio::buffers_begin(bufs), boost::asio::buffers_begin(bufs) + size);
130
131 std::string answer;
132 try {
133 answer = self->_handler(dataAsString, *headers);
134 } catch (std::exception& e) {
135 std::cout << "error in HttpServer::Connection#_readBody answer: " << e.what() << std::endl;
136 answer = self->_httpParser.generateResponse("Internal server error", "text/plain", 500, "Internal server error", false);
137 }
138 boost::asio::async_write(
139 self->_socket,
140 boost::asio::buffer(answer),
141 [](const boost::system::error_code&, std::size_t) { });
142
143 self->_socket.close();
144 });
145 }
146 };
147
149 _acceptor.async_accept(_socket, [this](const boost::system::error_code& e) {
150 if (e) {
151 std::cout << "error in HttpServer: " << e << std::endl;
152 _startAccept();
153 return;
154 }
155
156 auto connection(std::make_shared<Connection>(std::move(_socket), _handler, _httpParser));
157 connection->start();
158
159 _startAccept();
160 });
161 }
162
163 boost::asio::io_service _ioService;
164 boost::asio::basic_socket_acceptor<Protocol> _acceptor;
165 boost::asio::basic_stream_socket<Protocol> _socket;
168};
169
170}
171
172#endif //TGBOT_HTTPSERVER_H
const HttpParser & _httpParser
Definition HttpServer.h:69
boost::asio::basic_stream_socket< Protocol > _socket
Definition HttpServer.h:67
Connection(boost::asio::basic_stream_socket< Protocol > socket, ServerHandler handler, const HttpParser &httpParser)
Definition HttpServer.h:57
const ServerHandler _handler
Definition HttpServer.h:68
void _readBody(std::shared_ptr< boost::asio::streambuf > data, unsigned long long size, std::shared_ptr< std::unordered_map< std::string, std::string > > headers)
Definition HttpServer.h:114
This class handles HTTP requests from the Internet.
Definition HttpServer.h:25
std::function< std::string(const std::string &, const std::unordered_map< std::string, std::string > &)> ServerHandler
Definition HttpServer.h:31
boost::asio::basic_socket_acceptor< Protocol > _acceptor
Definition HttpServer.h:164
boost::asio::basic_stream_socket< Protocol > _socket
Definition HttpServer.h:165
boost::asio::io_service _ioService
Definition HttpServer.h:163
HttpServer(const typename boost::asio::basic_socket_acceptor< Protocol >::endpoint_type &endpoint, ServerHandler handler)
Definition HttpServer.h:33
const ServerHandler _handler
Definition HttpServer.h:166
void start()
Starts receiving new connections.
Definition HttpServer.h:41
const HttpParser _httpParser
Definition HttpServer.h:167
void stop()
Stops receiving new connections.
Definition HttpServer.h:49
Definition Api.h:40