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, time_t* 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