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
HttpCodeIsInformational(uint32_t code)135 inline bool HttpCodeIsInformational(uint32_t code) {
136 return ((code / 100) == 1);
137 }
HttpCodeIsSuccessful(uint32_t code)138 inline bool HttpCodeIsSuccessful(uint32_t code) {
139 return ((code / 100) == 2);
140 }
HttpCodeIsRedirection(uint32_t code)141 inline bool HttpCodeIsRedirection(uint32_t code) {
142 return ((code / 100) == 3);
143 }
HttpCodeIsClientError(uint32_t code)144 inline bool HttpCodeIsClientError(uint32_t code) {
145 return ((code / 100) == 4);
146 }
HttpCodeIsServerError(uint32_t code)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
HttpDefaultPort(bool secure)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 {
operatoriless185 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
Url(const string & url)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)
host_(host)210 : host_(host), port_(port), secure_(HTTP_SECURE_PORT == port) {
211 set_full_path(path);
212 }
213
valid()214 bool valid() const { return !host_.empty(); }
clear()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
set_url(const string & val)223 void set_url(const string& val) {
224 do_set_url(val.c_str(), val.size());
225 }
url()226 string url() const {
227 string val; do_get_url(&val); return val;
228 }
229
set_address(const string & val)230 void set_address(const string& val) {
231 do_set_address(val.c_str(), val.size());
232 }
address()233 string address() const {
234 string val; do_get_address(&val); return val;
235 }
236
set_full_path(const string & val)237 void set_full_path(const string& val) {
238 do_set_full_path(val.c_str(), val.size());
239 }
full_path()240 string full_path() const {
241 string val; do_get_full_path(&val); return val;
242 }
243
set_host(const string & val)244 void set_host(const string& val) { host_ = val; }
host()245 const string& host() const { return host_; }
246
set_port(uint16_t val)247 void set_port(uint16_t val) { port_ = val; }
port()248 uint16_t port() const { return port_; }
249
set_secure(bool val)250 void set_secure(bool val) { secure_ = val; }
secure()251 bool secure() const { return secure_; }
252
set_path(const string & val)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 }
path()261 const string& path() const { return path_; }
262
set_query(const string & val)263 void set_query(const string& val) {
264 ASSERT(val.empty() || (val[0] == static_cast<CTYPE>('?')));
265 query_ = val;
266 }
query()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
beginHttpData318 inline const_iterator begin() const {
319 return headers_.begin();
320 }
endHttpData321 inline const_iterator end() const {
322 return headers_.end();
323 }
beginHttpData324 inline iterator begin() {
325 return headers_.begin();
326 }
endHttpData327 inline iterator end() {
328 return headers_.end();
329 }
beginHttpData330 inline const_iterator begin(const std::string& name) const {
331 return headers_.lower_bound(name);
332 }
endHttpData333 inline const_iterator end(const std::string& name) const {
334 return headers_.upper_bound(name);
335 }
beginHttpData336 inline iterator begin(const std::string& name) {
337 return headers_.lower_bound(name);
338 }
endHttpData339 inline iterator end(const std::string& name) {
340 return headers_.upper_bound(name);
341 }
342
343 // Convenience methods using HttpHeader
changeHeaderHttpData344 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 }
clearHeaderHttpData356 inline void clearHeader(HttpHeader header) {
357 clearHeader(ToString(header));
358 }
hasHeaderHttpData359 inline bool hasHeader(HttpHeader header, std::string* value) const {
360 return hasHeader(ToString(header), value);
361 }
beginHttpData362 inline const_iterator begin(HttpHeader header) const {
363 return headers_.lower_bound(ToString(header));
364 }
endHttpData365 inline const_iterator end(HttpHeader header) const {
366 return headers_.upper_bound(ToString(header));
367 }
beginHttpData368 inline iterator begin(HttpHeader header) {
369 return headers_.lower_bound(ToString(header));
370 }
endHttpData371 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
HttpRequestDataHttpRequestData394 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
HttpResponseDataHttpResponseData410 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;
HttpAuthContextHttpAuthContext438 HttpAuthContext(const std::string& auth) : auth_method(auth) { }
~HttpAuthContextHttpAuthContext439 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