From 897d2683778c8455c3c3ab0859122259f23fb896 Mon Sep 17 00:00:00 2001 From: Zhe Ma Date: Thu, 19 Sep 2019 17:13:54 +0800 Subject: [PATCH 1/3] Fix URL encoding issue. --- webcc/url.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/webcc/url.cc b/webcc/url.cc index cf9a75d..2feb1a0 100644 --- a/webcc/url.cc +++ b/webcc/url.cc @@ -98,12 +98,17 @@ std::string EncodeImpl(const std::string& raw, // UTF8 return encoded; } +// Our own implementation of alpha numeric instead of std::isalnum to avoid +// taking locale into account. +inline bool IsAlNum(int c) { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + // Characters that are allowed in a URI but do not have a reserved purpose are // are called unreserved. These include uppercase and lowercase letters, decimal // digits, hyphen, period, underscore, and tilde. inline bool IsUnreserved(int c) { - return std::isalnum((unsigned char)c) || c == '-' || c == '.' || c == '_' || - c == '~'; + return IsAlNum((unsigned char)c) || c == '-' || c == '.' || c == '_' || c == '~'; } // General delimiters serve as the delimiters between different uri components. From 3423dede5da03833a376e6e389d9698b05a96eaf Mon Sep 17 00:00:00 2001 From: Zhe Ma Date: Thu, 24 Oct 2019 16:07:44 +0800 Subject: [PATCH 2/3] Add IP address to Request. --- webcc/connection.cc | 7 +++++++ webcc/request.h | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/webcc/connection.cc b/webcc/connection.cc index f432bde..48cc41e 100644 --- a/webcc/connection.cc +++ b/webcc/connection.cc @@ -19,6 +19,13 @@ Connection::Connection(tcp::socket socket, ConnectionPool* pool, void Connection::Start() { request_.reset(new Request{}); + + boost::system::error_code ec; + auto endpoint = socket_.remote_endpoint(ec); + if (!ec) { + request_->set_ip(endpoint.address().to_string()); + } + request_parser_.Init(request_.get(), view_matcher_); DoRead(); } diff --git a/webcc/request.h b/webcc/request.h index d19e97a..dedaacf 100644 --- a/webcc/request.h +++ b/webcc/request.h @@ -55,6 +55,14 @@ public: args_ = args; } + const std::string& ip() const { + return ip_; + } + + void set_ip(const std::string& ip) { + ip_ = ip; + } + // Check if the body is a multi-part form data. bool IsForm() const; @@ -73,6 +81,9 @@ private: // The URL regex matched arguments (usually resource ID's). // Used by server only. UrlArgs args_; + + // Client IP address. + std::string ip_; }; using RequestPtr = std::shared_ptr; From a725c5fea22eab59fc66c4169c133fe1a0998936 Mon Sep 17 00:00:00 2001 From: Zhe Ma Date: Mon, 18 Nov 2019 17:33:36 +0800 Subject: [PATCH 3/3] Fix async reading timeout issue. --- webcc/client.cc | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/webcc/client.cc b/webcc/client.cc index b47b0bb..1e48fab 100644 --- a/webcc/client.cc +++ b/webcc/client.cc @@ -158,9 +158,6 @@ void Client::WriteRequest(RequestPtr request) { void Client::ReadResponse() { LOG_VERB("Read response (timeout: %ds)...", timeout_); - timer_.expires_after(std::chrono::seconds(timeout_)); - - DoWaitTimer(); DoReadResponse(); if (!error_) { @@ -179,26 +176,25 @@ void Client::DoReadResponse() { length = inner_length; }; - // Read the first piece of data asynchronously so that the timer could also - // be async-waited. - socket_->AsyncReadSome(std::move(handler), &buffer_); + while (true) { + ec = boost::asio::error::would_block; + length = 0; + + socket_->AsyncReadSome(std::move(handler), &buffer_); - // Block until the asynchronous operation has completed. - do { - io_context_.run_one(); - } while (ec == boost::asio::error::would_block); + // Start the timer. + DoWaitTimer(); - // Now we have read the first piece of data. - // The left data will be read synchronously to void stack overflow because of - // too many recursive calls. + // Block until the asynchronous operation has completed. + do { + io_context_.run_one(); + } while (ec == boost::asio::error::would_block); - // Stop the timer. - CancelTimer(); + // Stop the timer. + CancelTimer(); - do { + // The error normally is caused by timeout. See OnTimer(). if (ec || length == 0) { - // For the first async-read, the error normally is caused by timeout. - // See OnTimer(). Close(); error_.Set(Error::kSocketReadError, "Socket read error"); LOG_ERRO("Socket read error (%s).", ec.message().c_str()); @@ -230,15 +226,12 @@ void Client::DoReadResponse() { LOG_INFO("Finished to read the HTTP response."); break; } - - // Read next piece of data synchronously. - socket_->ReadSome(&buffer_, &length, &ec); - - } while (true); + } } void Client::DoWaitTimer() { LOG_VERB("Wait timer asynchronously."); + timer_.expires_after(std::chrono::seconds(timeout_)); timer_.async_wait(std::bind(&Client::OnTimer, this, std::placeholders::_1)); }