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_t HTTP_DEFAULT_PORT = 80;
    116 const uint16_t 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_t code) {
    136   return ((code / 100) == 1);
    137 }
    138 inline bool HttpCodeIsSuccessful(uint32_t code) {
    139   return ((code / 100) == 2);
    140 }
    141 inline bool HttpCodeIsRedirection(uint32_t code) {
    142   return ((code / 100) == 3);
    143 }
    144 inline bool HttpCodeIsClientError(uint32_t code) {
    145   return ((code / 100) == 4);
    146 }
    147 inline bool HttpCodeIsServerError(uint32_t code) {
    148   return ((code / 100) == 5);
    149 }
    150 
    151 bool HttpCodeHasBody(uint32_t code);
    152 bool HttpCodeIsCacheable(uint32_t code);
    153 bool HttpHeaderIsEndToEnd(HttpHeader header);
    154 bool HttpHeaderIsCollapsible(HttpHeader header);
    155 
    156 struct HttpData;
    157 bool HttpShouldKeepAlive(const HttpData& data);
    158 
    159 typedef std::pair<std::string, std::string> HttpAttribute;
    160 typedef std::vector<HttpAttribute> HttpAttributeList;
    161 void HttpComposeAttributes(const HttpAttributeList& attributes, char separator,
    162                            std::string* composed);
    163 void HttpParseAttributes(const char * data, size_t len,
    164                          HttpAttributeList& attributes);
    165 bool HttpHasAttribute(const HttpAttributeList& attributes,
    166                       const std::string& name,
    167                       std::string* value);
    168 bool 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
    174 bool HttpDateToSeconds(const std::string& date, time_t* seconds);
    175 
    176 inline 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
    181 std::string HttpAddress(const SocketAddress& address, bool secure);
    182 
    183 // functional for insensitive std::string compare
    184 struct 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
    191 std::string quote(const std::string& str);
    192 
    193 //////////////////////////////////////////////////////////////////////
    194 // Url
    195 //////////////////////////////////////////////////////////////////////
    196 
    197 template<class CTYPE>
    198 class Url {
    199 public:
    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 
    271 private:
    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 
    289 struct 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 
    381 protected:
    382  virtual ~HttpData();
    383   void clear(bool release_document);
    384   void copy(const HttpData& src);
    385 
    386 private:
    387   HeaderMap headers_;
    388 };
    389 
    390 struct 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 
    406 struct 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 
    427 struct HttpTransaction {
    428   HttpRequestData request;
    429   HttpResponseData response;
    430 };
    431 
    432 //////////////////////////////////////////////////////////////////////
    433 // Http Authentication
    434 //////////////////////////////////////////////////////////////////////
    435 
    436 struct HttpAuthContext {
    437   std::string auth_method;
    438   HttpAuthContext(const std::string& auth) : auth_method(auth) { }
    439   virtual ~HttpAuthContext() { }
    440 };
    441 
    442 enum 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.
    447 HttpAuthResult 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