diff --git a/examples/client_basics.cc b/examples/client_basics.cc index 62b314d..d5a6fb7 100644 --- a/examples/client_basics.cc +++ b/examples/client_basics.cc @@ -31,6 +31,7 @@ int main() { Url("http://httpbin.org/get"). Query("key1", "value1"). Query("key2", "value2"). + Date(). Header("Accept", "application/json") ()); diff --git a/unittest/utility_unittest.cc b/unittest/utility_unittest.cc index 4e16d83..dae3b84 100644 --- a/unittest/utility_unittest.cc +++ b/unittest/utility_unittest.cc @@ -8,7 +8,7 @@ TEST(UtilityTest, SplitKV) { std::string key; std::string value; - bool ok = webcc::SplitKV(str, ':', &key, &value); + bool ok = webcc::utility::SplitKV(str, ':', &key, &value); EXPECT_EQ(true, ok); EXPECT_EQ("Connection", key); diff --git a/webcc/client_session.cc b/webcc/client_session.cc index bb65d5a..5e5fc05 100644 --- a/webcc/client_session.cc +++ b/webcc/client_session.cc @@ -3,6 +3,7 @@ #include "webcc/base64.h" #include "webcc/logger.h" #include "webcc/url.h" +#include "webcc/utility.h" namespace webcc { @@ -124,7 +125,7 @@ ResponsePtr ClientSession::Patch(const std::string& url, std::string&& data, void ClientSession::InitHeaders() { using namespace headers; - headers_.Set(kUserAgent, UserAgent()); + headers_.Set(kUserAgent, utility::UserAgent()); // Content-Encoding Tokens: // (https://en.wikipedia.org/wiki/HTTP_compression) diff --git a/webcc/common.cc b/webcc/common.cc index c754672..f1e23af 100644 --- a/webcc/common.cc +++ b/webcc/common.cc @@ -98,7 +98,7 @@ std::vector
::iterator Headers::Find(const std::string& key) { static bool ParseValue(const std::string& str, const std::string& expected_key, std::string* value) { std::string key; - if (!SplitKV(str, '=', &key, value)) { + if (!utility::SplitKV(str, '=', &key, value)) { return false; } @@ -182,7 +182,7 @@ bool ContentDisposition::Init(const std::string& str) { std::string key; std::string value; for (std::size_t i = 1; i < parts.size(); ++i) { - if (!SplitKV(parts[i], '=', &key, &value)) { + if (!utility::SplitKV(parts[i], '=', &key, &value)) { return false; } diff --git a/webcc/globals.cc b/webcc/globals.cc index dd33279..7402187 100644 --- a/webcc/globals.cc +++ b/webcc/globals.cc @@ -8,11 +8,6 @@ namespace webcc { // ----------------------------------------------------------------------------- -const std::string& UserAgent() { - static std::string s_user_agent = std::string("Webcc/") + WEBCC_VERSION; - return s_user_agent; -} - namespace media_types { // TODO: Add more. diff --git a/webcc/globals.h b/webcc/globals.h index 24efe10..4e0e14b 100644 --- a/webcc/globals.h +++ b/webcc/globals.h @@ -38,8 +38,6 @@ #endif // _MSC_VER -#define ARRAY_SIZE(A) (sizeof(A) / sizeof(*(A))) - namespace webcc { // ----------------------------------------------------------------------------- @@ -149,9 +147,6 @@ enum class ContentEncoding { kDeflate, }; -// Return default user agent for HTTP headers. -const std::string& UserAgent(); - // ----------------------------------------------------------------------------- // Client side error codes. diff --git a/webcc/gzip.cc b/webcc/gzip.cc index ed18281..28489e2 100644 --- a/webcc/gzip.cc +++ b/webcc/gzip.cc @@ -49,7 +49,7 @@ bool Compress(const std::string& input, std::string* output) { } std::size_t size = buf.size() - stream.avail_out; - output->insert(output->end(), buf.data(), buf.data() + size); + output->append(buf.data(), size); } while (stream.avail_out == 0); @@ -106,6 +106,7 @@ bool Decompress(const std::string& input, std::string* output) { if (err == Z_STREAM_END) { break; } + if (err != Z_OK) { inflateEnd(&stream); if (stream.msg != nullptr) { diff --git a/webcc/message.cc b/webcc/message.cc index 9a9d0d8..80cc9aa 100644 --- a/webcc/message.cc +++ b/webcc/message.cc @@ -1,7 +1,5 @@ #include "webcc/message.h" -#include -#include // for put_time #include #include "boost/algorithm/string.hpp" @@ -181,11 +179,4 @@ std::string Message::Dump(std::size_t indent, return ss.str(); } -std::string Message::GetTimestamp() { - std::time_t t = std::time(nullptr); - std::stringstream ss; - ss << std::put_time(std::gmtime(&t), "%a, %d %b %Y %H:%M:%S") << " GMT"; - return ss.str(); -} - } // namespace webcc diff --git a/webcc/message.h b/webcc/message.h index f8e2983..07387ad 100644 --- a/webcc/message.h +++ b/webcc/message.h @@ -112,11 +112,6 @@ protected: SetHeader(headers::kContentLength, std::to_string(content_length)); } - // Get the timestamp for HTTP Date header field. - // E.g., Wed, 21 Oct 2015 07:28:00 GMT - // See: https://tools.ietf.org/html/rfc7231#section-7.1.1.2 - std::string GetTimestamp(); - protected: std::string start_line_; diff --git a/webcc/parser.cc b/webcc/parser.cc index 8c5c575..f4aca5c 100644 --- a/webcc/parser.cc +++ b/webcc/parser.cc @@ -138,7 +138,7 @@ bool Parser::GetNextLine(std::size_t off, std::string* line, bool erase) { bool Parser::ParseHeaderLine(const std::string& line) { Header header; - if (!SplitKV(line, ':', &header.first, &header.second)) { + if (!utility::SplitKV(line, ':', &header.first, &header.second)) { LOG_ERRO("Invalid header: %s", line.c_str()); return false; } diff --git a/webcc/request.cc b/webcc/request.cc index 15f94f7..bb143bc 100644 --- a/webcc/request.cc +++ b/webcc/request.cc @@ -37,7 +37,7 @@ void Request::Prepare() { // Another choice to generate the boundary is like what Apache does. // See: https://stackoverflow.com/a/5686863 if (boundary_.empty()) { - boundary_ = RandomUuid(); + boundary_ = utility::RandomUuid(); } SetContentType("multipart/form-data; boundary=" + boundary_); diff --git a/webcc/request_builder.cc b/webcc/request_builder.cc index ad15f37..4442cd4 100644 --- a/webcc/request_builder.cc +++ b/webcc/request_builder.cc @@ -78,6 +78,12 @@ RequestBuilder& RequestBuilder::AuthToken(const std::string& token) { return Auth("Token", token); } +RequestBuilder& RequestBuilder::Date() { + headers_.push_back(headers::kDate); + headers_.push_back(utility::GetTimestamp()); + return *this; +} + void RequestBuilder::SetContent(RequestPtr request, std::string&& data) { #if WEBCC_ENABLE_GZIP if (gzip_ && data.size() > kGzipThreshold) { diff --git a/webcc/request_builder.h b/webcc/request_builder.h index d592726..0d75d51 100644 --- a/webcc/request_builder.h +++ b/webcc/request_builder.h @@ -96,6 +96,9 @@ public: RequestBuilder& AuthToken(const std::string& token); + // Add the Date header to the request. + RequestBuilder& Date(); + private: void SetContent(RequestPtr request, std::string&& data); diff --git a/webcc/request_parser.cc b/webcc/request_parser.cc index 9571a0d..00295f1 100644 --- a/webcc/request_parser.cc +++ b/webcc/request_parser.cc @@ -167,7 +167,7 @@ bool RequestParser::ParsePartHeaders(bool* need_more_data) { } Header header; - if (!SplitKV(line, ':', &header.first, &header.second)) { + if (!utility::SplitKV(line, ':', &header.first, &header.second)) { LOG_ERRO("Invalid part header line: %s", line.c_str()); return false; } diff --git a/webcc/response.cc b/webcc/response.cc index 8d127a1..d299c6b 100644 --- a/webcc/response.cc +++ b/webcc/response.cc @@ -1,12 +1,14 @@ #include "webcc/response.h" +#include "webcc/utility.h" + namespace webcc { void Response::Prepare() { PrepareStatusLine(); - SetHeader(headers::kServer, UserAgent()); - SetHeader(headers::kDate, GetTimestamp()); + SetHeader(headers::kServer, utility::UserAgent()); + SetHeader(headers::kDate, utility::GetTimestamp()); Message::Prepare(); } diff --git a/webcc/utility.cc b/webcc/utility.cc index 0d97c7c..0edfac3 100644 --- a/webcc/utility.cc +++ b/webcc/utility.cc @@ -1,12 +1,17 @@ #include "webcc/utility.h" +#include +#include // for put_time #include #include "boost/algorithm/string.hpp" #include "boost/uuid/random_generator.hpp" #include "boost/uuid/uuid_io.hpp" +#include "webcc/version.h" + namespace webcc { +namespace utility { std::string RandomUuid() { boost::uuids::uuid u = boost::uuids::random_generator()(); @@ -15,6 +20,18 @@ std::string RandomUuid() { return ss.str(); } +const std::string& UserAgent() { + static auto s_user_agent = std::string("Webcc/") + WEBCC_VERSION; + return s_user_agent; +} + +std::string GetTimestamp() { + std::time_t t = std::time(nullptr); + std::stringstream ss; + ss << std::put_time(std::gmtime(&t), "%a, %d %b %Y %H:%M:%S") << " GMT"; + return ss.str(); +} + bool SplitKV(const std::string& str, char delimiter, std::string* part1, std::string* part2) { std::size_t pos = str.find(delimiter); @@ -31,4 +48,5 @@ bool SplitKV(const std::string& str, char delimiter, return true; } +} // namespace utility } // namespace webcc diff --git a/webcc/utility.h b/webcc/utility.h index 37283e0..01a89f3 100644 --- a/webcc/utility.h +++ b/webcc/utility.h @@ -4,14 +4,25 @@ #include namespace webcc { +namespace utility { +// Get a randomly generated UUID. std::string RandomUuid(); +// Get default user agent for HTTP headers. +const std::string& UserAgent(); + +// Get the timestamp for HTTP Date header field. +// E.g., Wed, 21 Oct 2015 07:28:00 GMT +// See: https://tools.ietf.org/html/rfc7231#section-7.1.1.2 +std::string GetTimestamp(); + // Split a key-value string. // E.g., split "Connection: Keep-Alive". bool SplitKV(const std::string& str, char delimiter, std::string* key, std::string* value); +} // namespace utility } // namespace webcc #endif // WEBCC_UTILITY_H_