-
Notifications
You must be signed in to change notification settings - Fork 441
impl(rest): improve http header representation #16058
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3e41068
ae0f7b4
d39ef3b
65f07ab
f5fb378
a78ca6b
88988ca
9a274e8
86d7bf2
081c6d8
c835db2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,13 @@ | |
| #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_HTTP_HEADER_H | ||
|
|
||
| #include "google/cloud/version.h" | ||
| #include "absl/strings/ascii.h" | ||
| #include <cstdint> | ||
| #if UINTPTR_MAX == UINT64_MAX | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better include
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops; fixed. |
||
| #include "absl/container/flat_hash_map.h" | ||
| #else | ||
| #include <unordered_map> | ||
| #endif // UINTPTR_MAX == UINT64_MAX | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
|
|
@@ -24,17 +31,67 @@ namespace cloud { | |
| namespace rest_internal { | ||
| GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN | ||
|
|
||
| // This class represents a case-insensitive HTTP header name by storing all | ||
| // strings in lower-case. | ||
| class HttpHeaderName { | ||
| public: | ||
| HttpHeaderName() = default; | ||
| HttpHeaderName(std::string name) // NOLINT(google-explicit-constructor) | ||
| : name_(std::move(name)) { | ||
| absl::AsciiStrToLower(&name_); | ||
| } | ||
| HttpHeaderName(std::string_view name) // NOLINT(google-explicit-constructor) | ||
| : HttpHeaderName(std::string{name}) {} | ||
| HttpHeaderName(char const* name) // NOLINT(google-explicit-constructor) | ||
| : HttpHeaderName(std::string{name}) {} | ||
|
|
||
| operator std::string() const { // NOLINT(google-explicit-constructor) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. There is not a different |
||
| return name_; | ||
| } | ||
| operator std::string_view() const { // NOLINT(google-explicit-constructor) | ||
| return name_; | ||
| } | ||
| operator char const*() const { // NOLINT(google-explicit-constructor) | ||
| return name_.c_str(); | ||
| } | ||
|
|
||
| bool empty() const { return name_.empty(); } | ||
| std::string const& name() const { return name_; } | ||
|
|
||
| friend bool operator==(HttpHeaderName const& lhs, HttpHeaderName const& rhs) { | ||
| return lhs.name_ == rhs.name_; | ||
| } | ||
| friend bool operator<(HttpHeaderName const& lhs, HttpHeaderName const& rhs) { | ||
| return lhs.name_ < rhs.name_; | ||
| } | ||
| friend bool operator!=(HttpHeaderName const& lhs, HttpHeaderName const& rhs) { | ||
| return !(lhs == rhs); | ||
| } | ||
| friend bool operator>(HttpHeaderName const& lhs, HttpHeaderName const& rhs) { | ||
| return !(lhs < rhs) && (lhs != rhs); | ||
| } | ||
| friend bool operator>=(HttpHeaderName const& lhs, HttpHeaderName const& rhs) { | ||
| return !(lhs < rhs); | ||
| } | ||
| friend bool operator<=(HttpHeaderName const& lhs, HttpHeaderName const& rhs) { | ||
| return !(lhs > rhs); | ||
| } | ||
|
|
||
| private: | ||
| std::string name_; | ||
| }; | ||
|
|
||
| /** | ||
| * This class represents an HTTP header field. | ||
| */ | ||
| class HttpHeader { | ||
| public: | ||
| HttpHeader() = default; | ||
| explicit HttpHeader(std::string key); | ||
| HttpHeader(std::string key, std::string value); | ||
| HttpHeader(std::string key, std::initializer_list<char const*> values); | ||
|
|
||
| HttpHeader(std::string key, std::vector<std::string> values); | ||
| explicit HttpHeader(HttpHeaderName key); | ||
| explicit HttpHeader(std::pair<std::string, std::string> header); | ||
| HttpHeader(HttpHeaderName key, std::string value); | ||
| HttpHeader(HttpHeaderName key, std::initializer_list<char const*> values); | ||
| HttpHeader(HttpHeaderName key, std::vector<std::string> values); | ||
|
|
||
| HttpHeader(HttpHeader&&) = default; | ||
| HttpHeader& operator=(HttpHeader&&) = default; | ||
|
|
@@ -57,14 +114,20 @@ class HttpHeader { | |
| friend bool operator<(HttpHeader const& lhs, HttpHeader const& rhs); | ||
|
|
||
| // If the key is empty, the entire HttpHeader is considered empty. | ||
| bool empty() const { return key_.empty(); } | ||
| bool empty() const { return name_.empty(); } | ||
|
|
||
| // Number of values. | ||
| std::size_t size() const { return values_.size(); } | ||
|
|
||
| // Checks to see if the values are empty. Does not inspect the key field. | ||
| bool EmptyValues() const { return values_.empty(); } | ||
|
|
||
| // Performs a case-insensitive comparison of the key. | ||
| bool IsSameKey(HttpHeader const& other) const; | ||
| bool IsSameKey(std::string const& key) const; | ||
| bool IsSameKey(HttpHeaderName const& name) const; | ||
|
|
||
| std::string name() const { return name_; } | ||
| std::vector<std::string> const& values() const { return values_; } | ||
|
|
||
| // While the RFCs indicate that header keys are case-insensitive, no attempt | ||
| // to convert them to all lowercase is made. Header keys are printed in the | ||
|
|
@@ -83,14 +146,44 @@ class HttpHeader { | |
| HttpHeader& MergeHeader(HttpHeader const& other); | ||
| HttpHeader& MergeHeader(HttpHeader&& other); | ||
|
|
||
| using value_type = std::string; | ||
| using const_iterator = std::vector<value_type>::const_iterator; | ||
| const_iterator begin() const { return values_.begin(); } | ||
| const_iterator end() const { return values_.end(); } | ||
| const_iterator cbegin() const { return begin(); } | ||
| const_iterator cend() const { return end(); } | ||
|
|
||
| private: | ||
| std::string key_; | ||
| HttpHeaderName name_; | ||
| std::vector<std::string> values_; | ||
| }; | ||
|
|
||
| // Abseil does not guarantee compatibility with 32-bit platforms that they do | ||
| // not test with. Support for such platforms is a community effort. Using | ||
| // std::unordered_map on 32-bit platforms reduces the likelihood of issues | ||
| // arising due to this arrangement. | ||
| #if UINTPTR_MAX == UINT64_MAX | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| // 64-bit architecture | ||
| using HttpHeaders = absl::flat_hash_map<HttpHeaderName, HttpHeader>; | ||
| #else | ||
| // 32-bit architecture | ||
| using HttpHeaders = std::unordered_map<HttpHeaderName, HttpHeader>; | ||
| #endif // UINTPTR_MAX == UINT64_MAX | ||
|
|
||
| GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END | ||
| } // namespace rest_internal | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing nesting levels within pre-processor conditionals is generally considered bad practice.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
| } // namespace cloud | ||
| } // namespace google | ||
|
|
||
| #if UINTPTR_MAX != UINT64_MAX | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Forgive my memory failings, but how does
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The HttpHeaderName type has an implicit std::string conversion operator. |
||
| // This specialization has to be in the global namespace. | ||
| template <> | ||
| struct std::hash<google::cloud::rest_internal::HttpHeaderName> { | ||
| std::size_t operator()( | ||
| google::cloud::rest_internal::HttpHeaderName const& k) const noexcept { | ||
| return std::hash<std::string>()(k.name()); | ||
| } | ||
| }; | ||
| #endif // UINTPTR_MAX != UINT64_MAX | ||
|
|
||
| #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_HTTP_HEADER_H | ||
Uh oh!
There was an error while loading. Please reload this page.