Implemented socket_reader
This commit is contained in:
parent
c3346a4815
commit
315c11d6e2
108
httplib.h
108
httplib.h
@ -271,14 +271,31 @@ 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)
|
||||||
|
: strm_(strm)
|
||||||
|
, fixed_buffer_(fixed_buffer)
|
||||||
|
, fixed_buffer_size_(fixed_buffer_size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ptr() const {
|
||||||
|
if (glowable_buffer_.empty()) {
|
||||||
|
return fixed_buffer_;
|
||||||
|
} else {
|
||||||
|
return glowable_buffer_.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getline() {
|
||||||
|
fixed_buffer_used_size_ = 0;
|
||||||
|
glowable_buffer_.clear();
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char byte;
|
char byte;
|
||||||
auto n = strm.read(&byte, 1);
|
auto n = strm_.read(&byte, 1);
|
||||||
|
|
||||||
if (n < 1) {
|
if (n < 1) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
@ -288,25 +305,36 @@ inline bool socket_gets(Stream& strm, char* buf, size_t bufsiz)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == bufsiz) {
|
append(byte);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[i++] = byte;
|
|
||||||
|
|
||||||
if (byte == '\n') {
|
if (byte == '\n') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == bufsiz) {
|
append('\0');
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[i] = '\0';
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void append(char c) {
|
||||||
|
if (fixed_buffer_used_size_ < fixed_buffer_size_) {
|
||||||
|
fixed_buffer_[fixed_buffer_used_size_++] = c;
|
||||||
|
} else {
|
||||||
|
if (glowable_buffer_.empty()) {
|
||||||
|
glowable_buffer_.assign(fixed_buffer_, fixed_buffer_size_);
|
||||||
|
}
|
||||||
|
glowable_buffer_ += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream& strm_;
|
||||||
|
char* fixed_buffer_;
|
||||||
|
const size_t fixed_buffer_size_;
|
||||||
|
size_t fixed_buffer_used_size_;
|
||||||
|
std::string glowable_buffer_;
|
||||||
|
};
|
||||||
|
|
||||||
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]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user