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