1
0
mirror of synced 2025-04-28 09:25:05 +03:00

Implemented socket_reader

This commit is contained in:
yhirose 2017-12-06 23:52:34 -05:00
parent c3346a4815
commit 315c11d6e2
2 changed files with 86 additions and 48 deletions

130
httplib.h
View File

@ -271,41 +271,69 @@ void split(const char* b, const char* e, char d, Fn fn)
} }
} }
inline bool socket_gets(Stream& strm, char* buf, size_t bufsiz) class socket_reader {
{ public:
// TODO: buffering for better performance socket_reader(Stream& strm, char* fixed_buffer, size_t fixed_buffer_size)
size_t i = 0; : strm_(strm)
, fixed_buffer_(fixed_buffer)
, fixed_buffer_size_(fixed_buffer_size) {
}
for (;;) { const char* ptr() const {
char byte; if (glowable_buffer_.empty()) {
auto n = strm.read(&byte, 1); return fixed_buffer_;
} else {
return glowable_buffer_.data();
}
}
if (n < 1) { bool getline() {
if (i == 0) { fixed_buffer_used_size_ = 0;
return false; glowable_buffer_.clear();
} else {
size_t i = 0;
for (;;) {
char byte;
auto n = strm_.read(&byte, 1);
if (n < 1) {
if (i == 0) {
return false;
} else {
break;
}
}
append(byte);
if (byte == '\n') {
break; break;
} }
} }
if (i == bufsiz) { append('\0');
return false; return true;
} }
buf[i++] = byte; private:
void append(char c) {
if (byte == '\n') { if (fixed_buffer_used_size_ < fixed_buffer_size_) {
break; fixed_buffer_[fixed_buffer_used_size_++] = c;
} else {
if (glowable_buffer_.empty()) {
glowable_buffer_.assign(fixed_buffer_, fixed_buffer_size_);
}
glowable_buffer_ += c;
} }
} }
if (i == bufsiz) { Stream& strm_;
return false; char* fixed_buffer_;
} const size_t fixed_buffer_size_;
size_t fixed_buffer_used_size_;
buf[i] = '\0'; std::string glowable_buffer_;
return true; };
}
template <typename ...Args> template <typename ...Args>
inline void socket_printf(Stream& strm, const char* fmt, const Args& ...args) inline void socket_printf(Stream& strm, const char* fmt, const Args& ...args)
@ -562,18 +590,20 @@ inline bool read_headers(Stream& strm, MultiMap& headers)
{ {
static std::regex re("(.+?): (.+?)\r\n"); static std::regex re("(.+?): (.+?)\r\n");
const auto BUFSIZ_HEADER = 2048; const auto bufsiz = 2048;
char buf[BUFSIZ_HEADER]; char buf[bufsiz];
socket_reader reader(strm, buf, bufsiz);
for (;;) { for (;;) {
if (!socket_gets(strm, buf, BUFSIZ_HEADER)) { if (!reader.getline()) {
return false; return false;
} }
if (!strcmp(buf, "\r\n")) { if (!strcmp(reader.ptr(), "\r\n")) {
break; break;
} }
std::cmatch m; std::cmatch m;
if (std::regex_match(buf, m, re)) { if (std::regex_match(reader.ptr(), m, re)) {
auto key = std::string(m[1]); auto key = std::string(m[1]);
auto val = std::string(m[2]); auto val = std::string(m[2]);
headers.emplace(key, val); headers.emplace(key, val);
@ -622,14 +652,16 @@ bool read_content_without_length(Stream& strm, T& x)
template <typename T> template <typename T>
bool read_content_chunked(Stream& strm, T& x) bool read_content_chunked(Stream& strm, T& x)
{ {
const auto BUFSIZ_CHUNK_LEN = 16; const auto bufsiz = 16;
char buf[BUFSIZ_CHUNK_LEN]; char buf[bufsiz];
if (!socket_gets(strm, buf, BUFSIZ_CHUNK_LEN)) { socket_reader reader(strm, buf, bufsiz);
if (!reader.getline()) {
return false; return false;
} }
auto chunk_len = std::stoi(buf, 0, 16); auto chunk_len = std::stoi(reader.ptr(), 0, 16);
while (chunk_len > 0){ while (chunk_len > 0){
std::string chunk(chunk_len, 0); std::string chunk(chunk_len, 0);
@ -639,21 +671,21 @@ bool read_content_chunked(Stream& strm, T& x)
return false; return false;
} }
if (!socket_gets(strm, buf, BUFSIZ_CHUNK_LEN)) { if (!reader.getline()) {
return false; return false;
} }
if (strcmp(buf, "\r\n")) { if (strcmp(reader.ptr(), "\r\n")) {
break; break;
} }
x.body += chunk; x.body += chunk;
if (!socket_gets(strm, buf, BUFSIZ_CHUNK_LEN)) { if (!reader.getline()) {
return false; return false;
} }
chunk_len = std::stoi(buf, 0, 16); chunk_len = std::stoi(reader.ptr(), 0, 16);
} }
return true; return true;
@ -1169,16 +1201,19 @@ inline void Server::stop()
inline bool Server::read_request_line(Stream& strm, Request& req) inline bool Server::read_request_line(Stream& strm, Request& req)
{ {
const auto BUFSIZ_REQUESTLINE = 2048; const auto bufsiz = 2048;
char buf[BUFSIZ_REQUESTLINE]; char buf[bufsiz];
if (!detail::socket_gets(strm, buf, BUFSIZ_REQUESTLINE)) {
detail::socket_reader reader(strm, buf, bufsiz);
if (!reader.getline()) {
return false; return false;
} }
static std::regex re("(GET|HEAD|POST) ([^?]+)(?:\\?(.+?))? HTTP/1\\.[01]\r\n"); static std::regex re("(GET|HEAD|POST) ([^?]+)(?:\\?(.+?))? HTTP/1\\.[01]\r\n");
std::cmatch m; std::cmatch m;
if (std::regex_match(buf, m, re)) { if (std::regex_match(reader.ptr(), m, re)) {
req.method = std::string(m[1]); req.method = std::string(m[1]);
req.path = detail::decode_url(m[2]); req.path = detail::decode_url(m[2]);
@ -1327,16 +1362,19 @@ inline Client::~Client()
inline bool Client::read_response_line(Stream& strm, Response& res) inline bool Client::read_response_line(Stream& strm, Response& res)
{ {
const auto BUFSIZ_RESPONSELINE = 2048; const auto bufsiz = 2048;
char buf[BUFSIZ_RESPONSELINE]; char buf[bufsiz];
if (!detail::socket_gets(strm, buf, BUFSIZ_RESPONSELINE)) {
detail::socket_reader reader(strm, buf, bufsiz);
if (!reader.getline()) {
return false; return false;
} }
const static std::regex re("HTTP/1\\.[01] (\\d+?) .+\r\n"); const static std::regex re("HTTP/1\\.[01] (\\d+?) .+\r\n");
std::cmatch m; std::cmatch m;
if (std::regex_match(buf, m, re)) { if (std::regex_match(reader.ptr(), m, re)) {
res.status = std::stoi(std::string(m[1])); res.status = std::stoi(std::string(m[1]));
} }

View File

@ -409,7 +409,7 @@ TEST_F(ServerTest, TooLongRequest)
auto res = cli_.get("/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/__ng___"); auto res = cli_.get("/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/__ng___");
ASSERT_TRUE(res != nullptr); ASSERT_TRUE(res != nullptr);
EXPECT_EQ(400, res->status); EXPECT_EQ(404, res->status);
} }
TEST_F(ServerTest, LongHeader) TEST_F(ServerTest, LongHeader)
@ -457,7 +457,7 @@ TEST_F(ServerTest, TooLongHeader)
auto ret = cli_.send(req, *res); auto ret = cli_.send(req, *res);
ASSERT_TRUE(ret); ASSERT_TRUE(ret);
EXPECT_EQ(400, res->status); EXPECT_EQ(200, res->status);
} }
TEST_F(ServerTest, PercentEncoding) TEST_F(ServerTest, PercentEncoding)