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 23namespace rtc { 24 25class CryptString; 26class SocketAddress; 27 28////////////////////////////////////////////////////////////////////// 29// Constants 30////////////////////////////////////////////////////////////////////// 31 32enum 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 57enum HttpVersion { 58 HVER_1_0, HVER_1_1, HVER_UNKNOWN, 59 HVER_LAST = HVER_UNKNOWN 60}; 61 62enum HttpVerb { 63 HV_GET, HV_POST, HV_PUT, HV_DELETE, HV_CONNECT, HV_HEAD, 64 HV_LAST = HV_HEAD 65}; 66 67enum 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 83enum 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 115const uint16_t HTTP_DEFAULT_PORT = 80; 116const uint16_t HTTP_SECURE_PORT = 443; 117 118////////////////////////////////////////////////////////////////////// 119// Utility Functions 120////////////////////////////////////////////////////////////////////// 121 122inline HttpError mkerr(HttpError err, HttpError def_err = HE_DEFAULT) { 123 return (err != HE_NONE) ? err : def_err; 124} 125 126const char* ToString(HttpVersion version); 127bool FromString(HttpVersion& version, const std::string& str); 128 129const char* ToString(HttpVerb verb); 130bool FromString(HttpVerb& verb, const std::string& str); 131 132const char* ToString(HttpHeader header); 133bool FromString(HttpHeader& header, const std::string& str); 134 135inline bool HttpCodeIsInformational(uint32_t code) { 136 return ((code / 100) == 1); 137} 138inline bool HttpCodeIsSuccessful(uint32_t code) { 139 return ((code / 100) == 2); 140} 141inline bool HttpCodeIsRedirection(uint32_t code) { 142 return ((code / 100) == 3); 143} 144inline bool HttpCodeIsClientError(uint32_t code) { 145 return ((code / 100) == 4); 146} 147inline bool HttpCodeIsServerError(uint32_t code) { 148 return ((code / 100) == 5); 149} 150 151bool HttpCodeHasBody(uint32_t code); 152bool HttpCodeIsCacheable(uint32_t code); 153bool HttpHeaderIsEndToEnd(HttpHeader header); 154bool HttpHeaderIsCollapsible(HttpHeader header); 155 156struct HttpData; 157bool HttpShouldKeepAlive(const HttpData& data); 158 159typedef std::pair<std::string, std::string> HttpAttribute; 160typedef std::vector<HttpAttribute> HttpAttributeList; 161void HttpComposeAttributes(const HttpAttributeList& attributes, char separator, 162 std::string* composed); 163void HttpParseAttributes(const char * data, size_t len, 164 HttpAttributeList& attributes); 165bool HttpHasAttribute(const HttpAttributeList& attributes, 166 const std::string& name, 167 std::string* value); 168bool HttpHasNthAttribute(HttpAttributeList& attributes, 169 size_t index, 170 std::string* name, 171 std::string* value); 172 173// Convert RFC1123 date (DoW, DD Mon YYYY HH:MM:SS TZ) to unix timestamp 174bool HttpDateToSeconds(const std::string& date, time_t* seconds); 175 176inline uint16_t HttpDefaultPort(bool secure) { 177 return secure ? HTTP_SECURE_PORT : HTTP_DEFAULT_PORT; 178} 179 180// Returns the http server notation for a given address 181std::string HttpAddress(const SocketAddress& address, bool secure); 182 183// functional for insensitive std::string compare 184struct iless { 185 bool operator()(const std::string& lhs, const std::string& rhs) const { 186 return (::_stricmp(lhs.c_str(), rhs.c_str()) < 0); 187 } 188}; 189 190// put quotes around a string and escape any quotes inside it 191std::string quote(const std::string& str); 192 193////////////////////////////////////////////////////////////////////// 194// Url 195////////////////////////////////////////////////////////////////////// 196 197template<class CTYPE> 198class Url { 199public: 200 typedef typename Traits<CTYPE>::string string; 201 202 // TODO: Implement Encode/Decode 203 static int Encode(const CTYPE* source, CTYPE* destination, size_t len); 204 static int Encode(const string& source, string& destination); 205 static int Decode(const CTYPE* source, CTYPE* destination, size_t len); 206 static int Decode(const string& source, string& destination); 207 208 Url(const string& url) { do_set_url(url.c_str(), url.size()); } 209 Url(const string& path, const string& host, uint16_t port = HTTP_DEFAULT_PORT) 210 : host_(host), port_(port), secure_(HTTP_SECURE_PORT == port) { 211 set_full_path(path); 212 } 213 214 bool valid() const { return !host_.empty(); } 215 void clear() { 216 host_.clear(); 217 port_ = HTTP_DEFAULT_PORT; 218 secure_ = false; 219 path_.assign(1, static_cast<CTYPE>('/')); 220 query_.clear(); 221 } 222 223 void set_url(const string& val) { 224 do_set_url(val.c_str(), val.size()); 225 } 226 string url() const { 227 string val; do_get_url(&val); return val; 228 } 229 230 void set_address(const string& val) { 231 do_set_address(val.c_str(), val.size()); 232 } 233 string address() const { 234 string val; do_get_address(&val); return val; 235 } 236 237 void set_full_path(const string& val) { 238 do_set_full_path(val.c_str(), val.size()); 239 } 240 string full_path() const { 241 string val; do_get_full_path(&val); return val; 242 } 243 244 void set_host(const string& val) { host_ = val; } 245 const string& host() const { return host_; } 246 247 void set_port(uint16_t val) { port_ = val; } 248 uint16_t port() const { return port_; } 249 250 void set_secure(bool val) { secure_ = val; } 251 bool secure() const { return secure_; } 252 253 void set_path(const string& val) { 254 if (val.empty()) { 255 path_.assign(1, static_cast<CTYPE>('/')); 256 } else { 257 ASSERT(val[0] == static_cast<CTYPE>('/')); 258 path_ = val; 259 } 260 } 261 const string& path() const { return path_; } 262 263 void set_query(const string& val) { 264 ASSERT(val.empty() || (val[0] == static_cast<CTYPE>('?'))); 265 query_ = val; 266 } 267 const string& query() const { return query_; } 268 269 bool get_attribute(const string& name, string* value) const; 270 271private: 272 void do_set_url(const CTYPE* val, size_t len); 273 void do_set_address(const CTYPE* val, size_t len); 274 void do_set_full_path(const CTYPE* val, size_t len); 275 276 void do_get_url(string* val) const; 277 void do_get_address(string* val) const; 278 void do_get_full_path(string* val) const; 279 280 string host_, path_, query_; 281 uint16_t port_; 282 bool secure_; 283}; 284 285////////////////////////////////////////////////////////////////////// 286// HttpData 287////////////////////////////////////////////////////////////////////// 288 289struct HttpData { 290 typedef std::multimap<std::string, std::string, iless> HeaderMap; 291 typedef HeaderMap::const_iterator const_iterator; 292 typedef HeaderMap::iterator iterator; 293 294 HttpVersion version; 295 scoped_ptr<StreamInterface> document; 296 297 HttpData(); 298 299 enum HeaderCombine { HC_YES, HC_NO, HC_AUTO, HC_REPLACE, HC_NEW }; 300 void changeHeader(const std::string& name, const std::string& value, 301 HeaderCombine combine); 302 inline void addHeader(const std::string& name, const std::string& value, 303 bool append = true) { 304 changeHeader(name, value, append ? HC_AUTO : HC_NO); 305 } 306 inline void setHeader(const std::string& name, const std::string& value, 307 bool overwrite = true) { 308 changeHeader(name, value, overwrite ? HC_REPLACE : HC_NEW); 309 } 310 // Returns count of erased headers 311 size_t clearHeader(const std::string& name); 312 // Returns iterator to next header 313 iterator clearHeader(iterator header); 314 315 // keep in mind, this may not do what you want in the face of multiple headers 316 bool hasHeader(const std::string& name, std::string* value) const; 317 318 inline const_iterator begin() const { 319 return headers_.begin(); 320 } 321 inline const_iterator end() const { 322 return headers_.end(); 323 } 324 inline iterator begin() { 325 return headers_.begin(); 326 } 327 inline iterator end() { 328 return headers_.end(); 329 } 330 inline const_iterator begin(const std::string& name) const { 331 return headers_.lower_bound(name); 332 } 333 inline const_iterator end(const std::string& name) const { 334 return headers_.upper_bound(name); 335 } 336 inline iterator begin(const std::string& name) { 337 return headers_.lower_bound(name); 338 } 339 inline iterator end(const std::string& name) { 340 return headers_.upper_bound(name); 341 } 342 343 // Convenience methods using HttpHeader 344 inline void changeHeader(HttpHeader header, const std::string& value, 345 HeaderCombine combine) { 346 changeHeader(ToString(header), value, combine); 347 } 348 inline void addHeader(HttpHeader header, const std::string& value, 349 bool append = true) { 350 addHeader(ToString(header), value, append); 351 } 352 inline void setHeader(HttpHeader header, const std::string& value, 353 bool overwrite = true) { 354 setHeader(ToString(header), value, overwrite); 355 } 356 inline void clearHeader(HttpHeader header) { 357 clearHeader(ToString(header)); 358 } 359 inline bool hasHeader(HttpHeader header, std::string* value) const { 360 return hasHeader(ToString(header), value); 361 } 362 inline const_iterator begin(HttpHeader header) const { 363 return headers_.lower_bound(ToString(header)); 364 } 365 inline const_iterator end(HttpHeader header) const { 366 return headers_.upper_bound(ToString(header)); 367 } 368 inline iterator begin(HttpHeader header) { 369 return headers_.lower_bound(ToString(header)); 370 } 371 inline iterator end(HttpHeader header) { 372 return headers_.upper_bound(ToString(header)); 373 } 374 375 void setContent(const std::string& content_type, StreamInterface* document); 376 void setDocumentAndLength(StreamInterface* document); 377 378 virtual size_t formatLeader(char* buffer, size_t size) const = 0; 379 virtual HttpError parseLeader(const char* line, size_t len) = 0; 380 381protected: 382 virtual ~HttpData(); 383 void clear(bool release_document); 384 void copy(const HttpData& src); 385 386private: 387 HeaderMap headers_; 388}; 389 390struct HttpRequestData : public HttpData { 391 HttpVerb verb; 392 std::string path; 393 394 HttpRequestData() : verb(HV_GET) { } 395 396 void clear(bool release_document); 397 void copy(const HttpRequestData& src); 398 399 size_t formatLeader(char* buffer, size_t size) const override; 400 HttpError parseLeader(const char* line, size_t len) override; 401 402 bool getAbsoluteUri(std::string* uri) const; 403 bool getRelativeUri(std::string* host, std::string* path) const; 404}; 405 406struct HttpResponseData : public HttpData { 407 uint32_t scode; 408 std::string message; 409 410 HttpResponseData() : scode(HC_INTERNAL_SERVER_ERROR) { } 411 void clear(bool release_document); 412 void copy(const HttpResponseData& src); 413 414 // Convenience methods 415 void set_success(uint32_t scode = HC_OK); 416 void set_success(const std::string& content_type, 417 StreamInterface* document, 418 uint32_t scode = HC_OK); 419 void set_redirect(const std::string& location, 420 uint32_t scode = HC_MOVED_TEMPORARILY); 421 void set_error(uint32_t scode); 422 423 size_t formatLeader(char* buffer, size_t size) const override; 424 HttpError parseLeader(const char* line, size_t len) override; 425}; 426 427struct HttpTransaction { 428 HttpRequestData request; 429 HttpResponseData response; 430}; 431 432////////////////////////////////////////////////////////////////////// 433// Http Authentication 434////////////////////////////////////////////////////////////////////// 435 436struct HttpAuthContext { 437 std::string auth_method; 438 HttpAuthContext(const std::string& auth) : auth_method(auth) { } 439 virtual ~HttpAuthContext() { } 440}; 441 442enum HttpAuthResult { HAR_RESPONSE, HAR_IGNORE, HAR_CREDENTIALS, HAR_ERROR }; 443 444// 'context' is used by this function to record information between calls. 445// Start by passing a null pointer, then pass the same pointer each additional 446// call. When the authentication attempt is finished, delete the context. 447HttpAuthResult HttpAuthenticate( 448 const char * challenge, size_t len, 449 const SocketAddress& server, 450 const std::string& method, const std::string& uri, 451 const std::string& username, const CryptString& password, 452 HttpAuthContext *& context, std::string& response, std::string& auth_method); 453 454////////////////////////////////////////////////////////////////////// 455 456} // namespace rtc 457 458#endif // WEBRTC_BASE_HTTPCOMMON_H__ 459