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