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 21 namespace net { 22 23 class UploadDataStream; 24 25 class 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