1 /* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef WEBRTC_BASE_HTTPCOMMON_H__ 12 #define WEBRTC_BASE_HTTPCOMMON_H__ 13 14 #include <map> 15 #include <string> 16 #include <vector> 17 #include "webrtc/base/basictypes.h" 18 #include "webrtc/base/common.h" 19 #include "webrtc/base/scoped_ptr.h" 20 #include "webrtc/base/stringutils.h" 21 #include "webrtc/base/stream.h" 22 23 namespace rtc { 24 25 class CryptString; 26 class SocketAddress; 27 28 ////////////////////////////////////////////////////////////////////// 29 // Constants 30 ////////////////////////////////////////////////////////////////////// 31 32 enum HttpCode { 33 HC_OK = 200, 34 HC_NON_AUTHORITATIVE = 203, 35 HC_NO_CONTENT = 204, 36 HC_PARTIAL_CONTENT = 206, 37 38 HC_MULTIPLE_CHOICES = 300, 39 HC_MOVED_PERMANENTLY = 301, 40 HC_FOUND = 302, 41 HC_SEE_OTHER = 303, 42 HC_NOT_MODIFIED = 304, 43 HC_MOVED_TEMPORARILY = 307, 44 45 HC_BAD_REQUEST = 400, 46 HC_UNAUTHORIZED = 401, 47 HC_FORBIDDEN = 403, 48 HC_NOT_FOUND = 404, 49 HC_PROXY_AUTHENTICATION_REQUIRED = 407, 50 HC_GONE = 410, 51 52 HC_INTERNAL_SERVER_ERROR = 500, 53 HC_NOT_IMPLEMENTED = 501, 54 HC_SERVICE_UNAVAILABLE = 503, 55 }; 56 57 enum HttpVersion { 58 HVER_1_0, HVER_1_1, HVER_UNKNOWN, 59 HVER_LAST = HVER_UNKNOWN 60 }; 61 62 enum HttpVerb { 63 HV_GET, HV_POST, HV_PUT, HV_DELETE, HV_CONNECT, HV_HEAD, 64 HV_LAST = HV_HEAD 65 }; 66 67 enum HttpError { 68 HE_NONE, 69 HE_PROTOCOL, // Received non-valid HTTP data 70 HE_DISCONNECTED, // Connection closed unexpectedly 71 HE_OVERFLOW, // Received too much data for internal buffers 72 HE_CONNECT_FAILED, // The socket failed to connect. 73 HE_SOCKET_ERROR, // An error occurred on a connected socket 74 HE_SHUTDOWN, // Http object is being destroyed 75 HE_OPERATION_CANCELLED, // Connection aborted locally 76 HE_AUTH, // Proxy Authentication Required 77 HE_CERTIFICATE_EXPIRED, // During SSL negotiation 78 HE_STREAM, // Problem reading or writing to the document 79 HE_CACHE, // Problem reading from cache 80 HE_DEFAULT 81 }; 82 83 enum HttpHeader { 84 HH_AGE, 85 HH_CACHE_CONTROL, 86 HH_CONNECTION, 87 HH_CONTENT_DISPOSITION, 88 HH_CONTENT_LENGTH, 89 HH_CONTENT_RANGE, 90 HH_CONTENT_TYPE, 91 HH_COOKIE, 92 HH_DATE, 93 HH_ETAG, 94 HH_EXPIRES, 95 HH_HOST, 96 HH_IF_MODIFIED_SINCE, 97 HH_IF_NONE_MATCH, 98 HH_KEEP_ALIVE, 99 HH_LAST_MODIFIED, 100 HH_LOCATION, 101 HH_PROXY_AUTHENTICATE, 102 HH_PROXY_AUTHORIZATION, 103 HH_PROXY_CONNECTION, 104 HH_RANGE, 105 HH_SET_COOKIE, 106 HH_TE, 107 HH_TRAILERS, 108 HH_TRANSFER_ENCODING, 109 HH_UPGRADE, 110 HH_USER_AGENT, 111 HH_WWW_AUTHENTICATE, 112 HH_LAST = HH_WWW_AUTHENTICATE 113 }; 114 115 const uint16 HTTP_DEFAULT_PORT = 80; 116 const uint16 HTTP_SECURE_PORT = 443; 117 118 ////////////////////////////////////////////////////////////////////// 119 // Utility Functions 120 ////////////////////////////////////////////////////////////////////// 121 122 inline HttpError mkerr(HttpError err, HttpError def_err = HE_DEFAULT) { 123 return (err != HE_NONE) ? err : def_err; 124 } 125 126 const char* ToString(HttpVersion version); 127 bool FromString(HttpVersion& version, const std::string& str); 128 129 const char* ToString(HttpVerb verb); 130 bool FromString(HttpVerb& verb, const std::string& str); 131 132 const char* ToString(HttpHeader header); 133 bool FromString(HttpHeader& header, const std::string& str); 134 135 inline bool HttpCodeIsInformational(uint32 code) { return ((code / 100) == 1); } 136 inline bool HttpCodeIsSuccessful(uint32 code) { return ((code / 100) == 2); } 137 inline bool HttpCodeIsRedirection(uint32 code) { return ((code / 100) == 3); } 138 inline bool HttpCodeIsClientError(uint32 code) { return ((code / 100) == 4); } 139 inline bool HttpCodeIsServerError(uint32 code) { return ((code / 100) == 5); } 140 141 bool HttpCodeHasBody(uint32 code); 142 bool HttpCodeIsCacheable(uint32 code); 143 bool HttpHeaderIsEndToEnd(HttpHeader header); 144 bool HttpHeaderIsCollapsible(HttpHeader header); 145 146 struct HttpData; 147 bool HttpShouldKeepAlive(const HttpData& data); 148 149 typedef std::pair<std::string, std::string> HttpAttribute; 150 typedef std::vector<HttpAttribute> HttpAttributeList; 151 void HttpComposeAttributes(const HttpAttributeList& attributes, char separator, 152 std::string* composed); 153 void HttpParseAttributes(const char * data, size_t len, 154 HttpAttributeList& attributes); 155 bool HttpHasAttribute(const HttpAttributeList& attributes, 156 const std::string& name, 157 std::string* value); 158 bool HttpHasNthAttribute(HttpAttributeList& attributes, 159 size_t index, 160 std::string* name, 161 std::string* value); 162 163 // Convert RFC1123 date (DoW, DD Mon YYYY HH:MM:SS TZ) to unix timestamp 164 bool HttpDateToSeconds(const std::string& date, time_t* seconds); 165 166 inline uint16 HttpDefaultPort(bool secure) { 167 return secure ? HTTP_SECURE_PORT : HTTP_DEFAULT_PORT; 168 } 169 170 // Returns the http server notation for a given address 171 std::string HttpAddress(const SocketAddress& address, bool secure); 172 173 // functional for insensitive std::string compare 174 struct iless { 175 bool operator()(const std::string& lhs, const std::string& rhs) const { 176 return (::_stricmp(lhs.c_str(), rhs.c_str()) < 0); 177 } 178 }; 179 180 // put quotes around a string and escape any quotes inside it 181 std::string quote(const std::string& str); 182 183 ////////////////////////////////////////////////////////////////////// 184 // Url 185 ////////////////////////////////////////////////////////////////////// 186 187 template<class CTYPE> 188 class Url { 189 public: 190 typedef typename Traits<CTYPE>::string string; 191 192 // TODO: Implement Encode/Decode 193 static int Encode(const CTYPE* source, CTYPE* destination, size_t len); 194 static int Encode(const string& source, string& destination); 195 static int Decode(const CTYPE* source, CTYPE* destination, size_t len); 196 static int Decode(const string& source, string& destination); 197 198 Url(const string& url) { do_set_url(url.c_str(), url.size()); } 199 Url(const string& path, const string& host, uint16 port = HTTP_DEFAULT_PORT) 200 : host_(host), port_(port), secure_(HTTP_SECURE_PORT == port) 201 { set_full_path(path); } 202 203 bool valid() const { return !host_.empty(); } 204 void clear() { 205 host_.clear(); 206 port_ = HTTP_DEFAULT_PORT; 207 secure_ = false; 208 path_.assign(1, static_cast<CTYPE>('/')); 209 query_.clear(); 210 } 211 212 void set_url(const string& val) { 213 do_set_url(val.c_str(), val.size()); 214 } 215 string url() const { 216 string val; do_get_url(&val); return val; 217 } 218 219 void set_address(const string& val) { 220 do_set_address(val.c_str(), val.size()); 221 } 222 string address() const { 223 string val; do_get_address(&val); return val; 224 } 225 226 void set_full_path(const string& val) { 227 do_set_full_path(val.c_str(), val.size()); 228 } 229 string full_path() const { 230 string val; do_get_full_path(&val); return val; 231 } 232 233 void set_host(const string& val) { host_ = val; } 234 const string& host() const { return host_; } 235 236 void set_port(uint16 val) { port_ = val; } 237 uint16 port() const { return port_; } 238 239 void set_secure(bool val) { secure_ = val; } 240 bool secure() const { return secure_; } 241 242 void set_path(const string& val) { 243 if (val.empty()) { 244 path_.assign(1, static_cast<CTYPE>('/')); 245 } else { 246 ASSERT(val[0] == static_cast<CTYPE>('/')); 247 path_ = val; 248 } 249 } 250 const string& path() const { return path_; } 251 252 void set_query(const string& val) { 253 ASSERT(val.empty() || (val[0] == static_cast<CTYPE>('?'))); 254 query_ = val; 255 } 256 const string& query() const { return query_; } 257 258 bool get_attribute(const string& name, string* value) const; 259 260 private: 261 void do_set_url(const CTYPE* val, size_t len); 262 void do_set_address(const CTYPE* val, size_t len); 263 void do_set_full_path(const CTYPE* val, size_t len); 264 265 void do_get_url(string* val) const; 266 void do_get_address(string* val) const; 267 void do_get_full_path(string* val) const; 268 269 string host_, path_, query_; 270 uint16 port_; 271 bool secure_; 272 }; 273 274 ////////////////////////////////////////////////////////////////////// 275 // HttpData 276 ////////////////////////////////////////////////////////////////////// 277 278 struct HttpData { 279 typedef std::multimap<std::string, std::string, iless> HeaderMap; 280 typedef HeaderMap::const_iterator const_iterator; 281 typedef HeaderMap::iterator iterator; 282 283 HttpVersion version; 284 scoped_ptr<StreamInterface> document; 285 286 HttpData() : version(HVER_1_1) { } 287 288 enum HeaderCombine { HC_YES, HC_NO, HC_AUTO, HC_REPLACE, HC_NEW }; 289 void changeHeader(const std::string& name, const std::string& value, 290 HeaderCombine combine); 291 inline void addHeader(const std::string& name, const std::string& value, 292 bool append = true) { 293 changeHeader(name, value, append ? HC_AUTO : HC_NO); 294 } 295 inline void setHeader(const std::string& name, const std::string& value, 296 bool overwrite = true) { 297 changeHeader(name, value, overwrite ? HC_REPLACE : HC_NEW); 298 } 299 // Returns count of erased headers 300 size_t clearHeader(const std::string& name); 301 // Returns iterator to next header 302 iterator clearHeader(iterator header); 303 304 // keep in mind, this may not do what you want in the face of multiple headers 305 bool hasHeader(const std::string& name, std::string* value) const; 306 307 inline const_iterator begin() const { 308 return headers_.begin(); 309 } 310 inline const_iterator end() const { 311 return headers_.end(); 312 } 313 inline iterator begin() { 314 return headers_.begin(); 315 } 316 inline iterator end() { 317 return headers_.end(); 318 } 319 inline const_iterator begin(const std::string& name) const { 320 return headers_.lower_bound(name); 321 } 322 inline const_iterator end(const std::string& name) const { 323 return headers_.upper_bound(name); 324 } 325 inline iterator begin(const std::string& name) { 326 return headers_.lower_bound(name); 327 } 328 inline iterator end(const std::string& name) { 329 return headers_.upper_bound(name); 330 } 331 332 // Convenience methods using HttpHeader 333 inline void changeHeader(HttpHeader header, const std::string& value, 334 HeaderCombine combine) { 335 changeHeader(ToString(header), value, combine); 336 } 337 inline void addHeader(HttpHeader header, const std::string& value, 338 bool append = true) { 339 addHeader(ToString(header), value, append); 340 } 341 inline void setHeader(HttpHeader header, const std::string& value, 342 bool overwrite = true) { 343 setHeader(ToString(header), value, overwrite); 344 } 345 inline void clearHeader(HttpHeader header) { 346 clearHeader(ToString(header)); 347 } 348 inline bool hasHeader(HttpHeader header, std::string* value) const { 349 return hasHeader(ToString(header), value); 350 } 351 inline const_iterator begin(HttpHeader header) const { 352 return headers_.lower_bound(ToString(header)); 353 } 354 inline const_iterator end(HttpHeader header) const { 355 return headers_.upper_bound(ToString(header)); 356 } 357 inline iterator begin(HttpHeader header) { 358 return headers_.lower_bound(ToString(header)); 359 } 360 inline iterator end(HttpHeader header) { 361 return headers_.upper_bound(ToString(header)); 362 } 363 364 void setContent(const std::string& content_type, StreamInterface* document); 365 void setDocumentAndLength(StreamInterface* document); 366 367 virtual size_t formatLeader(char* buffer, size_t size) const = 0; 368 virtual HttpError parseLeader(const char* line, size_t len) = 0; 369 370 protected: 371 virtual ~HttpData() { } 372 void clear(bool release_document); 373 void copy(const HttpData& src); 374 375 private: 376 HeaderMap headers_; 377 }; 378 379 struct HttpRequestData : public HttpData { 380 HttpVerb verb; 381 std::string path; 382 383 HttpRequestData() : verb(HV_GET) { } 384 385 void clear(bool release_document); 386 void copy(const HttpRequestData& src); 387 388 virtual size_t formatLeader(char* buffer, size_t size) const; 389 virtual HttpError parseLeader(const char* line, size_t len); 390 391 bool getAbsoluteUri(std::string* uri) const; 392 bool getRelativeUri(std::string* host, std::string* path) const; 393 }; 394 395 struct HttpResponseData : public HttpData { 396 uint32 scode; 397 std::string message; 398 399 HttpResponseData() : scode(HC_INTERNAL_SERVER_ERROR) { } 400 void clear(bool release_document); 401 void copy(const HttpResponseData& src); 402 403 // Convenience methods 404 void set_success(uint32 scode = HC_OK); 405 void set_success(const std::string& content_type, StreamInterface* document, 406 uint32 scode = HC_OK); 407 void set_redirect(const std::string& location, 408 uint32 scode = HC_MOVED_TEMPORARILY); 409 void set_error(uint32 scode); 410 411 virtual size_t formatLeader(char* buffer, size_t size) const; 412 virtual HttpError parseLeader(const char* line, size_t len); 413 }; 414 415 struct HttpTransaction { 416 HttpRequestData request; 417 HttpResponseData response; 418 }; 419 420 ////////////////////////////////////////////////////////////////////// 421 // Http Authentication 422 ////////////////////////////////////////////////////////////////////// 423 424 struct HttpAuthContext { 425 std::string auth_method; 426 HttpAuthContext(const std::string& auth) : auth_method(auth) { } 427 virtual ~HttpAuthContext() { } 428 }; 429 430 enum HttpAuthResult { HAR_RESPONSE, HAR_IGNORE, HAR_CREDENTIALS, HAR_ERROR }; 431 432 // 'context' is used by this function to record information between calls. 433 // Start by passing a null pointer, then pass the same pointer each additional 434 // call. When the authentication attempt is finished, delete the context. 435 HttpAuthResult HttpAuthenticate( 436 const char * challenge, size_t len, 437 const SocketAddress& server, 438 const std::string& method, const std::string& uri, 439 const std::string& username, const CryptString& password, 440 HttpAuthContext *& context, std::string& response, std::string& auth_method); 441 442 ////////////////////////////////////////////////////////////////////// 443 444 } // namespace rtc 445 446 #endif // WEBRTC_BASE_HTTPCOMMON_H__ 447