• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_BALSA_HEADER_API_H_
6 #define QUICHE_BALSA_HEADER_API_H_
7 
8 #include <cstddef>
9 #include <functional>
10 #include <string>
11 #include <vector>
12 
13 #include "absl/strings/string_view.h"
14 #include "quiche/common/platform/api/quiche_export.h"
15 #include "quiche/common/platform/api/quiche_lower_case_string.h"
16 
17 namespace quiche {
18 
19 // An API so we can reuse functions for BalsaHeaders and Envoy's HeaderMap.
20 // Contains only const member functions, so it can wrap const HeaderMaps;
21 // non-const functions are in HeaderApi.
22 //
23 // Depending on the implementation, the headers may act like HTTP/1 headers
24 // (BalsaHeaders) or HTTP/2 headers (HeaderMap). For HTTP-version-specific
25 // headers or pseudoheaders like "host" or ":authority", use this API's
26 // implementation-independent member functions, like Authority(). Looking those
27 // headers up by name is deprecated and may QUICHE_DCHECK-fail.
28 // For the differences between HTTP/1 and HTTP/2 headers, see RFC 7540:
29 // https://tools.ietf.org/html/rfc7540#section-8.1.2
30 //
31 // Operations on header keys are case-insensitive while operations on header
32 // values are case-sensitive.
33 //
34 // Some methods have overloads which accept Envoy-style LowerCaseStrings. Often
35 // these keys are accessible from Envoy::Http::Headers::get().SomeHeader,
36 // already lowercaseified. It's faster to avoid converting them to and from
37 // lowercase. Additionally, some implementations of ConstHeaderApi might take
38 // advantage of a constant-time lookup for inlined headers.
39 class QUICHE_EXPORT ConstHeaderApi {
40  public:
~ConstHeaderApi()41   virtual ~ConstHeaderApi() {}
42 
43   // Determine whether the headers are empty.
44   virtual bool IsEmpty() const = 0;
45 
46   // Returns the header entry for the first instance with key |key|
47   // If header isn't present, returns absl::string_view().
48   virtual absl::string_view GetHeader(absl::string_view key) const = 0;
49 
GetHeader(const QuicheLowerCaseString & key)50   virtual absl::string_view GetHeader(const QuicheLowerCaseString& key) const {
51     // Default impl for BalsaHeaders, etc.
52     return GetHeader(key.get());
53   }
54 
55   // Collects all of the header entries with key |key| and returns them in |out|
56   // Headers are returned in the order they are inserted.
57   virtual void GetAllOfHeader(absl::string_view key,
58                               std::vector<absl::string_view>* out) const = 0;
GetAllOfHeader(absl::string_view key)59   virtual std::vector<absl::string_view> GetAllOfHeader(
60       absl::string_view key) const {
61     std::vector<absl::string_view> out;
62     GetAllOfHeader(key, &out);
63     return out;
64   }
GetAllOfHeader(const QuicheLowerCaseString & key,std::vector<absl::string_view> * out)65   virtual void GetAllOfHeader(const QuicheLowerCaseString& key,
66                               std::vector<absl::string_view>* out) const {
67     return GetAllOfHeader(key.get(), out);
68   }
69 
70   // Determine if a given header is present.
71   virtual bool HasHeader(absl::string_view key) const = 0;
72 
73   // Determines if a given header is present with non-empty value.
74   virtual bool HasNonEmptyHeader(absl::string_view key) const = 0;
75 
76   // Goes through all headers with key |key| and checks to see if one of the
77   // values is |value|.  Returns true if there are headers with the desired key
78   // and value, false otherwise.
79   virtual bool HeaderHasValue(absl::string_view key,
80                               absl::string_view value) const = 0;
81 
82   // Same as above, but value is treated as case insensitive.
83   virtual bool HeaderHasValueIgnoreCase(absl::string_view key,
84                                         absl::string_view value) const = 0;
85 
86   // Joins all values for header entries with `key` into a comma-separated
87   // string.  Headers are returned in the order they are inserted.
88   virtual std::string GetAllOfHeaderAsString(absl::string_view key) const = 0;
GetAllOfHeaderAsString(const QuicheLowerCaseString & key)89   virtual std::string GetAllOfHeaderAsString(
90       const QuicheLowerCaseString& key) const {
91     return GetAllOfHeaderAsString(key.get());
92   }
93 
94   // Returns true if we have at least one header with given prefix
95   // [case insensitive]. Currently for test use only.
96   virtual bool HasHeadersWithPrefix(absl::string_view key) const = 0;
97 
98   // Returns the key value pairs for all headers where the header key begins
99   // with the specified prefix.
100   // Headers are returned in the order they are inserted.
101   virtual void GetAllOfHeaderWithPrefix(
102       absl::string_view prefix,
103       std::vector<std::pair<absl::string_view, absl::string_view>>* out)
104       const = 0;
105 
106   // Returns the key value pairs for all headers in this object. If 'limit' is
107   // >= 0, return at most 'limit' headers.
108   virtual void GetAllHeadersWithLimit(
109       std::vector<std::pair<absl::string_view, absl::string_view>>* out,
110       int limit) const = 0;
111 
112   // Returns a textual representation of the header object. The format of the
113   // string may depend on the underlying implementation.
114   virtual std::string DebugString() const = 0;
115 
116   // Applies the argument function to each header line.  If the argument
117   // function returns false, iteration stops and ForEachHeader returns false;
118   // otherwise, ForEachHeader returns true.
119   virtual bool ForEachHeader(std::function<bool(const absl::string_view key,
120                                                 const absl::string_view value)>
121                                  fn) const = 0;
122 
123   // Returns the upper bound byte size of the headers. This can be used to size
124   // a Buffer when serializing headers.
125   virtual size_t GetSizeForWriteBuffer() const = 0;
126 
127   // Returns the response code for response headers. If no status code exists,
128   // the return value is implementation-specific.
129   virtual absl::string_view response_code() const = 0;
130 
131   // Returns the response code for response headers or 0 if no status code
132   // exists.
133   virtual size_t parsed_response_code() const = 0;
134 
135   // Returns the response reason phrase; the stored one for HTTP/1 headers, or a
136   // phrase determined from the response code for HTTP/2 headers..
137   virtual absl::string_view response_reason_phrase() const = 0;
138 
139   // Return the HTTP first line of this request, generally of the format:
140   // GET /path/ HTTP/1.1
141   // TODO(b/110421449): deprecate this method.
142   virtual std::string first_line_of_request() const = 0;
143 
144   // Return the method for this request, such as GET or POST.
145   virtual absl::string_view request_method() const = 0;
146 
147   // Return the request URI from the first line of this request, such as
148   // "/path/".
149   virtual absl::string_view request_uri() const = 0;
150 
151   // Return the version portion of the first line of this request, such as
152   // "HTTP/1.1".
153   // TODO(b/110421449): deprecate this method.
154   virtual absl::string_view request_version() const = 0;
155 
156   virtual absl::string_view response_version() const = 0;
157 
158   // Returns the authority portion of a request, or an empty string if missing.
159   // This is the value of the host header for HTTP/1 headers and the value of
160   // the :authority pseudo-header for HTTP/2 headers.
161   virtual absl::string_view Authority() const = 0;
162 
163   // Call the provided function on the cookie, avoiding
164   // copies if possible. The cookie is the value of the Cookie header; for
165   // HTTP/2 headers, if there are multiple Cookie headers, they will be joined
166   // by "; ", per go/rfc/7540#section-8.1.2.5. If there is no Cookie header,
167   // cookie.data() will be nullptr. The lifetime of the cookie isn't guaranteed
168   // to extend beyond this call.
169   virtual void ApplyToCookie(
170       std::function<void(absl::string_view cookie)> f) const = 0;
171 
172   virtual size_t content_length() const = 0;
173   virtual bool content_length_valid() const = 0;
174 
175   // TODO(b/118501626): Add functions for working with other headers and
176   // pseudo-headers whose presence or value depends on HTTP version, including:
177   // :method, :scheme, :path, connection, and cookie.
178 };
179 
180 // An API so we can reuse functions for BalsaHeaders and Envoy's HeaderMap.
181 // Inherits const functions from ConstHeaderApi and adds non-const functions,
182 // for use with non-const HeaderMaps.
183 //
184 // For HTTP-version-specific headers and pseudo-headers, the same caveats apply
185 // as with ConstHeaderApi.
186 //
187 // Operations on header keys are case-insensitive while operations on header
188 // values are case-sensitive.
189 class QUICHE_EXPORT HeaderApi : public virtual ConstHeaderApi {
190  public:
191   // Replaces header entries with key |key| if they exist, or appends
192   // a new header if none exist.
193   virtual void ReplaceOrAppendHeader(absl::string_view key,
194                                      absl::string_view value) = 0;
195 
196   // Removes all headers in given set of |keys| at once
197   virtual void RemoveAllOfHeaderInList(
198       const std::vector<absl::string_view>& keys) = 0;
199 
200   // Removes all headers with key |key|.
201   virtual void RemoveAllOfHeader(absl::string_view key) = 0;
202 
203   // Append a new header entry to the header object with key |key| and value
204   // |value|.
205   virtual void AppendHeader(absl::string_view key, absl::string_view value) = 0;
206 
207   // Removes all headers starting with 'key' [case insensitive]
208   virtual void RemoveAllHeadersWithPrefix(absl::string_view key) = 0;
209 
210   // Appends ',value' to an existing header named 'key'.  If no header with the
211   // correct key exists, it will call AppendHeader(key, value).  Calling this
212   // function on a key which exists several times in the headers will produce
213   // unpredictable results.
214   virtual void AppendToHeader(absl::string_view key,
215                               absl::string_view value) = 0;
216 
217   // Appends ', value' to an existing header named 'key'.  If no header with the
218   // correct key exists, it will call AppendHeader(key, value).  Calling this
219   // function on a key which exists several times in the headers will produce
220   // unpredictable results.
221   virtual void AppendToHeaderWithCommaAndSpace(absl::string_view key,
222                                                absl::string_view value) = 0;
223 
224   // Set the header or pseudo-header corresponding to the authority portion of a
225   // request: host for HTTP/1 headers, or :authority for HTTP/2 headers.
226   virtual void ReplaceOrAppendAuthority(absl::string_view value) = 0;
227   virtual void RemoveAuthority() = 0;
228 
229   // These set portions of the first line for HTTP/1 headers, or the
230   // corresponding pseudo-headers for HTTP/2 headers.
231   virtual void SetRequestMethod(absl::string_view method) = 0;
232   virtual void SetResponseCode(absl::string_view code) = 0;
233   // As SetResponseCode, but slightly faster for BalsaHeaders if the caller
234   // represents the response code as an integer and not a string.
235   virtual void SetParsedResponseCodeAndUpdateFirstline(
236       size_t parsed_response_code) = 0;
237 
238   // Sets the request URI.
239   //
240   // For HTTP/1 headers, sets the request URI portion of the first line (the
241   // second token). Doesn't parse the URI; leaves the Host header unchanged.
242   //
243   // For HTTP/2 headers, sets the :path pseudo-header, and also :scheme and
244   // :authority if they're present in the URI; otherwise, leaves :scheme and
245   // :authority unchanged.
246   //
247   // The caller is responsible for verifying that the URI is in a valid format.
248   virtual void SetRequestUri(absl::string_view uri) = 0;
249 
250   // These are only meaningful for HTTP/1 headers; for HTTP/2 headers, they do
251   // nothing.
252   virtual void SetRequestVersion(absl::string_view version) = 0;
253   virtual void SetResponseVersion(absl::string_view version) = 0;
254   virtual void SetResponseReasonPhrase(absl::string_view reason_phrase) = 0;
255 
256   // SetContentLength, SetTransferEncodingToChunkedAndClearContentLength, and
257   // SetNoTransferEncoding modifies the header object to use
258   // content-length and transfer-encoding headers in a consistent
259   // manner. They set all internal flags and status, if applicable, so client
260   // can get a consistent view from various accessors.
261   virtual void SetContentLength(size_t length) = 0;
262   // Sets transfer-encoding to chunked and updates internal state.
263   virtual void SetTransferEncodingToChunkedAndClearContentLength() = 0;
264   // Removes transfer-encoding headers and updates internal state.
265   virtual void SetNoTransferEncoding() = 0;
266 
267   // If true, QUICHE_BUG if a header that starts with an invalid prefix is
268   // explicitly set. Not implemented for Envoy headers; can only be set false.
269   virtual void set_enforce_header_policy(bool enforce) = 0;
270 };
271 
272 }  // namespace quiche
273 
274 #endif  // QUICHE_BALSA_HEADER_API_H_
275