Home | History | Annotate | Download | only in base
      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