OLD | NEW |
| (Empty) |
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 | |
5 #ifndef NET_HTTP_HTTP_RESPONSE_HEADERS_H_ | |
6 #define NET_HTTP_HTTP_RESPONSE_HEADERS_H_ | |
7 | |
8 #include <string> | |
9 #include <vector> | |
10 | |
11 #include "base/basictypes.h" | |
12 #include "base/containers/hash_tables.h" | |
13 #include "base/memory/ref_counted.h" | |
14 #include "base/strings/string_piece.h" | |
15 #include "net/base/net_export.h" | |
16 #include "net/base/net_log.h" | |
17 #include "net/http/http_version.h" | |
18 | |
19 class Pickle; | |
20 class PickleIterator; | |
21 | |
22 namespace base { | |
23 class Time; | |
24 class TimeDelta; | |
25 } | |
26 | |
27 namespace net { | |
28 | |
29 class HttpByteRange; | |
30 | |
31 enum ValidationType { | |
32 VALIDATION_NONE, // The resource is fresh. | |
33 VALIDATION_ASYNCHRONOUS, // The resource requires async revalidation. | |
34 VALIDATION_SYNCHRONOUS // The resource requires sync revalidation. | |
35 }; | |
36 | |
37 // HttpResponseHeaders: parses and holds HTTP response headers. | |
38 class NET_EXPORT HttpResponseHeaders | |
39 : public base::RefCountedThreadSafe<HttpResponseHeaders> { | |
40 public: | |
41 // Persist options. | |
42 typedef int PersistOptions; | |
43 static const PersistOptions PERSIST_RAW = -1; // Raw, unparsed headers. | |
44 static const PersistOptions PERSIST_ALL = 0; // Parsed headers. | |
45 static const PersistOptions PERSIST_SANS_COOKIES = 1 << 0; | |
46 static const PersistOptions PERSIST_SANS_CHALLENGES = 1 << 1; | |
47 static const PersistOptions PERSIST_SANS_HOP_BY_HOP = 1 << 2; | |
48 static const PersistOptions PERSIST_SANS_NON_CACHEABLE = 1 << 3; | |
49 static const PersistOptions PERSIST_SANS_RANGES = 1 << 4; | |
50 static const PersistOptions PERSIST_SANS_SECURITY_STATE = 1 << 5; | |
51 | |
52 struct FreshnessLifetimes { | |
53 // How long the resource will be fresh for. | |
54 base::TimeDelta freshness; | |
55 // How long after becoming not fresh that the resource will be stale but | |
56 // usable (if async revalidation is enabled). | |
57 base::TimeDelta staleness; | |
58 }; | |
59 | |
60 static const char kContentRange[]; | |
61 | |
62 // Parses the given raw_headers. raw_headers should be formatted thus: | |
63 // includes the http status response line, each line is \0-terminated, and | |
64 // it's terminated by an empty line (ie, 2 \0s in a row). | |
65 // (Note that line continuations should have already been joined; | |
66 // see HttpUtil::AssembleRawHeaders) | |
67 // | |
68 // HttpResponseHeaders does not perform any encoding changes on the input. | |
69 // | |
70 explicit HttpResponseHeaders(const std::string& raw_headers); | |
71 | |
72 // Initializes from the representation stored in the given pickle. The data | |
73 // for this object is found relative to the given pickle_iter, which should | |
74 // be passed to the pickle's various Read* methods. | |
75 explicit HttpResponseHeaders(PickleIterator* pickle_iter); | |
76 | |
77 // Appends a representation of this object to the given pickle. | |
78 // The options argument can be a combination of PersistOptions. | |
79 void Persist(Pickle* pickle, PersistOptions options); | |
80 | |
81 // Performs header merging as described in 13.5.3 of RFC 2616. | |
82 void Update(const HttpResponseHeaders& new_headers); | |
83 | |
84 // Removes all instances of a particular header. | |
85 void RemoveHeader(const std::string& name); | |
86 | |
87 // Removes a particular header line. The header name is compared | |
88 // case-insensitively. | |
89 void RemoveHeaderLine(const std::string& name, const std::string& value); | |
90 | |
91 // Adds a particular header. |header| has to be a single header without any | |
92 // EOL termination, just [<header-name>: <header-values>] | |
93 // If a header with the same name is already stored, the two headers are not | |
94 // merged together by this method; the one provided is simply put at the | |
95 // end of the list. | |
96 void AddHeader(const std::string& header); | |
97 | |
98 // Replaces the current status line with the provided one (|new_status| should | |
99 // not have any EOL). | |
100 void ReplaceStatusLine(const std::string& new_status); | |
101 | |
102 // Updates headers (Content-Length and Content-Range) in the |headers| to | |
103 // include the right content length and range for |byte_range|. This also | |
104 // updates HTTP status line if |replace_status_line| is true. | |
105 // |byte_range| must have a valid, bounded range (i.e. coming from a valid | |
106 // response or should be usable for a response). | |
107 void UpdateWithNewRange(const HttpByteRange& byte_range, | |
108 int64 resource_size, | |
109 bool replace_status_line); | |
110 | |
111 // Creates a normalized header string. The output will be formatted exactly | |
112 // like so: | |
113 // HTTP/<version> <status_code> <status_text>\n | |
114 // [<header-name>: <header-values>\n]* | |
115 // meaning, each line is \n-terminated, and there is no extra whitespace | |
116 // beyond the single space separators shown (of course, values can contain | |
117 // whitespace within them). If a given header-name appears more than once | |
118 // in the set of headers, they are combined into a single line like so: | |
119 // <header-name>: <header-value1>, <header-value2>, ...<header-valueN>\n | |
120 // | |
121 // DANGER: For some headers (e.g., "Set-Cookie"), the normalized form can be | |
122 // a lossy format. This is due to the fact that some servers generate | |
123 // Set-Cookie headers that contain unquoted commas (usually as part of the | |
124 // value of an "expires" attribute). So, use this function with caution. Do | |
125 // not expect to be able to re-parse Set-Cookie headers from this output. | |
126 // | |
127 // NOTE: Do not make any assumptions about the encoding of this output | |
128 // string. It may be non-ASCII, and the encoding used by the server is not | |
129 // necessarily known to us. Do not assume that this output is UTF-8! | |
130 // | |
131 // TODO(darin): remove this method | |
132 // | |
133 void GetNormalizedHeaders(std::string* output) const; | |
134 | |
135 // Fetch the "normalized" value of a single header, where all values for the | |
136 // header name are separated by commas. See the GetNormalizedHeaders for | |
137 // format details. Returns false if this header wasn't found. | |
138 // | |
139 // NOTE: Do not make any assumptions about the encoding of this output | |
140 // string. It may be non-ASCII, and the encoding used by the server is not | |
141 // necessarily known to us. Do not assume that this output is UTF-8! | |
142 // | |
143 // TODO(darin): remove this method | |
144 // | |
145 bool GetNormalizedHeader(const std::string& name, std::string* value) const; | |
146 | |
147 // Returns the normalized status line. For HTTP/0.9 responses (i.e., | |
148 // responses that lack a status line), this is the manufactured string | |
149 // "HTTP/0.9 200 OK". | |
150 std::string GetStatusLine() const; | |
151 | |
152 // Get the HTTP version of the normalized status line. | |
153 HttpVersion GetHttpVersion() const { | |
154 return http_version_; | |
155 } | |
156 | |
157 // Get the HTTP version determined while parsing; or (0,0) if parsing failed | |
158 HttpVersion GetParsedHttpVersion() const { | |
159 return parsed_http_version_; | |
160 } | |
161 | |
162 // Get the HTTP status text of the normalized status line. | |
163 std::string GetStatusText() const; | |
164 | |
165 // Enumerate the "lines" of the response headers. This skips over the status | |
166 // line. Use GetStatusLine if you are interested in that. Note that this | |
167 // method returns the un-coalesced response header lines, so if a response | |
168 // header appears on multiple lines, then it will appear multiple times in | |
169 // this enumeration (in the order the header lines were received from the | |
170 // server). Also, a given header might have an empty value. Initialize a | |
171 // 'void*' variable to NULL and pass it by address to EnumerateHeaderLines. | |
172 // Call EnumerateHeaderLines repeatedly until it returns false. The | |
173 // out-params 'name' and 'value' are set upon success. | |
174 bool EnumerateHeaderLines(void** iter, | |
175 std::string* name, | |
176 std::string* value) const; | |
177 | |
178 // Enumerate the values of the specified header. If you are only interested | |
179 // in the first header, then you can pass NULL for the 'iter' parameter. | |
180 // Otherwise, to iterate across all values for the specified header, | |
181 // initialize a 'void*' variable to NULL and pass it by address to | |
182 // EnumerateHeader. Note that a header might have an empty value. Call | |
183 // EnumerateHeader repeatedly until it returns false. | |
184 bool EnumerateHeader(void** iter, | |
185 const base::StringPiece& name, | |
186 std::string* value) const; | |
187 | |
188 // Returns true if the response contains the specified header-value pair. | |
189 // Both name and value are compared case insensitively. | |
190 bool HasHeaderValue(const base::StringPiece& name, | |
191 const base::StringPiece& value) const; | |
192 | |
193 // Returns true if the response contains the specified header. | |
194 // The name is compared case insensitively. | |
195 bool HasHeader(const base::StringPiece& name) const; | |
196 | |
197 // Get the mime type and charset values in lower case form from the headers. | |
198 // Empty strings are returned if the values are not present. | |
199 void GetMimeTypeAndCharset(std::string* mime_type, | |
200 std::string* charset) const; | |
201 | |
202 // Get the mime type in lower case from the headers. If there's no mime | |
203 // type, returns false. | |
204 bool GetMimeType(std::string* mime_type) const; | |
205 | |
206 // Get the charset in lower case from the headers. If there's no charset, | |
207 // returns false. | |
208 bool GetCharset(std::string* charset) const; | |
209 | |
210 // Returns true if this response corresponds to a redirect. The target | |
211 // location of the redirect is optionally returned if location is non-null. | |
212 bool IsRedirect(std::string* location) const; | |
213 | |
214 // Returns true if the HTTP response code passed in corresponds to a | |
215 // redirect. | |
216 static bool IsRedirectResponseCode(int response_code); | |
217 | |
218 // Returns VALIDATION_NONE if the response can be reused without | |
219 // validation. VALIDATION_ASYNCHRONOUS means the response can be re-used, but | |
220 // asynchronous revalidation must be performed. VALIDATION_SYNCHRONOUS means | |
221 // that the result cannot be reused without revalidation. | |
222 // The result is relative to the current_time parameter, which is | |
223 // a parameter to support unit testing. The request_time parameter indicates | |
224 // the time at which the request was made that resulted in this response, | |
225 // which was received at response_time. | |
226 ValidationType RequiresValidation(const base::Time& request_time, | |
227 const base::Time& response_time, | |
228 const base::Time& current_time) const; | |
229 | |
230 // Calculates the amount of time the server claims the response is fresh from | |
231 // the time the response was generated. See section 13.2.4 of RFC 2616. See | |
232 // RequiresValidation for a description of the response_time parameter. See | |
233 // the definition of FreshnessLifetimes above for the meaning of the return | |
234 // value. See RFC 5861 section 3 for the definition of | |
235 // stale-while-revalidate. | |
236 FreshnessLifetimes GetFreshnessLifetimes( | |
237 const base::Time& response_time) const; | |
238 | |
239 // Returns the age of the response. See section 13.2.3 of RFC 2616. | |
240 // See RequiresValidation for a description of this method's parameters. | |
241 base::TimeDelta GetCurrentAge(const base::Time& request_time, | |
242 const base::Time& response_time, | |
243 const base::Time& current_time) const; | |
244 | |
245 // The following methods extract values from the response headers. If a | |
246 // value is not present, then false is returned. Otherwise, true is returned | |
247 // and the out param is assigned to the corresponding value. | |
248 bool GetMaxAgeValue(base::TimeDelta* value) const; | |
249 bool GetAgeValue(base::TimeDelta* value) const; | |
250 bool GetDateValue(base::Time* value) const; | |
251 bool GetLastModifiedValue(base::Time* value) const; | |
252 bool GetExpiresValue(base::Time* value) const; | |
253 bool GetStaleWhileRevalidateValue(base::TimeDelta* value) const; | |
254 | |
255 // Extracts the time value of a particular header. This method looks for the | |
256 // first matching header value and parses its value as a HTTP-date. | |
257 bool GetTimeValuedHeader(const std::string& name, base::Time* result) const; | |
258 | |
259 // Determines if this response indicates a keep-alive connection. | |
260 bool IsKeepAlive() const; | |
261 | |
262 // Returns true if this response has a strong etag or last-modified header. | |
263 // See section 13.3.3 of RFC 2616. | |
264 bool HasStrongValidators() const; | |
265 | |
266 // Extracts the value of the Content-Length header or returns -1 if there is | |
267 // no such header in the response. | |
268 int64 GetContentLength() const; | |
269 | |
270 // Extracts the value of the specified header or returns -1 if there is no | |
271 // such header in the response. | |
272 int64 GetInt64HeaderValue(const std::string& header) const; | |
273 | |
274 // Extracts the values in a Content-Range header and returns true if they are | |
275 // valid for a 206 response; otherwise returns false. | |
276 // The following values will be outputted: | |
277 // |*first_byte_position| = inclusive position of the first byte of the range | |
278 // |*last_byte_position| = inclusive position of the last byte of the range | |
279 // |*instance_length| = size in bytes of the object requested | |
280 // If any of the above values is unknown, its value will be -1. | |
281 bool GetContentRange(int64* first_byte_position, | |
282 int64* last_byte_position, | |
283 int64* instance_length) const; | |
284 | |
285 // Returns true if the response is chunk-encoded. | |
286 bool IsChunkEncoded() const; | |
287 | |
288 // Creates a Value for use with the NetLog containing the response headers. | |
289 base::Value* NetLogCallback(NetLog::LogLevel log_level) const; | |
290 | |
291 // Takes in a Value created by the above function, and attempts to create a | |
292 // copy of the original headers. Returns true on success. On failure, | |
293 // clears |http_response_headers|. | |
294 // TODO(mmenke): Long term, we want to remove this, and migrate external | |
295 // consumers to be NetworkDelegates. | |
296 static bool FromNetLogParam( | |
297 const base::Value* event_param, | |
298 scoped_refptr<HttpResponseHeaders>* http_response_headers); | |
299 | |
300 // Returns the HTTP response code. This is 0 if the response code text seems | |
301 // to exist but could not be parsed. Otherwise, it defaults to 200 if the | |
302 // response code is not found in the raw headers. | |
303 int response_code() const { return response_code_; } | |
304 | |
305 // Returns the raw header string. | |
306 const std::string& raw_headers() const { return raw_headers_; } | |
307 | |
308 private: | |
309 friend class base::RefCountedThreadSafe<HttpResponseHeaders>; | |
310 | |
311 typedef base::hash_set<std::string> HeaderSet; | |
312 | |
313 // The members of this structure point into raw_headers_. | |
314 struct ParsedHeader; | |
315 typedef std::vector<ParsedHeader> HeaderList; | |
316 | |
317 HttpResponseHeaders(); | |
318 ~HttpResponseHeaders(); | |
319 | |
320 // Initializes from the given raw headers. | |
321 void Parse(const std::string& raw_input); | |
322 | |
323 // Helper function for ParseStatusLine. | |
324 // Tries to extract the "HTTP/X.Y" from a status line formatted like: | |
325 // HTTP/1.1 200 OK | |
326 // with line_begin and end pointing at the begin and end of this line. If the | |
327 // status line is malformed, returns HttpVersion(0,0). | |
328 static HttpVersion ParseVersion(std::string::const_iterator line_begin, | |
329 std::string::const_iterator line_end); | |
330 | |
331 // Tries to extract the status line from a header block, given the first | |
332 // line of said header block. If the status line is malformed, we'll | |
333 // construct a valid one. Example input: | |
334 // HTTP/1.1 200 OK | |
335 // with line_begin and end pointing at the begin and end of this line. | |
336 // Output will be a normalized version of this. | |
337 void ParseStatusLine(std::string::const_iterator line_begin, | |
338 std::string::const_iterator line_end, | |
339 bool has_headers); | |
340 | |
341 // Find the header in our list (case-insensitive) starting with parsed_ at | |
342 // index |from|. Returns string::npos if not found. | |
343 size_t FindHeader(size_t from, const base::StringPiece& name) const; | |
344 | |
345 // Search the Cache-Control header for a directive matching |directive|. If | |
346 // present, treat its value as a time offset in seconds, write it to |result|, | |
347 // and return true. | |
348 bool GetCacheControlDirective(const base::StringPiece& directive, | |
349 base::TimeDelta* result) const; | |
350 | |
351 // Add a header->value pair to our list. If we already have header in our | |
352 // list, append the value to it. | |
353 void AddHeader(std::string::const_iterator name_begin, | |
354 std::string::const_iterator name_end, | |
355 std::string::const_iterator value_begin, | |
356 std::string::const_iterator value_end); | |
357 | |
358 // Add to parsed_ given the fields of a ParsedHeader object. | |
359 void AddToParsed(std::string::const_iterator name_begin, | |
360 std::string::const_iterator name_end, | |
361 std::string::const_iterator value_begin, | |
362 std::string::const_iterator value_end); | |
363 | |
364 // Replaces the current headers with the merged version of |raw_headers| and | |
365 // the current headers without the headers in |headers_to_remove|. Note that | |
366 // |headers_to_remove| are removed from the current headers (before the | |
367 // merge), not after the merge. | |
368 void MergeWithHeaders(const std::string& raw_headers, | |
369 const HeaderSet& headers_to_remove); | |
370 | |
371 // Adds the values from any 'cache-control: no-cache="foo,bar"' headers. | |
372 void AddNonCacheableHeaders(HeaderSet* header_names) const; | |
373 | |
374 // Adds the set of header names that contain cookie values. | |
375 static void AddSensitiveHeaders(HeaderSet* header_names); | |
376 | |
377 // Adds the set of rfc2616 hop-by-hop response headers. | |
378 static void AddHopByHopHeaders(HeaderSet* header_names); | |
379 | |
380 // Adds the set of challenge response headers. | |
381 static void AddChallengeHeaders(HeaderSet* header_names); | |
382 | |
383 // Adds the set of cookie response headers. | |
384 static void AddCookieHeaders(HeaderSet* header_names); | |
385 | |
386 // Adds the set of content range response headers. | |
387 static void AddHopContentRangeHeaders(HeaderSet* header_names); | |
388 | |
389 // Adds the set of transport security state headers. | |
390 static void AddSecurityStateHeaders(HeaderSet* header_names); | |
391 | |
392 // We keep a list of ParsedHeader objects. These tell us where to locate the | |
393 // header-value pairs within raw_headers_. | |
394 HeaderList parsed_; | |
395 | |
396 // The raw_headers_ consists of the normalized status line (terminated with a | |
397 // null byte) and then followed by the raw null-terminated headers from the | |
398 // input that was passed to our constructor. We preserve the input [*] to | |
399 // maintain as much ancillary fidelity as possible (since it is sometimes | |
400 // hard to tell what may matter down-stream to a consumer of XMLHttpRequest). | |
401 // [*] The status line may be modified. | |
402 std::string raw_headers_; | |
403 | |
404 // This is the parsed HTTP response code. | |
405 int response_code_; | |
406 | |
407 // The normalized http version (consistent with what GetStatusLine() returns). | |
408 HttpVersion http_version_; | |
409 | |
410 // The parsed http version number (not normalized). | |
411 HttpVersion parsed_http_version_; | |
412 | |
413 DISALLOW_COPY_AND_ASSIGN(HttpResponseHeaders); | |
414 }; | |
415 | |
416 } // namespace net | |
417 | |
418 #endif // NET_HTTP_HTTP_RESPONSE_HEADERS_H_ | |
OLD | NEW |