blob: 2897c5a5a66fb1502f67aebf5b55872d0ff267e0 [file] [log] [blame]
deadbeeff137e972017-03-23 22:45:491/*
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
Mirko Bonadei92ea95e2017-09-15 04:47:3111#ifndef RTC_BASE_HTTPCOMMON_H_
12#define RTC_BASE_HTTPCOMMON_H_
deadbeeff137e972017-03-23 22:45:4913
Henrik Kjellanderec78f1c2017-06-29 05:52:5014#include <map>
15#include <memory>
16#include <string>
17#include <vector>
Mirko Bonadei92ea95e2017-09-15 04:47:3118#include "rtc_base/basictypes.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/stream.h"
21#include "rtc_base/stringutils.h"
deadbeeff137e972017-03-23 22:45:4922
Henrik Kjellanderec78f1c2017-06-29 05:52:5023namespace rtc {
deadbeeff137e972017-03-23 22:45:4924
Henrik Kjellanderec78f1c2017-06-29 05:52:5025class 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;
Henrik Kjellanderec78f1c2017-06-29 05:52:50161void HttpParseAttributes(const char * data, size_t len,
162 HttpAttributeList& attributes);
163bool HttpHasAttribute(const HttpAttributeList& attributes,
164 const std::string& name,
165 std::string* value);
166bool HttpHasNthAttribute(HttpAttributeList& attributes,
167 size_t index,
168 std::string* name,
169 std::string* value);
170
171// Convert RFC1123 date (DoW, DD Mon YYYY HH:MM:SS TZ) to unix timestamp
172bool HttpDateToSeconds(const std::string& date, time_t* seconds);
173
174inline uint16_t HttpDefaultPort(bool secure) {
175 return secure ? HTTP_SECURE_PORT : HTTP_DEFAULT_PORT;
176}
177
178// Returns the http server notation for a given address
179std::string HttpAddress(const SocketAddress& address, bool secure);
180
181// functional for insensitive std::string compare
182struct iless {
183 bool operator()(const std::string& lhs, const std::string& rhs) const {
184 return (::_stricmp(lhs.c_str(), rhs.c_str()) < 0);
185 }
186};
187
188// put quotes around a string and escape any quotes inside it
189std::string quote(const std::string& str);
190
191//////////////////////////////////////////////////////////////////////
192// Url
193//////////////////////////////////////////////////////////////////////
194
195template<class CTYPE>
196class Url {
197public:
198 typedef typename Traits<CTYPE>::string string;
199
200 // TODO: Implement Encode/Decode
201 static int Encode(const CTYPE* source, CTYPE* destination, size_t len);
202 static int Encode(const string& source, string& destination);
203 static int Decode(const CTYPE* source, CTYPE* destination, size_t len);
204 static int Decode(const string& source, string& destination);
205
206 Url(const string& url) { do_set_url(url.c_str(), url.size()); }
207 Url(const string& path, const string& host, uint16_t port = HTTP_DEFAULT_PORT)
208 : host_(host), port_(port), secure_(HTTP_SECURE_PORT == port) {
209 set_full_path(path);
210 }
211
212 bool valid() const { return !host_.empty(); }
213 void clear() {
214 host_.clear();
215 port_ = HTTP_DEFAULT_PORT;
216 secure_ = false;
217 path_.assign(1, static_cast<CTYPE>('/'));
218 query_.clear();
219 }
220
221 void set_url(const string& val) {
222 do_set_url(val.c_str(), val.size());
223 }
224 string url() const {
225 string val; do_get_url(&val); return val;
226 }
227
228 void set_address(const string& val) {
229 do_set_address(val.c_str(), val.size());
230 }
231 string address() const {
232 string val; do_get_address(&val); return val;
233 }
234
235 void set_full_path(const string& val) {
236 do_set_full_path(val.c_str(), val.size());
237 }
238 string full_path() const {
239 string val; do_get_full_path(&val); return val;
240 }
241
242 void set_host(const string& val) { host_ = val; }
243 const string& host() const { return host_; }
244
245 void set_port(uint16_t val) { port_ = val; }
246 uint16_t port() const { return port_; }
247
248 void set_secure(bool val) { secure_ = val; }
249 bool secure() const { return secure_; }
250
251 void set_path(const string& val) {
252 if (val.empty()) {
253 path_.assign(1, static_cast<CTYPE>('/'));
254 } else {
255 RTC_DCHECK(val[0] == static_cast<CTYPE>('/'));
256 path_ = val;
257 }
258 }
259 const string& path() const { return path_; }
260
261 void set_query(const string& val) {
262 RTC_DCHECK(val.empty() || (val[0] == static_cast<CTYPE>('?')));
263 query_ = val;
264 }
265 const string& query() const { return query_; }
266
267 bool get_attribute(const string& name, string* value) const;
268
269private:
270 void do_set_url(const CTYPE* val, size_t len);
271 void do_set_address(const CTYPE* val, size_t len);
272 void do_set_full_path(const CTYPE* val, size_t len);
273
274 void do_get_url(string* val) const;
275 void do_get_address(string* val) const;
276 void do_get_full_path(string* val) const;
277
278 string host_, path_, query_;
279 uint16_t port_;
280 bool secure_;
281};
282
283//////////////////////////////////////////////////////////////////////
284// HttpData
285//////////////////////////////////////////////////////////////////////
286
287struct HttpData {
288 typedef std::multimap<std::string, std::string, iless> HeaderMap;
289 typedef HeaderMap::const_iterator const_iterator;
290 typedef HeaderMap::iterator iterator;
291
292 HttpVersion version;
293 std::unique_ptr<StreamInterface> document;
294
295 HttpData();
296
297 enum HeaderCombine { HC_YES, HC_NO, HC_AUTO, HC_REPLACE, HC_NEW };
298 void changeHeader(const std::string& name, const std::string& value,
299 HeaderCombine combine);
300 inline void addHeader(const std::string& name, const std::string& value,
301 bool append = true) {
302 changeHeader(name, value, append ? HC_AUTO : HC_NO);
303 }
304 inline void setHeader(const std::string& name, const std::string& value,
305 bool overwrite = true) {
306 changeHeader(name, value, overwrite ? HC_REPLACE : HC_NEW);
307 }
308 // Returns count of erased headers
309 size_t clearHeader(const std::string& name);
310 // Returns iterator to next header
311 iterator clearHeader(iterator header);
312
313 // keep in mind, this may not do what you want in the face of multiple headers
314 bool hasHeader(const std::string& name, std::string* value) const;
315
316 inline const_iterator begin() const {
317 return headers_.begin();
318 }
319 inline const_iterator end() const {
320 return headers_.end();
321 }
322 inline iterator begin() {
323 return headers_.begin();
324 }
325 inline iterator end() {
326 return headers_.end();
327 }
328 inline const_iterator begin(const std::string& name) const {
329 return headers_.lower_bound(name);
330 }
331 inline const_iterator end(const std::string& name) const {
332 return headers_.upper_bound(name);
333 }
334 inline iterator begin(const std::string& name) {
335 return headers_.lower_bound(name);
336 }
337 inline iterator end(const std::string& name) {
338 return headers_.upper_bound(name);
339 }
340
341 // Convenience methods using HttpHeader
342 inline void changeHeader(HttpHeader header, const std::string& value,
343 HeaderCombine combine) {
344 changeHeader(ToString(header), value, combine);
345 }
346 inline void addHeader(HttpHeader header, const std::string& value,
347 bool append = true) {
348 addHeader(ToString(header), value, append);
349 }
350 inline void setHeader(HttpHeader header, const std::string& value,
351 bool overwrite = true) {
352 setHeader(ToString(header), value, overwrite);
353 }
354 inline void clearHeader(HttpHeader header) {
355 clearHeader(ToString(header));
356 }
357 inline bool hasHeader(HttpHeader header, std::string* value) const {
358 return hasHeader(ToString(header), value);
359 }
360 inline const_iterator begin(HttpHeader header) const {
361 return headers_.lower_bound(ToString(header));
362 }
363 inline const_iterator end(HttpHeader header) const {
364 return headers_.upper_bound(ToString(header));
365 }
366 inline iterator begin(HttpHeader header) {
367 return headers_.lower_bound(ToString(header));
368 }
369 inline iterator end(HttpHeader header) {
370 return headers_.upper_bound(ToString(header));
371 }
372
373 void setContent(const std::string& content_type, StreamInterface* document);
374 void setDocumentAndLength(StreamInterface* document);
375
376 virtual size_t formatLeader(char* buffer, size_t size) const = 0;
377 virtual HttpError parseLeader(const char* line, size_t len) = 0;
378
379protected:
380 virtual ~HttpData();
381 void clear(bool release_document);
382 void copy(const HttpData& src);
383
384private:
385 HeaderMap headers_;
386};
387
388struct HttpRequestData : public HttpData {
389 HttpVerb verb;
390 std::string path;
391
392 HttpRequestData() : verb(HV_GET) { }
393
394 void clear(bool release_document);
395 void copy(const HttpRequestData& src);
396
397 size_t formatLeader(char* buffer, size_t size) const override;
398 HttpError parseLeader(const char* line, size_t len) override;
399
400 bool getAbsoluteUri(std::string* uri) const;
401 bool getRelativeUri(std::string* host, std::string* path) const;
402};
403
404struct HttpResponseData : public HttpData {
405 uint32_t scode;
406 std::string message;
407
408 HttpResponseData() : scode(HC_INTERNAL_SERVER_ERROR) { }
409 void clear(bool release_document);
410 void copy(const HttpResponseData& src);
411
412 // Convenience methods
413 void set_success(uint32_t scode = HC_OK);
414 void set_success(const std::string& content_type,
415 StreamInterface* document,
416 uint32_t scode = HC_OK);
417 void set_redirect(const std::string& location,
418 uint32_t scode = HC_MOVED_TEMPORARILY);
419 void set_error(uint32_t scode);
420
421 size_t formatLeader(char* buffer, size_t size) const override;
422 HttpError parseLeader(const char* line, size_t len) override;
423};
424
425struct HttpTransaction {
426 HttpRequestData request;
427 HttpResponseData response;
428};
429
430//////////////////////////////////////////////////////////////////////
431// Http Authentication
432//////////////////////////////////////////////////////////////////////
433
434struct HttpAuthContext {
435 std::string auth_method;
436 HttpAuthContext(const std::string& auth) : auth_method(auth) { }
437 virtual ~HttpAuthContext() { }
438};
439
440enum HttpAuthResult { HAR_RESPONSE, HAR_IGNORE, HAR_CREDENTIALS, HAR_ERROR };
441
442// 'context' is used by this function to record information between calls.
443// Start by passing a null pointer, then pass the same pointer each additional
444// call. When the authentication attempt is finished, delete the context.
445HttpAuthResult HttpAuthenticate(
446 const char * challenge, size_t len,
447 const SocketAddress& server,
448 const std::string& method, const std::string& uri,
449 const std::string& username, const CryptString& password,
450 HttpAuthContext *& context, std::string& response, std::string& auth_method);
451
452//////////////////////////////////////////////////////////////////////
453
454} // namespace rtc
455
Mirko Bonadei92ea95e2017-09-15 04:47:31456#endif // RTC_BASE_HTTPCOMMON_H_