PageRenderTime 3249ms CodeModel.GetById 2813ms RepoModel.GetById 0ms app.codeStats 0ms

/mordor/http/http.h

http://github.com/mozy/mordor
C Header | 535 lines | 420 code | 79 blank | 36 comment | 39 complexity | e2c95befba66ac5eddd990a635800ec7 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #ifndef __MORDOR_HTTP_H__
  2. #define __MORDOR_HTTP_H__
  3. // Copyright (c) 2009 - Mozy, Inc.
  4. #include <map>
  5. #include <set>
  6. #include <stdexcept>
  7. #include <vector>
  8. #include <boost/variant.hpp>
  9. #include <boost/date_time.hpp>
  10. #include "mordor/predef.h"
  11. #include "mordor/string.h"
  12. #include "mordor/uri.h"
  13. #include "mordor/version.h"
  14. namespace Mordor {
  15. namespace HTTP {
  16. struct Exception : virtual Mordor::Exception {};
  17. struct IncompleteMessageHeaderException : virtual Exception, virtual StreamException {};
  18. // Unparseable
  19. struct BadMessageHeaderException : virtual Exception, StreamException {};
  20. struct PriorRequestFailedException : virtual Exception {};
  21. struct ConnectionVoluntarilyClosedException : virtual PriorRequestFailedException {};
  22. // Logically doesn't make sense
  23. struct InvalidMessageHeaderException : virtual Exception, virtual StreamException {
  24. public:
  25. InvalidMessageHeaderException() {}
  26. InvalidMessageHeaderException(const std::string &message)
  27. : m_message(message) {}
  28. ~InvalidMessageHeaderException() throw() {}
  29. const char *what() const throw() { return m_message.c_str(); }
  30. private:
  31. std::string m_message;
  32. };
  33. struct InvalidTransferEncodingException : virtual InvalidMessageHeaderException
  34. {
  35. public:
  36. InvalidTransferEncodingException(const std::string &message)
  37. : InvalidMessageHeaderException(message)
  38. {}
  39. };
  40. extern const std::string GET;
  41. extern const std::string HEAD;
  42. extern const std::string POST;
  43. extern const std::string PUT;
  44. extern const std::string DELETE;
  45. extern const std::string CONNECT;
  46. extern const std::string OPTIONS;
  47. extern const std::string TRACE;
  48. enum Status
  49. {
  50. INVALID = 0,
  51. CONTINUE = 100,
  52. SWITCHING_PROTOCOL = 101,
  53. OK = 200,
  54. CREATED = 201,
  55. ACCEPTED = 202,
  56. NON_AUTHORITATIVE_INFORMATION = 203,
  57. NO_CONTENT = 204,
  58. RESET_CONTENT = 205,
  59. PARTIAL_CONTENT = 206,
  60. MULTIPLE_CHOICES = 300,
  61. MOVED_PERMANENTLY = 301,
  62. FOUND = 302,
  63. SEE_OTHER = 303,
  64. NOT_MODIFIED = 304,
  65. USE_PROXY = 305,
  66. // UNUSED = 306,
  67. TEMPORARY_REDIRECT = 307,
  68. BAD_REQUEST = 400,
  69. UNAUTHORIZED = 401,
  70. PAYMENT_REQUIRED = 402,
  71. FORBIDDEN = 403,
  72. NOT_FOUND = 404,
  73. METHOD_NOT_ALLOWED = 405,
  74. NOT_ACCEPTABLE = 406,
  75. PROXY_AUTHENTICATION_REQUIRED = 407,
  76. REQUEST_TIMEOUT = 408,
  77. CONFLICT = 409,
  78. GONE = 410,
  79. LENGTH_REQUIRED = 411,
  80. PRECONDITION_FAILED = 412,
  81. REQUEST_ENTITY_TOO_LARGE = 413,
  82. REQUEST_URI_TOO_LONG = 414,
  83. UNSUPPORTED_MEDIA_TYPE = 415,
  84. REQUESTED_RANGE_NOT_SATISFIABLE = 416,
  85. EXPECTATION_FAILED = 417,
  86. PRECONDITION_REQUIRED = 428,
  87. INTERNAL_SERVER_ERROR = 500,
  88. NOT_IMPLEMENTED = 501,
  89. BAD_GATEWAY = 502,
  90. SERVICE_UNAVAILABLE = 503,
  91. GATEWAY_TIMEOUT = 504,
  92. HTTP_VERSION_NOT_SUPPORTED = 505
  93. };
  94. const char *reason(Status s);
  95. class Redirect : public HTTP::Exception
  96. {
  97. public:
  98. Redirect(Status status, const URI &uri)
  99. : m_status(status), m_uri(uri)
  100. {}
  101. ~Redirect() throw() {}
  102. Status status() const { return m_status; }
  103. const URI &uri() const { return m_uri; }
  104. private:
  105. Status m_status;
  106. URI m_uri;
  107. };
  108. std::string quote(const std::string &str, bool alwaysQuote = false, bool comment = false);
  109. std::string unquote(const char *str, size_t size);
  110. std::string unquote(const std::string &str);
  111. boost::posix_time::ptime parseHttpDate(const char *str, size_t size);
  112. // Mordor uses the following datastrutures to represent the standard contents
  113. // of HTTP headers in a C++-friendly fashion. These are used to build and
  114. // parse HTTP requests and responses.
  115. struct Version
  116. {
  117. Version() : major(~0), minor(~0) {}
  118. Version(unsigned char m, unsigned char n) : major(m), minor(n) {}
  119. unsigned char major;
  120. unsigned char minor;
  121. bool operator==(const Version& rhs) const
  122. {
  123. return major == rhs.major && minor == rhs.minor;
  124. }
  125. bool operator!=(const Version& rhs) const
  126. {
  127. return !(*this == rhs);
  128. }
  129. bool operator<(const Version& rhs) const
  130. {
  131. return major < rhs.major || (major == rhs.major && minor < rhs.minor);
  132. }
  133. bool operator<=(const Version& rhs) const
  134. {
  135. return !(*this > rhs);
  136. }
  137. bool operator>(const Version& rhs) const
  138. {
  139. return rhs < *this;
  140. }
  141. bool operator>=(const Version& rhs) const
  142. {
  143. return !(*this < rhs);
  144. }
  145. };
  146. struct ETag
  147. {
  148. ETag()
  149. : weak(false), unspecified(true)
  150. {}
  151. ETag(const std::string &v, bool w = false)
  152. : weak(w), unspecified(false), value(v)
  153. {}
  154. bool weak, unspecified;
  155. std::string value;
  156. bool operator< (const ETag &rhs) const
  157. {
  158. if (unspecified && !rhs.unspecified)
  159. return true;
  160. if (!unspecified && rhs.unspecified)
  161. return false;
  162. if (weak && !rhs.weak)
  163. return false;
  164. if (!weak && rhs.weak)
  165. return true;
  166. return value < rhs.value;
  167. }
  168. /// Compare two Entity Tags according to the weak comparison function
  169. ///
  170. /// @return if *this and rhs have the same value, ignoring weakness
  171. bool weakCompare(const ETag &rhs) const
  172. {
  173. return unspecified == rhs.unspecified && value == rhs.value;
  174. }
  175. /// Compare two Entity Tags according to the strong comparison function
  176. ///
  177. /// @return if *this and rhs are both strong, and have the same value
  178. bool strongCompare(const ETag &rhs) const
  179. {
  180. return !weak && !rhs.weak && unspecified == rhs.unspecified &&
  181. value == rhs.value;
  182. }
  183. /// Compare two Entity Tags for exact equality
  184. ///
  185. /// @return if *this and rhs are identical (weakness and value)
  186. bool operator== (const ETag &rhs) const
  187. {
  188. return weak == rhs.weak && unspecified == rhs.unspecified &&
  189. value == rhs.value;
  190. }
  191. bool operator!= (const ETag &rhs) const
  192. {
  193. return weak != rhs.weak || unspecified != rhs.unspecified ||
  194. value != rhs.value;
  195. }
  196. };
  197. struct Product
  198. {
  199. Product() {}
  200. Product(const std::string &_product, const std::string &_version)
  201. : product(_product), version(_version)
  202. {}
  203. Product(const char *_product, const char *_version)
  204. : product(_product), version(_version)
  205. {}
  206. std::string product;
  207. std::string version;
  208. };
  209. typedef std::vector<Product> ProductList;
  210. typedef std::vector<boost::variant<Product, std::string> > ProductAndCommentList;
  211. typedef std::set<std::string, caseinsensitiveless> StringSet;
  212. typedef std::map<std::string, std::string, caseinsensitiveless> StringMap;
  213. struct ValueWithParameters
  214. {
  215. ValueWithParameters()
  216. {}
  217. ValueWithParameters(const char *val) : value(val)
  218. {}
  219. ValueWithParameters(const std::string &val) : value(val)
  220. {}
  221. std::string value;
  222. StringMap parameters;
  223. };
  224. typedef std::vector<ValueWithParameters> ParameterizedList;
  225. struct AuthParams
  226. {
  227. AuthParams(const std::string &_scheme = std::string(),
  228. const std::string &_param = std::string())
  229. : scheme(_scheme),
  230. param(_param)
  231. {}
  232. std::string scheme;
  233. /// non-list parameters
  234. std::string param;
  235. /// key=value pair list parameters
  236. StringMap parameters;
  237. };
  238. typedef std::vector<AuthParams> ChallengeList;
  239. struct KeyValueWithParameters
  240. {
  241. KeyValueWithParameters()
  242. {}
  243. KeyValueWithParameters(const std::string &_key,
  244. const std::string &_value)
  245. : key(_key), value(_value)
  246. {}
  247. KeyValueWithParameters(const char *_key)
  248. : key(_key)
  249. {}
  250. KeyValueWithParameters(const char *_key,
  251. const char *_value)
  252. : key(_key), value(_value)
  253. {}
  254. std::string key;
  255. std::string value;
  256. StringMap parameters;
  257. };
  258. typedef std::vector<KeyValueWithParameters> ParameterizedKeyValueList;
  259. struct MediaType
  260. {
  261. MediaType() {}
  262. MediaType(const std::string &type_, const std::string &subtype_)
  263. : type(type_), subtype(subtype_)
  264. {}
  265. std::string type;
  266. std::string subtype;
  267. StringMap parameters;
  268. };
  269. typedef std::vector<std::pair<unsigned long long, unsigned long long> > RangeSet;
  270. struct ContentRange
  271. {
  272. ContentRange(unsigned long long first_ = ~0ull,
  273. unsigned long long last_ = ~0ull,
  274. unsigned long long instance_ = ~0ull)
  275. : first(first_),
  276. last(last_),
  277. instance(instance_)
  278. {}
  279. unsigned long long first;
  280. /// @note If first == ~0ull, then last is ignored for comparison, and only
  281. /// useful for forcing a serialization of "bytes */*"
  282. unsigned long long last;
  283. unsigned long long instance;
  284. bool operator==(const ContentRange &rhs) const
  285. {
  286. return first == rhs.first && (first == ~0ull || last == rhs.last) &&
  287. instance == rhs.instance;
  288. }
  289. bool operator!=(const ContentRange &rhs) const
  290. {
  291. return !(*this == rhs);
  292. }
  293. };
  294. struct AcceptValue
  295. {
  296. AcceptValue() : qvalue(~0u) {}
  297. AcceptValue(const char *v, unsigned int q = ~0u)
  298. : value(v), qvalue(q)
  299. {}
  300. AcceptValue(const std::string &v, unsigned int q = ~0u)
  301. : value(v), qvalue(q)
  302. {}
  303. std::string value;
  304. unsigned int qvalue;
  305. bool operator== (const AcceptValue &rhs) const;
  306. bool operator!= (const AcceptValue &rhs) const { return !(*this == rhs); }
  307. };
  308. typedef std::vector<AcceptValue> AcceptList;
  309. struct AcceptValueWithParameters
  310. {
  311. AcceptValueWithParameters() : qvalue(~0u) {}
  312. AcceptValueWithParameters(const char *v, unsigned int q = ~0u)
  313. : value(v), qvalue(q)
  314. {}
  315. AcceptValueWithParameters(const std::string &v, unsigned int q = ~0u)
  316. : value(v), qvalue(q)
  317. {}
  318. std::string value;
  319. StringMap parameters;
  320. unsigned int qvalue;
  321. StringMap acceptParams;
  322. bool operator== (const AcceptValueWithParameters &rhs) const;
  323. bool operator!= (const AcceptValueWithParameters &rhs) const
  324. { return !(*this == rhs); }
  325. };
  326. typedef std::vector<AcceptValueWithParameters> AcceptListWithParameters;
  327. // First line of a HTTP Request, e.g. "GET /events/1196798 HTTP/1.1"
  328. struct RequestLine
  329. {
  330. RequestLine() : method(GET) {}
  331. std::string method;
  332. URI uri;
  333. Version ver;
  334. };
  335. // First line of an HTTP Response, e.g. "HTTP/1.1 200 OK"
  336. struct StatusLine
  337. {
  338. StatusLine() : status(OK) {}
  339. Status status;
  340. std::string reason;
  341. Version ver;
  342. };
  343. // Each member of the following structures contains the parsed value
  344. // of a standard HTTP header of approximately the same name.
  345. // e.g. GeneralHeaders::connection contains the "Connection" header
  346. // and RequestHeaders::acceptCharset contains the "Accept-Charset" header
  347. // (see http://en.wikipedia.org/wiki/List_of_HTTP_header_fields)
  348. struct GeneralHeaders
  349. {
  350. StringSet connection;
  351. boost::posix_time::ptime date;
  352. StringSet proxyConnection; // NON-STANDARD!!!!
  353. ParameterizedList transferEncoding;
  354. StringSet trailer;
  355. ProductList upgrade;
  356. };
  357. struct RequestHeaders
  358. {
  359. AcceptList acceptCharset;
  360. AcceptList acceptEncoding;
  361. AuthParams authorization;
  362. ParameterizedKeyValueList expect;
  363. std::string host;
  364. std::set<ETag> ifMatch;
  365. boost::posix_time::ptime ifModifiedSince;
  366. std::set<ETag> ifNoneMatch;
  367. boost::variant<ETag, boost::posix_time::ptime> ifRange;
  368. boost::posix_time::ptime ifUnmodifiedSince;
  369. AuthParams proxyAuthorization;
  370. RangeSet range;
  371. URI referer;
  372. AcceptListWithParameters te;
  373. ProductAndCommentList userAgent;
  374. };
  375. struct ResponseHeaders
  376. {
  377. StringSet acceptRanges;
  378. ETag eTag;
  379. URI location;
  380. ChallengeList proxyAuthenticate;
  381. boost::variant<boost::posix_time::ptime, unsigned long long> retryAfter;
  382. ProductAndCommentList server;
  383. ChallengeList wwwAuthenticate;
  384. };
  385. struct EntityHeaders
  386. {
  387. EntityHeaders() : contentLength(~0ull) {}
  388. std::vector<std::string> allow; // "Allow"
  389. std::vector<std::string> contentEncoding; // "Content-Encoding"
  390. unsigned long long contentLength; // "Content-Length"
  391. std::string contentMD5; // "Content-MD5"
  392. ContentRange contentRange; // "Content-Range"
  393. MediaType contentType; // "Content-Type"
  394. boost::posix_time::ptime expires; // "Expires"
  395. boost::posix_time::ptime lastModified; // "Last-Modified"
  396. // All non-standard headers are stored in this map.
  397. // Typically these headers use the naming convention "X-...",
  398. // for example "X-Meta", "X-ObjectID" but that is not manditory.
  399. // This is also the structure to set any Cookie
  400. StringMap extension;
  401. };
  402. struct Request
  403. {
  404. RequestLine requestLine;
  405. GeneralHeaders general;
  406. RequestHeaders request;
  407. EntityHeaders entity;
  408. };
  409. struct Response
  410. {
  411. StatusLine status;
  412. GeneralHeaders general;
  413. ResponseHeaders response;
  414. EntityHeaders entity;
  415. };
  416. bool isAcceptable(const ChallengeList &list, const std::string &scheme);
  417. const AuthParams &challengeForSchemeAndRealm(const ChallengeList &list,
  418. const std::string &scheme, const std::string &realm = std::string());
  419. bool isAcceptable(const AcceptListWithParameters &list, const AcceptValueWithParameters &value, bool defaultMissing = false);
  420. // @note the available MUST be sorted in descending order before sending to this function
  421. const AcceptValueWithParameters *preferred(const AcceptListWithParameters &accept, const AcceptListWithParameters &available);
  422. bool isAcceptable(const AcceptList &list, const AcceptValue &value, bool defaultMissing = false);
  423. // @note the available MUST be sorted in descending order before sending to this function
  424. const AcceptValue *preferred(const AcceptList &accept, const AcceptList &available);
  425. std::ostream& operator<<(std::ostream& os, Status s);
  426. std::ostream& operator<<(std::ostream& os, Version v);
  427. std::ostream& operator<<(std::ostream& os, const ETag &e);
  428. std::ostream& operator<<(std::ostream& os, const std::set<ETag> &v);
  429. std::ostream& operator<<(std::ostream& os, const Product &p);
  430. std::ostream& operator<<(std::ostream& os, const ProductList &l);
  431. std::ostream& operator<<(std::ostream& os, const ProductAndCommentList &l);
  432. std::ostream& operator<<(std::ostream& os, const ValueWithParameters &v);
  433. std::ostream& operator<<(std::ostream& os, const ParameterizedList &l);
  434. std::ostream& operator<<(std::ostream& os, const AuthParams &v);
  435. std::ostream& operator<<(std::ostream& os, const ChallengeList &l);
  436. std::ostream& operator<<(std::ostream& os, const KeyValueWithParameters &v);
  437. std::ostream& operator<<(std::ostream& os, const ParameterizedKeyValueList &v);
  438. std::ostream& operator<<(std::ostream& os, const MediaType &m);
  439. std::ostream& operator<<(std::ostream& os, const ContentRange &m);
  440. std::ostream& operator<<(std::ostream& os, const AcceptValue &v);
  441. std::ostream& operator<<(std::ostream& os, const AcceptList &l);
  442. std::ostream& operator<<(std::ostream& os, const AcceptValueWithParameters &v);
  443. std::ostream& operator<<(std::ostream& os, const AcceptListWithParameters &l);
  444. std::ostream& operator<<(std::ostream& os, const RequestLine &r);
  445. std::ostream& operator<<(std::ostream& os, const StatusLine &s);
  446. std::ostream& operator<<(std::ostream& os, const GeneralHeaders &g);
  447. std::ostream& operator<<(std::ostream& os, const RequestHeaders &r);
  448. std::ostream& operator<<(std::ostream& os, const ResponseHeaders &r);
  449. std::ostream& operator<<(std::ostream& os, const EntityHeaders &e);
  450. // These operators are used to convert the Request and Response
  451. // structures, as filled in by a Client or Server, into the real
  452. // HTTP string format that is sent "over the wire"
  453. std::ostream& operator<<(std::ostream& os, const Request &r);
  454. std::ostream& operator<<(std::ostream& os, const Response &r);
  455. }}
  456. #endif