1// Copyright (c) 2011 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_UTIL_H_
6#define NET_HTTP_HTTP_UTIL_H_
7#pragma once
8
9#include <string>
10#include <vector>
11
12#include "base/memory/ref_counted.h"
13#include "base/string_tokenizer.h"
14#include "googleurl/src/gurl.h"
15#include "net/http/http_byte_range.h"
16
17// This is a macro to support extending this string literal at compile time.
18// Please excuse me polluting your global namespace!
19#define HTTP_LWS " \t"
20
21namespace net {
22
23class UploadDataStream;
24
25class HttpUtil {
26 public:
27  // Returns the absolute path of the URL, to be used for the http request.
28  // The absolute path starts with a '/' and may contain a query.
29  static std::string PathForRequest(const GURL& url);
30
31  // Returns the absolute URL, to be used for the http request. This url is
32  // made up of the protocol, host, [port], path, [query]. Everything else
33  // is stripped (username, password, reference).
34  static std::string SpecForRequest(const GURL& url);
35
36  // Locates the next occurance of delimiter in line, skipping over quoted
37  // strings (e.g., commas will not be treated as delimiters if they appear
38  // within a quoted string).  Returns the offset of the found delimiter or
39  // line.size() if no delimiter was found.
40  static size_t FindDelimiter(const std::string& line,
41                              size_t search_start,
42                              char delimiter);
43
44  // Parses the value of a Content-Type header.  The resulting mime_type and
45  // charset values are normalized to lowercase.  The mime_type and charset
46  // output values are only modified if the content_type_str contains a mime
47  // type and charset value, respectively.
48  static void ParseContentType(const std::string& content_type_str,
49                               std::string* mime_type,
50                               std::string* charset,
51                               bool *had_charset);
52
53  // Scans the headers and look for the first "Range" header in |headers|,
54  // if "Range" exists and the first one of it is well formatted then returns
55  // true, |ranges| will contain a list of valid ranges. If return
56  // value is false then values in |ranges| should not be used. The format of
57  // "Range" header is defined in RFC 2616 Section 14.35.1.
58  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1
59  static bool ParseRanges(const std::string& headers,
60                          std::vector<HttpByteRange>* ranges);
61
62  // Same thing as ParseRanges except the Range header is known and its value
63  // is directly passed in, rather than requiring searching through a string.
64  static bool ParseRangeHeader(const std::string& range_specifier,
65                               std::vector<HttpByteRange>* ranges);
66
67  // Scans the '\r\n'-delimited headers for the given header name.  Returns
68  // true if a match is found.  Input is assumed to be well-formed.
69  // TODO(darin): kill this
70  static bool HasHeader(const std::string& headers, const char* name);
71
72  // Strips all header lines from |headers| whose name matches
73  // |headers_to_remove|. |headers_to_remove| is a list of null-terminated
74  // lower-case header names, with array length |headers_to_remove_len|.
75  // Returns the stripped header lines list, separated by "\r\n".
76  static std::string StripHeaders(const std::string& headers,
77                                  const char* const headers_to_remove[],
78                                  size_t headers_to_remove_len);
79
80  // Multiple occurances of some headers cannot be coalesced into a comma-
81  // separated list since their values are (or contain) unquoted HTTP-date
82  // values, which may contain a comma (see RFC 2616 section 3.3.1).
83  static bool IsNonCoalescingHeader(std::string::const_iterator name_begin,
84                                    std::string::const_iterator name_end);
85  static bool IsNonCoalescingHeader(const std::string& name) {
86    return IsNonCoalescingHeader(name.begin(), name.end());
87  }
88
89  // Return true if the character is HTTP "linear white space" (SP | HT).
90  // This definition corresponds with the HTTP_LWS macro, and does not match
91  // newlines.
92  static bool IsLWS(char c);
93
94  // Trim HTTP_LWS chars from the beginning and end of the string.
95  static void TrimLWS(std::string::const_iterator* begin,
96                      std::string::const_iterator* end);
97
98  // Whether the character is the start of a quotation mark.
99  static bool IsQuote(char c);
100
101  // RFC 2616 Sec 2.2:
102  // quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
103  // Unquote() strips the surrounding quotemarks off a string, and unescapes
104  // any quoted-pair to obtain the value contained by the quoted-string.
105  // If the input is not quoted, then it works like the identity function.
106  static std::string Unquote(std::string::const_iterator begin,
107                             std::string::const_iterator end);
108
109  // Same as above.
110  static std::string Unquote(const std::string& str);
111
112  // The reverse of Unquote() -- escapes and surrounds with "
113  static std::string Quote(const std::string& str);
114
115  // Returns the start of the status line, or -1 if no status line was found.
116  // This allows for 4 bytes of junk to precede the status line (which is what
117  // mozilla does too).
118  static int LocateStartOfStatusLine(const char* buf, int buf_len);
119
120  // Returns index beyond the end-of-headers marker or -1 if not found.  RFC
121  // 2616 defines the end-of-headers marker as a double CRLF; however, some
122  // servers only send back LFs (e.g., Unix-based CGI scripts written using the
123  // ASIS Apache module).  This function therefore accepts the pattern LF[CR]LF
124  // as end-of-headers (just like Mozilla).
125  // The parameter |i| is the offset within |buf| to begin searching from.
126  static int LocateEndOfHeaders(const char* buf, int buf_len, int i = 0);
127
128  // Assemble "raw headers" in the format required by HttpResponseHeaders.
129  // This involves normalizing line terminators, converting [CR]LF to \0 and
130  // handling HTTP line continuations (i.e., lines starting with LWS are
131  // continuations of the previous line).  |buf_len| indicates the position of
132  // the end-of-headers marker as defined by LocateEndOfHeaders.
133  static std::string AssembleRawHeaders(const char* buf, int buf_len);
134
135  // Given a comma separated ordered list of language codes, return
136  // the list with a qvalue appended to each language.
137  // The way qvalues are assigned is rather simple. The qvalue
138  // starts with 1.0 and is decremented by 0.2 for each successive entry
139  // in the list until it reaches 0.2. All the entries after that are
140  // assigned the same qvalue of 0.2. Also, note that the 1st language
141  // will not have a qvalue added because the absence of a qvalue implicitly
142  // means q=1.0.
143  //
144  // When making a http request, this should be used to determine what
145  // to put in Accept-Language header. If a comma separated list of language
146  // codes *without* qvalue is sent, web servers regard all
147  // of them as having q=1.0 and pick one of them even though it may not
148  // be at the beginning of the list (see http://crbug.com/5899).
149  static std::string GenerateAcceptLanguageHeader(
150      const std::string& raw_language_list);
151
152  // Given a charset, return the list with a qvalue. If charset is utf-8,
153  // it will return 'utf-8,*;q=0.5'. Otherwise (e.g. 'euc-jp'), it'll return
154  // 'euc-jp,utf-8;q=0.7,*;q=0.3'.
155  static std::string GenerateAcceptCharsetHeader(const std::string& charset);
156
157  // Helper. If |*headers| already contains |header_name| do nothing,
158  // otherwise add <header_name> ": " <header_value> to the end of the list.
159  static void AppendHeaderIfMissing(const char* header_name,
160                                    const std::string& header_value,
161                                    std::string* headers);
162
163  // Used to iterate over the name/value pairs of HTTP headers.  To iterate
164  // over the values in a multi-value header, use ValuesIterator.
165  // See AssembleRawHeaders for joining line continuations (this iterator
166  // does not expect any).
167  class HeadersIterator {
168   public:
169    HeadersIterator(std::string::const_iterator headers_begin,
170                    std::string::const_iterator headers_end,
171                    const std::string& line_delimiter);
172    ~HeadersIterator();
173
174    // Advances the iterator to the next header, if any.  Returns true if there
175    // is a next header.  Use name* and values* methods to access the resultant
176    // header name and values.
177    bool GetNext();
178
179    // Iterates through the list of headers, starting with the current position
180    // and looks for the specified header.  Note that the name _must_ be
181    // lower cased.
182    // If the header was found, the return value will be true and the current
183    // position points to the header.  If the return value is false, the
184    // current position will be at the end of the headers.
185    bool AdvanceTo(const char* lowercase_name);
186
187    void Reset() {
188      lines_.Reset();
189    }
190
191    std::string::const_iterator name_begin() const {
192      return name_begin_;
193    }
194    std::string::const_iterator name_end() const {
195      return name_end_;
196    }
197    std::string name() const {
198      return std::string(name_begin_, name_end_);
199    }
200
201    std::string::const_iterator values_begin() const {
202      return values_begin_;
203    }
204    std::string::const_iterator values_end() const {
205      return values_end_;
206    }
207    std::string values() const {
208      return std::string(values_begin_, values_end_);
209    }
210
211   private:
212    StringTokenizer lines_;
213    std::string::const_iterator name_begin_;
214    std::string::const_iterator name_end_;
215    std::string::const_iterator values_begin_;
216    std::string::const_iterator values_end_;
217  };
218
219  // Iterates over delimited values in an HTTP header.  HTTP LWS is
220  // automatically trimmed from the resulting values.
221  //
222  // When using this class to iterate over response header values, be aware that
223  // for some headers (e.g., Last-Modified), commas are not used as delimiters.
224  // This iterator should be avoided for headers like that which are considered
225  // non-coalescing (see IsNonCoalescingHeader).
226  //
227  // This iterator is careful to skip over delimiters found inside an HTTP
228  // quoted string.
229  //
230  class ValuesIterator {
231   public:
232    ValuesIterator(std::string::const_iterator values_begin,
233                   std::string::const_iterator values_end,
234                   char delimiter);
235    ~ValuesIterator();
236
237    // Advances the iterator to the next value, if any.  Returns true if there
238    // is a next value.  Use value* methods to access the resultant value.
239    bool GetNext();
240
241    std::string::const_iterator value_begin() const {
242      return value_begin_;
243    }
244    std::string::const_iterator value_end() const {
245      return value_end_;
246    }
247    std::string value() const {
248      return std::string(value_begin_, value_end_);
249    }
250
251   private:
252    StringTokenizer values_;
253    std::string::const_iterator value_begin_;
254    std::string::const_iterator value_end_;
255  };
256
257  // Iterates over a delimited sequence of name-value pairs in an HTTP header.
258  // Each pair consists of a token (the name), an equals sign, and either a
259  // token or quoted-string (the value). Arbitrary HTTP LWS is permitted outside
260  // of and between names, values, and delimiters.
261  //
262  // String iterators returned from this class' methods may be invalidated upon
263  // calls to GetNext() or after the NameValuePairsIterator is destroyed.
264  class NameValuePairsIterator {
265   public:
266    NameValuePairsIterator(std::string::const_iterator begin,
267                           std::string::const_iterator end,
268                           char delimiter);
269    ~NameValuePairsIterator();
270
271    // Advances the iterator to the next pair, if any.  Returns true if there
272    // is a next pair.  Use name* and value* methods to access the resultant
273    // value.
274    bool GetNext();
275
276    // Returns false if there was a parse error.
277    bool valid() const { return valid_; }
278
279    // The name of the current name-value pair.
280    std::string::const_iterator name_begin() const { return name_begin_; }
281    std::string::const_iterator name_end() const { return name_end_; }
282    std::string name() const { return std::string(name_begin_, name_end_); }
283
284    // The value of the current name-value pair.
285    std::string::const_iterator value_begin() const {
286      return value_is_quoted_ ? unquoted_value_.begin() : value_begin_;
287    }
288    std::string::const_iterator value_end() const {
289      return value_is_quoted_ ? unquoted_value_.end() : value_end_;
290    }
291    std::string value() const {
292      return value_is_quoted_ ? unquoted_value_ : std::string(value_begin_,
293                                                               value_end_);
294    }
295
296   private:
297    HttpUtil::ValuesIterator props_;
298    bool valid_;
299
300    std::string::const_iterator begin_;
301    std::string::const_iterator end_;
302
303    std::string::const_iterator name_begin_;
304    std::string::const_iterator name_end_;
305
306    std::string::const_iterator value_begin_;
307    std::string::const_iterator value_end_;
308
309    // Do not store iterators into this string. The NameValuePairsIterator
310    // is copyable/assignable, and if copied the copy's iterators would point
311    // into the original's unquoted_value_ member.
312    std::string unquoted_value_;
313
314    bool value_is_quoted_;
315  };
316};
317
318}  // namespace net
319
320#endif  // NET_HTTP_HTTP_UTIL_H_
321