forked from googleapis/google-cloud-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttp_header.h
More file actions
189 lines (163 loc) · 6.76 KB
/
http_header.h
File metadata and controls
189 lines (163 loc) · 6.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_HTTP_HEADER_H
#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
#include "absl/container/flat_hash_map.h"
#else
#include <unordered_map>
#endif // UINTPTR_MAX == UINT64_MAX
#include <string>
#include <vector>
namespace google {
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)
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(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;
HttpHeader(HttpHeader const&) = default;
HttpHeader& operator=(HttpHeader const&) = default;
// Equality is determined by a case-insensitive comparison of the key and
// a case-sensitive comparison of the values. Ordering of the values is
// significant and two HttpHeaders of the same key must have the same ordering
// of the same values in order to be considered equal.
//
// HTTP/1.1 https://www.rfc-editor.org/rfc/rfc7230#section-3.2.2
friend bool operator==(HttpHeader const& lhs, HttpHeader const& rhs);
friend bool operator!=(HttpHeader const& lhs, HttpHeader const& rhs) {
return !(lhs == rhs);
}
// Lower case lexicographic comparison of keys without inspecting the values.
// This class provides operator< only for sorting purposes.
friend bool operator<(HttpHeader const& lhs, HttpHeader const& rhs);
// If the key is empty, the entire HttpHeader is considered 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(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
// case they were constructed with. We rely on libcurl to encode them per the
// HTTP version used.
//
// HTTP/1.1 https://www.rfc-editor.org/rfc/rfc7230#section-3.2
// HTTP/2 https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2
explicit operator std::string() const;
// Formats header as a string, but truncates the value if it is too long, or
// if it could contain a secret.
std::string DebugString() const;
// Merges the values from other into this if the keys are the same.
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:
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
// 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
} // namespace cloud
} // namespace google
#if UINTPTR_MAX != UINT64_MAX
// 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