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