http_response_headers.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. // Copyright (c) 2012 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. #ifndef NET_HTTP_HTTP_RESPONSE_HEADERS_H_
  5. #define NET_HTTP_HTTP_RESPONSE_HEADERS_H_
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <string>
  9. #include <unordered_set>
  10. #include <vector>
  11. #include "base/callback.h"
  12. #include "base/memory/ref_counted.h"
  13. #include "base/strings/string_piece.h"
  14. #include "base/time/time.h"
  15. #include "net/base/net_export.h"
  16. #include "net/http/http_version.h"
  17. #include "net/log/net_log_capture_mode.h"
  18. #include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
  19. namespace base {
  20. class Pickle;
  21. class PickleIterator;
  22. class Time;
  23. class TimeDelta;
  24. class Value;
  25. }
  26. namespace net {
  27. class HttpByteRange;
  28. enum ValidationType {
  29. VALIDATION_NONE, // The resource is fresh.
  30. VALIDATION_ASYNCHRONOUS, // The resource requires async revalidation.
  31. VALIDATION_SYNCHRONOUS // The resource requires sync revalidation.
  32. };
  33. // HttpResponseHeaders: parses and holds HTTP response headers.
  34. class NET_EXPORT HttpResponseHeaders
  35. : public base::RefCountedThreadSafe<HttpResponseHeaders> {
  36. public:
  37. // Persist options.
  38. typedef int PersistOptions;
  39. static const PersistOptions PERSIST_RAW = -1; // Raw, unparsed headers.
  40. static const PersistOptions PERSIST_ALL = 0; // Parsed headers.
  41. static const PersistOptions PERSIST_SANS_COOKIES = 1 << 0;
  42. static const PersistOptions PERSIST_SANS_CHALLENGES = 1 << 1;
  43. static const PersistOptions PERSIST_SANS_HOP_BY_HOP = 1 << 2;
  44. static const PersistOptions PERSIST_SANS_NON_CACHEABLE = 1 << 3;
  45. static const PersistOptions PERSIST_SANS_RANGES = 1 << 4;
  46. static const PersistOptions PERSIST_SANS_SECURITY_STATE = 1 << 5;
  47. struct FreshnessLifetimes {
  48. // How long the resource will be fresh for.
  49. base::TimeDelta freshness;
  50. // How long after becoming not fresh that the resource will be stale but
  51. // usable (if async revalidation is enabled).
  52. base::TimeDelta staleness;
  53. };
  54. static const char kContentRange[];
  55. static const char kLastModified[];
  56. static const char kVary[];
  57. HttpResponseHeaders() = delete;
  58. // Parses the given raw_headers. raw_headers should be formatted thus:
  59. // includes the http status response line, each line is \0-terminated, and
  60. // it's terminated by an empty line (ie, 2 \0s in a row).
  61. // (Note that line continuations should have already been joined;
  62. // see HttpUtil::AssembleRawHeaders)
  63. //
  64. // HttpResponseHeaders does not perform any encoding changes on the input.
  65. //
  66. explicit HttpResponseHeaders(const std::string& raw_headers);
  67. // Initializes from the representation stored in the given pickle. The data
  68. // for this object is found relative to the given pickle_iter, which should
  69. // be passed to the pickle's various Read* methods.
  70. explicit HttpResponseHeaders(base::PickleIterator* pickle_iter);
  71. // Takes headers as an ASCII string and tries to parse them as HTTP response
  72. // headers. returns nullptr on failure. Unlike the HttpResponseHeaders
  73. // constructor that takes a std::string, HttpUtil::AssembleRawHeaders should
  74. // not be called on |headers| before calling this method.
  75. static scoped_refptr<HttpResponseHeaders> TryToCreate(
  76. base::StringPiece headers);
  77. HttpResponseHeaders(const HttpResponseHeaders&) = delete;
  78. HttpResponseHeaders& operator=(const HttpResponseHeaders&) = delete;
  79. // Appends a representation of this object to the given pickle.
  80. // The options argument can be a combination of PersistOptions.
  81. void Persist(base::Pickle* pickle, PersistOptions options);
  82. // Performs header merging as described in 13.5.3 of RFC 2616.
  83. void Update(const HttpResponseHeaders& new_headers);
  84. // Removes all instances of a particular header.
  85. void RemoveHeader(base::StringPiece name);
  86. // Removes all instances of particular headers.
  87. void RemoveHeaders(const std::unordered_set<std::string>& header_names);
  88. // Removes a particular header line. The header name is compared
  89. // case-insensitively.
  90. void RemoveHeaderLine(const std::string& name, const std::string& value);
  91. // Adds the specified response header. If a header with the same name is
  92. // already stored, the two headers are not merged together by this method; the
  93. // one provided is simply put at the end of the list.
  94. void AddHeader(base::StringPiece name, base::StringPiece value);
  95. // Sets the specified response header, removing any matching old one if
  96. // present. The new header is added to the end of the header list, rather than
  97. // replacing the old one. This is the same as calling RemoveHeader() followed
  98. // be SetHeader().
  99. void SetHeader(base::StringPiece name, base::StringPiece value);
  100. // Adds a cookie header. |cookie_string| should be the header value without
  101. // the header name (Set-Cookie).
  102. void AddCookie(const std::string& cookie_string);
  103. // Replaces the current status line with the provided one (|new_status| should
  104. // not have any EOL).
  105. void ReplaceStatusLine(const std::string& new_status);
  106. // Updates headers (Content-Length and Content-Range) in the |headers| to
  107. // include the right content length and range for |byte_range|. This also
  108. // updates HTTP status line if |replace_status_line| is true.
  109. // |byte_range| must have a valid, bounded range (i.e. coming from a valid
  110. // response or should be usable for a response).
  111. void UpdateWithNewRange(const HttpByteRange& byte_range,
  112. int64_t resource_size,
  113. bool replace_status_line);
  114. // Fetches the "normalized" value of a single header, where all values for the
  115. // header name are separated by commas. This will be the sequence of strings
  116. // that would be returned from repeated calls to EnumerateHeader, joined by
  117. // the string ", ".
  118. //
  119. // Returns false if this header wasn't found.
  120. //
  121. // Example:
  122. // Foo: a, b,c
  123. // Foo: d
  124. //
  125. // string value;
  126. // GetNormalizedHeader("Foo", &value); // Now, |value| is "a, b, c, d".
  127. //
  128. // NOTE: Do not make any assumptions about the encoding of this output
  129. // string. It may be non-ASCII, and the encoding used by the server is not
  130. // necessarily known to us. Do not assume that this output is UTF-8!
  131. bool GetNormalizedHeader(base::StringPiece name, std::string* value) const;
  132. // Returns the normalized status line.
  133. std::string GetStatusLine() const;
  134. // Get the HTTP version of the normalized status line.
  135. HttpVersion GetHttpVersion() const {
  136. return http_version_;
  137. }
  138. // Get the HTTP status text of the normalized status line.
  139. std::string GetStatusText() const;
  140. // Enumerate the "lines" of the response headers. This skips over the status
  141. // line. Use GetStatusLine if you are interested in that. Note that this
  142. // method returns the un-coalesced response header lines, so if a response
  143. // header appears on multiple lines, then it will appear multiple times in
  144. // this enumeration (in the order the header lines were received from the
  145. // server). Also, a given header might have an empty value. Initialize a
  146. // 'size_t' variable to 0 and pass it by address to EnumerateHeaderLines.
  147. // Call EnumerateHeaderLines repeatedly until it returns false. The
  148. // out-params 'name' and 'value' are set upon success.
  149. //
  150. // WARNING: In effect, repeatedly calling EnumerateHeaderLines should return
  151. // the same collection of (name, value) pairs that you'd obtain from passing
  152. // each header name into EnumerateHeader and repeatedly calling
  153. // EnumerateHeader. This means the output will *not* necessarily correspond to
  154. // the verbatim lines of the headers. For instance, given
  155. // Foo: a, b
  156. // Foo: c
  157. // EnumerateHeaderLines will output ("Foo", "a"), ("Foo", "b"), and
  158. // ("Foo", "c").
  159. bool EnumerateHeaderLines(size_t* iter,
  160. std::string* name,
  161. std::string* value) const;
  162. // Enumerate the values of the specified header. If you are only interested
  163. // in the first header, then you can pass nullptr for the 'iter' parameter.
  164. // Otherwise, to iterate across all values for the specified header,
  165. // initialize a 'size_t' variable to 0 and pass it by address to
  166. // EnumerateHeader. Note that a header might have an empty value. Call
  167. // EnumerateHeader repeatedly until it returns false.
  168. //
  169. // Unless a header is explicitly marked as non-coalescing (see
  170. // HttpUtil::IsNonCoalescingHeader), headers that contain
  171. // comma-separated lists are treated "as if" they had been sent as
  172. // distinct headers. That is, a header of "Foo: a, b, c" would
  173. // enumerate into distinct values of "a", "b", and "c". This is also
  174. // true for headers that occur multiple times in a response; unless
  175. // they are marked non-coalescing, "Foo: a, b" followed by "Foo: c"
  176. // will enumerate to "a", "b", "c". Commas inside quoted strings are ignored,
  177. // for example a header of 'Foo: "a, b", "c"' would enumerate as '"a, b"',
  178. // '"c"'.
  179. //
  180. // This can cause issues for headers that might have commas in fields that
  181. // aren't quoted strings, for example a header of "Foo: <a, b>, <c>" would
  182. // enumerate as '<a', 'b>', '<c>', rather than as '<a, b>', '<c>'.
  183. //
  184. // To handle cases such as this, use GetNormalizedHeader to return the full
  185. // concatenated header, and then parse manually.
  186. bool EnumerateHeader(size_t* iter,
  187. base::StringPiece name,
  188. std::string* value) const;
  189. // Returns true if the response contains the specified header-value pair.
  190. // Both name and value are compared case insensitively.
  191. bool HasHeaderValue(base::StringPiece name, base::StringPiece value) const;
  192. // Returns true if the response contains the specified header.
  193. // The name is compared case insensitively.
  194. bool HasHeader(base::StringPiece name) const;
  195. // Get the mime type and charset values in lower case form from the headers.
  196. // Empty strings are returned if the values are not present.
  197. void GetMimeTypeAndCharset(std::string* mime_type,
  198. std::string* charset) const;
  199. // Get the mime type in lower case from the headers. If there's no mime
  200. // type, returns false.
  201. bool GetMimeType(std::string* mime_type) const;
  202. // Get the charset in lower case from the headers. If there's no charset,
  203. // returns false.
  204. bool GetCharset(std::string* charset) const;
  205. // Returns true if this response corresponds to a redirect. The target
  206. // location of the redirect is optionally returned if location is non-null.
  207. bool IsRedirect(std::string* location) const;
  208. // Returns true if the HTTP response code passed in corresponds to a
  209. // redirect.
  210. static bool IsRedirectResponseCode(int response_code);
  211. // Returns VALIDATION_NONE if the response can be reused without
  212. // validation. VALIDATION_ASYNCHRONOUS means the response can be re-used, but
  213. // asynchronous revalidation must be performed. VALIDATION_SYNCHRONOUS means
  214. // that the result cannot be reused without revalidation.
  215. // The result is relative to the current_time parameter, which is
  216. // a parameter to support unit testing. The request_time parameter indicates
  217. // the time at which the request was made that resulted in this response,
  218. // which was received at response_time.
  219. ValidationType RequiresValidation(const base::Time& request_time,
  220. const base::Time& response_time,
  221. const base::Time& current_time) const;
  222. // Calculates the amount of time the server claims the response is fresh from
  223. // the time the response was generated. See section 13.2.4 of RFC 2616. See
  224. // RequiresValidation for a description of the response_time parameter. See
  225. // the definition of FreshnessLifetimes above for the meaning of the return
  226. // value. See RFC 5861 section 3 for the definition of
  227. // stale-while-revalidate.
  228. FreshnessLifetimes GetFreshnessLifetimes(
  229. const base::Time& response_time) const;
  230. // Returns the age of the response. See section 13.2.3 of RFC 2616.
  231. // See RequiresValidation for a description of this method's parameters.
  232. base::TimeDelta GetCurrentAge(const base::Time& request_time,
  233. const base::Time& response_time,
  234. const base::Time& current_time) const;
  235. // The following methods extract values from the response headers. If a
  236. // value is not present, or is invalid, then false is returned. Otherwise,
  237. // true is returned and the out param is assigned to the corresponding value.
  238. bool GetMaxAgeValue(base::TimeDelta* value) const;
  239. bool GetAgeValue(base::TimeDelta* value) const;
  240. bool GetDateValue(base::Time* value) const;
  241. bool GetLastModifiedValue(base::Time* value) const;
  242. bool GetExpiresValue(base::Time* value) const;
  243. bool GetStaleWhileRevalidateValue(base::TimeDelta* value) const;
  244. // Extracts the time value of a particular header. This method looks for the
  245. // first matching header value and parses its value as a HTTP-date.
  246. bool GetTimeValuedHeader(const std::string& name, base::Time* result) const;
  247. // Determines if this response indicates a keep-alive connection.
  248. bool IsKeepAlive() const;
  249. // Returns true if this response has a strong etag or last-modified header.
  250. // See section 13.3.3 of RFC 2616.
  251. bool HasStrongValidators() const;
  252. // Returns true if this response has any validator (either a Last-Modified or
  253. // an ETag) regardless of whether it is strong or weak. See section 13.3.3 of
  254. // RFC 2616.
  255. bool HasValidators() const;
  256. // Extracts the value of the Content-Length header or returns -1 if there is
  257. // no such header in the response.
  258. int64_t GetContentLength() const;
  259. // Extracts the value of the specified header or returns -1 if there is no
  260. // such header in the response.
  261. int64_t GetInt64HeaderValue(const std::string& header) const;
  262. // Extracts the values in a Content-Range header and returns true if all three
  263. // values are present and valid for a 206 response; otherwise returns false.
  264. // The following values will be outputted:
  265. // |*first_byte_position| = inclusive position of the first byte of the range
  266. // |*last_byte_position| = inclusive position of the last byte of the range
  267. // |*instance_length| = size in bytes of the object requested
  268. // If this method returns false, then all of the outputs will be -1.
  269. bool GetContentRangeFor206(int64_t* first_byte_position,
  270. int64_t* last_byte_position,
  271. int64_t* instance_length) const;
  272. // Returns true if the response is chunk-encoded.
  273. bool IsChunkEncoded() const;
  274. // Creates a Value for use with the NetLog containing the response headers.
  275. base::Value NetLogParams(NetLogCaptureMode capture_mode) const;
  276. // Returns the HTTP response code. This is 0 if the response code text seems
  277. // to exist but could not be parsed. Otherwise, it defaults to 200 if the
  278. // response code is not found in the raw headers.
  279. int response_code() const { return response_code_; }
  280. // Returns the raw header string.
  281. const std::string& raw_headers() const { return raw_headers_; }
  282. // Returns true if |name| is a cookie related header name. This is consistent
  283. // with |PERSIST_SANS_COOKIES|.
  284. static bool IsCookieResponseHeader(base::StringPiece name);
  285. // Write a representation of this object into tracing proto.
  286. void WriteIntoTrace(perfetto::TracedValue context) const;
  287. private:
  288. friend class base::RefCountedThreadSafe<HttpResponseHeaders>;
  289. using HeaderSet = std::unordered_set<std::string>;
  290. // The members of this structure point into raw_headers_.
  291. struct ParsedHeader;
  292. typedef std::vector<ParsedHeader> HeaderList;
  293. ~HttpResponseHeaders();
  294. // Initializes from the given raw headers.
  295. void Parse(const std::string& raw_input);
  296. // Helper function for ParseStatusLine.
  297. // Tries to extract the "HTTP/X.Y" from a status line formatted like:
  298. // HTTP/1.1 200 OK
  299. // with line_begin and end pointing at the begin and end of this line. If the
  300. // status line is malformed, returns HttpVersion(0,0).
  301. static HttpVersion ParseVersion(std::string::const_iterator line_begin,
  302. std::string::const_iterator line_end);
  303. // Tries to extract the status line from a header block, given the first
  304. // line of said header block. If the status line is malformed, we'll
  305. // construct a valid one. Example input:
  306. // HTTP/1.1 200 OK
  307. // with line_begin and end pointing at the begin and end of this line.
  308. // Output will be a normalized version of this.
  309. void ParseStatusLine(std::string::const_iterator line_begin,
  310. std::string::const_iterator line_end,
  311. bool has_headers);
  312. // Find the header in our list (case-insensitive) starting with |parsed_| at
  313. // index |from|. Returns string::npos if not found.
  314. size_t FindHeader(size_t from, base::StringPiece name) const;
  315. // Search the Cache-Control header for a directive matching |directive|. If
  316. // present, treat its value as a time offset in seconds, write it to |result|,
  317. // and return true.
  318. bool GetCacheControlDirective(base::StringPiece directive,
  319. base::TimeDelta* result) const;
  320. // Add a header->value pair to our list. If we already have header in our
  321. // list, append the value to it.
  322. void AddHeader(std::string::const_iterator name_begin,
  323. std::string::const_iterator name_end,
  324. std::string::const_iterator value_begin,
  325. std::string::const_iterator value_end);
  326. // Add to parsed_ given the fields of a ParsedHeader object.
  327. void AddToParsed(std::string::const_iterator name_begin,
  328. std::string::const_iterator name_end,
  329. std::string::const_iterator value_begin,
  330. std::string::const_iterator value_end);
  331. // Replaces the current headers with the merged version of |raw_headers| and
  332. // the current headers without the headers in |headers_to_remove|. Note that
  333. // |headers_to_remove| are removed from the current headers (before the
  334. // merge), not after the merge.
  335. void MergeWithHeaders(const std::string& raw_headers,
  336. const HeaderSet& headers_to_remove);
  337. // Adds the values from any 'cache-control: no-cache="foo,bar"' headers.
  338. void AddNonCacheableHeaders(HeaderSet* header_names) const;
  339. // Adds the set of header names that contain cookie values.
  340. static void AddSensitiveHeaders(HeaderSet* header_names);
  341. // Adds the set of rfc2616 hop-by-hop response headers.
  342. static void AddHopByHopHeaders(HeaderSet* header_names);
  343. // Adds the set of challenge response headers.
  344. static void AddChallengeHeaders(HeaderSet* header_names);
  345. // Adds the set of cookie response headers.
  346. static void AddCookieHeaders(HeaderSet* header_names);
  347. // Adds the set of content range response headers.
  348. static void AddHopContentRangeHeaders(HeaderSet* header_names);
  349. // Adds the set of transport security state headers.
  350. static void AddSecurityStateHeaders(HeaderSet* header_names);
  351. // We keep a list of ParsedHeader objects. These tell us where to locate the
  352. // header-value pairs within raw_headers_.
  353. HeaderList parsed_;
  354. // The raw_headers_ consists of the normalized status line (terminated with a
  355. // null byte) and then followed by the raw null-terminated headers from the
  356. // input that was passed to our constructor. We preserve the input [*] to
  357. // maintain as much ancillary fidelity as possible (since it is sometimes
  358. // hard to tell what may matter down-stream to a consumer of XMLHttpRequest).
  359. // [*] The status line may be modified.
  360. std::string raw_headers_;
  361. // This is the parsed HTTP response code.
  362. int response_code_;
  363. // The normalized http version (consistent with what GetStatusLine() returns).
  364. HttpVersion http_version_;
  365. };
  366. using ResponseHeadersCallback =
  367. base::RepeatingCallback<void(scoped_refptr<const HttpResponseHeaders>)>;
  368. } // namespace net
  369. #endif // NET_HTTP_HTTP_RESPONSE_HEADERS_H_