PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/mordor/http/http.cpp

http://github.com/mozy/mordor
C++ | 810 lines | 790 code | 10 blank | 10 comment | 18 complexity | 3a0dd796675576cc3f8b692c2f5c391b MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "http.h"
  3. #include <boost/bind.hpp>
  4. #include <algorithm>
  5. #include <iostream>
  6. #include "mordor/assert.h"
  7. namespace Mordor {
  8. namespace HTTP {
  9. static boost::posix_time::time_facet rfc1123Facet_out("%a, %d %b %Y %H:%M:%S GMT",
  10. boost::posix_time::time_facet::period_formatter_type(),
  11. boost::posix_time::time_facet::special_values_formatter_type(),
  12. boost::posix_time::time_facet::date_gen_formatter_type(),
  13. 1 /* starting refcount, so this never gets deleted */);
  14. std::string
  15. quote(const std::string &str, bool alwaysQuote, bool comment)
  16. {
  17. if (comment)
  18. alwaysQuote = true;
  19. if (str.empty())
  20. return comment ? "()" : "\"\"";
  21. if (!alwaysQuote && str.find_first_not_of("!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~") == std::string::npos) {
  22. return str;
  23. }
  24. std::string result;
  25. result.reserve(str.length() + 2);
  26. result.append(1, comment ? '(' : '"');
  27. // qdtext = OCTET - CTL - '"' - '\\' | LWS
  28. // CR, LF, and HT are part of LWS, and are allowed
  29. // DEL is a CTL, and is not allowed
  30. // \ is the escape character, and must be escaped itself
  31. // " indicates end-of-string, and must be escaped
  32. static const char * escapedQuote =
  33. "\0\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f"
  34. "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
  35. "\x7f\\\"";
  36. static const char * escapedComment =
  37. "\0\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f"
  38. "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
  39. "\x7f\\()";
  40. const char *escaped = comment ? escapedComment : escapedQuote;
  41. size_t escapedCount = comment ? 33 : 32;
  42. size_t leftParens = 0, rightParens = 0;
  43. if (comment) {
  44. rightParens = std::count(str.begin(), str.end(), ')');
  45. }
  46. size_t lastEscape = 0;
  47. size_t nextEscape = str.find_first_of(escaped, 0, escapedCount);
  48. while (nextEscape != std::string::npos) {
  49. if (str[nextEscape] == '(' && rightParens > 0) {
  50. // Let this one through without quoting (there is at least one
  51. // more matching right paren coming up)
  52. ++leftParens;
  53. --rightParens;
  54. result.append(str.substr(lastEscape, nextEscape - lastEscape + 1));
  55. } else if (str[nextEscape] == ')' && leftParens > 0) {
  56. // Let this one through without quoting (it matches a previous
  57. // left paren)
  58. --leftParens;
  59. result.append(str.substr(lastEscape, nextEscape - lastEscape + 1));
  60. } else {
  61. // Unmatching right parens
  62. if (str[nextEscape] == ')') {
  63. MORDOR_ASSERT(rightParens > 0);
  64. --rightParens;
  65. }
  66. result.append(str.substr(lastEscape, nextEscape - lastEscape));
  67. result.append(1, '\\');
  68. result.append(1, str[nextEscape]);
  69. }
  70. lastEscape = nextEscape + 1;
  71. nextEscape = str.find_first_of(escaped, lastEscape, escapedCount);
  72. }
  73. result.append(str.substr(lastEscape));
  74. result.append(1, comment ? ')' : '"');
  75. return result;
  76. }
  77. static std::ostream& operator<<(std::ostream& os, const StringSet& set)
  78. {
  79. for (StringSet::const_iterator it(set.begin());
  80. it != set.end();
  81. ++it) {
  82. if (it != set.begin())
  83. os << ", ";
  84. os << *it;
  85. }
  86. return os;
  87. }
  88. static std::ostream& operator<<(std::ostream& os, const std::vector<std::string>& list)
  89. {
  90. for (std::vector<std::string>::const_iterator it(list.begin());
  91. it != list.end();
  92. ++it) {
  93. if (it != list.begin())
  94. os << ", ";
  95. os << *it;
  96. }
  97. return os;
  98. }
  99. static std::ostream& operator<<(std::ostream& os, const RangeSet& set)
  100. {
  101. MORDOR_ASSERT(!set.empty());
  102. os << "bytes=";
  103. for (RangeSet::const_iterator it(set.begin());
  104. it != set.end();
  105. ++it) {
  106. if (it != set.begin())
  107. os << ", ";
  108. if (it->first != ~0ull)
  109. os << it->first;
  110. os << "-";
  111. if (it->second != ~0ull)
  112. os << it->second;
  113. }
  114. return os;
  115. }
  116. struct serializeStringMapWithRequiredValue
  117. {
  118. serializeStringMapWithRequiredValue(const StringMap &m,
  119. const char *delim = ";", bool leadingDelimiter = true)
  120. : map(m),
  121. delimiter(delim),
  122. lead(leadingDelimiter)
  123. {}
  124. const StringMap& map;
  125. const char *delimiter;
  126. bool lead;
  127. };
  128. struct serializeStringMapWithOptionalValue
  129. {
  130. serializeStringMapWithOptionalValue(const StringMap &m) : map(m) {}
  131. const StringMap& map;
  132. };
  133. static std::ostream& operator<<(std::ostream& os, const serializeStringMapWithRequiredValue &map)
  134. {
  135. for (StringMap::const_iterator it(map.map.begin());
  136. it != map.map.end();
  137. ++it) {
  138. if (map.lead || it != map.map.begin())
  139. os << map.delimiter;
  140. os << it->first << "=" << quote(it->second);
  141. }
  142. return os;
  143. }
  144. static std::ostream& operator<<(std::ostream& os, const serializeStringMapWithOptionalValue &map)
  145. {
  146. for (StringMap::const_iterator it(map.map.begin());
  147. it != map.map.end();
  148. ++it) {
  149. os << ";" << it->first;
  150. if (!it->second.empty())
  151. os << "=" << quote(it->second);
  152. }
  153. return os;
  154. }
  155. const std::string GET("GET");
  156. const std::string HEAD("HEAD");
  157. const std::string POST("POST");
  158. const std::string PUT("PUT");
  159. const std::string DELETE("DELETE");
  160. const std::string CONNECT("CONNECT");
  161. const std::string OPTIONS("OPTIONS");
  162. const std::string TRACE("TRACE");
  163. const char *reason(Status s)
  164. {
  165. switch (s) {
  166. case CONTINUE:
  167. return "Continue";
  168. case SWITCHING_PROTOCOL:
  169. return "Switching Protocols";
  170. case OK:
  171. return "OK";
  172. case CREATED:
  173. return "Created";
  174. case ACCEPTED:
  175. return "Accepted";
  176. case NON_AUTHORITATIVE_INFORMATION:
  177. return "Non-Authoritative Information";
  178. case NO_CONTENT:
  179. return "No Content";
  180. case RESET_CONTENT:
  181. return "Reset Content";
  182. case PARTIAL_CONTENT:
  183. return "Partial Content";
  184. case MULTIPLE_CHOICES:
  185. return "Multiple Choices";
  186. case MOVED_PERMANENTLY:
  187. return "Moved Permanently";
  188. case FOUND:
  189. return "Found";
  190. case SEE_OTHER:
  191. return "See Other";
  192. case NOT_MODIFIED:
  193. return "Not Modified";
  194. case USE_PROXY:
  195. return "Use Proxy";
  196. case TEMPORARY_REDIRECT:
  197. return "Temporary Redirect";
  198. case BAD_REQUEST:
  199. return "Bad Request";
  200. case UNAUTHORIZED:
  201. return "Unauthorized";
  202. case PAYMENT_REQUIRED:
  203. return "Payment Required";
  204. case FORBIDDEN:
  205. return "Forbidden";
  206. case NOT_FOUND:
  207. return "Not Found";
  208. case METHOD_NOT_ALLOWED:
  209. return "Method Not Allowed";
  210. case NOT_ACCEPTABLE:
  211. return "Not Acceptable";
  212. case PROXY_AUTHENTICATION_REQUIRED:
  213. return "Proxy Authentication Required";
  214. case REQUEST_TIMEOUT:
  215. return "Request Time-out";
  216. case CONFLICT:
  217. return "Conflict";
  218. case GONE:
  219. return "Gone";
  220. case LENGTH_REQUIRED:
  221. return "Length Required";
  222. case PRECONDITION_FAILED:
  223. return "Precondition Failed";
  224. case REQUEST_ENTITY_TOO_LARGE:
  225. return "Request Entity Too Large";
  226. case REQUEST_URI_TOO_LONG:
  227. return "Request-URI Too Long";
  228. case UNSUPPORTED_MEDIA_TYPE:
  229. return "Unsupported Media Type";
  230. case REQUESTED_RANGE_NOT_SATISFIABLE:
  231. return "Requested range not satisfiable";
  232. case EXPECTATION_FAILED:
  233. return "Expectation Failed";
  234. case INTERNAL_SERVER_ERROR:
  235. return "Internal Server Error";
  236. case NOT_IMPLEMENTED:
  237. return "Not Implemented";
  238. case BAD_GATEWAY:
  239. return "Bad Gateway";
  240. case SERVICE_UNAVAILABLE:
  241. return "Service Unavailable";
  242. case GATEWAY_TIMEOUT:
  243. return "Gateway Time-out";
  244. case HTTP_VERSION_NOT_SUPPORTED:
  245. return "HTTP Version not supported";
  246. default:
  247. return "<INVALID>";
  248. }
  249. }
  250. bool
  251. AcceptValue::operator ==(const AcceptValue &rhs) const
  252. {
  253. return stricmp(value.c_str(), rhs.value.c_str()) == 0;
  254. }
  255. bool
  256. AcceptValueWithParameters::operator ==(const AcceptValueWithParameters &rhs) const
  257. {
  258. return stricmp(value.c_str(), rhs.value.c_str()) == 0 &&
  259. parameters == rhs.parameters;
  260. }
  261. bool
  262. isAcceptable(const ChallengeList &list, const std::string &scheme)
  263. {
  264. for (ChallengeList::const_iterator it = list.begin();
  265. it != list.end();
  266. ++it) {
  267. if (stricmp(it->scheme.c_str(), scheme.c_str()) == 0)
  268. return true;
  269. }
  270. return false;
  271. }
  272. const AuthParams &
  273. challengeForSchemeAndRealm(const ChallengeList &list,
  274. const std::string &scheme, const std::string &realm)
  275. {
  276. for (ChallengeList::const_iterator it = list.begin();
  277. it != list.end();
  278. ++it) {
  279. if (stricmp(it->scheme.c_str(), scheme.c_str()) == 0) {
  280. if (realm.empty())
  281. return *it;
  282. StringMap::const_iterator realmIt = it->parameters.find("realm");
  283. if (realmIt != it->parameters.end() &&
  284. stricmp(realmIt->second.c_str(), realm.c_str()) == 0)
  285. return *it;
  286. }
  287. }
  288. MORDOR_NOTREACHED();
  289. }
  290. template<class T>
  291. static bool isAcceptable(const std::vector<T> &list, const T &value, bool defaultMissing)
  292. {
  293. for (typename std::vector<T>::const_iterator it(list.begin()); it != list.end(); ++it) {
  294. if (*it == value) {
  295. return it->qvalue > 0;
  296. }
  297. }
  298. return defaultMissing;
  299. }
  300. bool
  301. isAcceptable(const AcceptListWithParameters &list, const AcceptValueWithParameters &value,
  302. bool defaultMissing)
  303. {
  304. return isAcceptable<AcceptValueWithParameters>(list, value, defaultMissing);
  305. }
  306. bool
  307. isAcceptable(const AcceptList &list, const AcceptValue &value, bool defaultMissing)
  308. {
  309. return isAcceptable<AcceptValue>(list, value, defaultMissing);
  310. }
  311. template<class T>
  312. static const T* preferred(const std::vector<T> &accept, const std::vector<T> &available)
  313. {
  314. MORDOR_ASSERT(!available.empty());
  315. #ifndef NDEBUG
  316. // Assert that the available list is ordered
  317. for (typename std::vector<T>::const_iterator it(available.begin()); it != available.end(); ++it) {
  318. MORDOR_ASSERT(it->qvalue <= 1000);
  319. typename std::vector<T>::const_iterator next(it);
  320. ++next;
  321. if (next != available.end())
  322. MORDOR_ASSERT(it->qvalue >= next->qvalue);
  323. }
  324. #endif
  325. const T* res = NULL;
  326. typename std::vector<T>::const_iterator availableIt(available.begin());
  327. while (availableIt != available.end()) {
  328. // find the highest qvalues from server's perspective
  329. typename std::vector<T>::const_iterator nextIt(availableIt);
  330. ++nextIt;
  331. while (nextIt != available.end() && nextIt->qvalue == availableIt->qvalue)
  332. ++nextIt;
  333. // find the highest qvalues from client's perspective
  334. for (; availableIt != nextIt; ++availableIt) {
  335. for (typename std::vector<T>::const_iterator it(accept.begin());
  336. it != accept.end(); ++it) {
  337. // client wants this, choose the highest one
  338. // if there are same qvalues, choose the 1st one we found
  339. if (*it == *availableIt && it->qvalue > 0) {
  340. // qvalue takes ~0u by default, which is equivalent to 1000
  341. if (!res || (std::min)(it->qvalue, 1000u) > (std::min)(res->qvalue, 1000u))
  342. res = &*it;
  343. break;
  344. }
  345. }
  346. }
  347. if (res) break;
  348. }
  349. return res;
  350. }
  351. const AcceptValueWithParameters *
  352. preferred(const AcceptListWithParameters &accept, const AcceptListWithParameters &available)
  353. {
  354. return preferred<AcceptValueWithParameters>(accept, available);
  355. }
  356. const AcceptValue *
  357. preferred(const AcceptList &accept, const AcceptList &available)
  358. {
  359. return preferred<AcceptValue>(accept, available);
  360. }
  361. std::ostream& operator<<(std::ostream& os, Status s)
  362. {
  363. return os << (int)s;
  364. }
  365. std::ostream& operator<<(std::ostream& os, Version v)
  366. {
  367. if (v.major == (unsigned char)~0 || v.minor == (unsigned char)~0)
  368. return os << "HTTP/0.0";
  369. return os << "HTTP/" << (int)v.major << "." << (int)v.minor;
  370. }
  371. std::ostream& operator<<(std::ostream& os, const ETag &e)
  372. {
  373. if (e.unspecified)
  374. return os << "*";
  375. if (e.weak)
  376. os << "W/";
  377. return os << quote(e.value, true);
  378. }
  379. std::ostream& operator<<(std::ostream& os, const std::set<ETag> &v)
  380. {
  381. MORDOR_ASSERT(!v.empty());
  382. for (std::set<ETag>::const_iterator it = v.begin();
  383. it != v.end();
  384. ++it) {
  385. if (it != v.begin())
  386. os << ", ";
  387. MORDOR_ASSERT(!it->unspecified || v.size() == 1);
  388. os << *it;
  389. }
  390. return os;
  391. }
  392. std::ostream& operator<<(std::ostream& os, const Product &p)
  393. {
  394. MORDOR_ASSERT(!p.product.empty());
  395. os << p.product;
  396. if (!p.version.empty())
  397. os << "/" << p.version;
  398. return os;
  399. }
  400. std::ostream& operator<<(std::ostream& os, const ProductList &l)
  401. {
  402. MORDOR_ASSERT(!l.empty());
  403. for (ProductList::const_iterator it = l.begin();
  404. it != l.end();
  405. ++it) {
  406. if (it != l.begin())
  407. os << ", ";
  408. os << *it;
  409. }
  410. return os;
  411. }
  412. std::ostream& operator<<(std::ostream& os, const ProductAndCommentList &l)
  413. {
  414. MORDOR_ASSERT(!l.empty());
  415. for (ProductAndCommentList::const_iterator it = l.begin();
  416. it != l.end();
  417. ++it) {
  418. if (it != l.begin())
  419. os << " ";
  420. const Product *product = boost::get<Product>(&*it);
  421. if (product)
  422. os << *product;
  423. else
  424. os << quote(boost::get<std::string>(*it), true, true);
  425. }
  426. return os;
  427. }
  428. std::ostream& operator<<(std::ostream& os, const ValueWithParameters &v)
  429. {
  430. MORDOR_ASSERT(!v.value.empty());
  431. return os << v.value << serializeStringMapWithRequiredValue(v.parameters);
  432. }
  433. std::ostream& operator<<(std::ostream& os, const ParameterizedList &l)
  434. {
  435. for (ParameterizedList::const_iterator it(l.begin());
  436. it != l.end();
  437. ++it) {
  438. if (it != l.begin())
  439. os << ", ";
  440. os << *it;
  441. }
  442. return os;
  443. }
  444. std::ostream &operator<<(std::ostream &os, const AuthParams &a)
  445. {
  446. MORDOR_ASSERT(a.param.empty() || a.parameters.empty());
  447. os << a.scheme;
  448. if (!a.param.empty())
  449. os << ' ' << a.param;
  450. if (!a.parameters.empty())
  451. os << ' ' << serializeStringMapWithRequiredValue(a.parameters, ", ", false);
  452. return os;
  453. }
  454. std::ostream &operator<<(std::ostream &os, const ChallengeList &l)
  455. {
  456. for (ChallengeList::const_iterator it(l.begin());
  457. it != l.end();
  458. ++it) {
  459. if (it != l.begin())
  460. os << ", ";
  461. os << *it;
  462. }
  463. return os;
  464. }
  465. std::ostream& operator<<(std::ostream& os, const KeyValueWithParameters &v)
  466. {
  467. MORDOR_ASSERT(!v.key.empty());
  468. os << quote(v.key);
  469. if (!v.value.empty())
  470. os << "=" << quote(v.value)
  471. << serializeStringMapWithOptionalValue(v.parameters);
  472. return os;
  473. }
  474. std::ostream& operator<<(std::ostream& os, const ParameterizedKeyValueList &l)
  475. {
  476. MORDOR_ASSERT(!l.empty());
  477. for (ParameterizedKeyValueList::const_iterator it(l.begin());
  478. it != l.end();
  479. ++it) {
  480. if (it != l.begin())
  481. os << ", ";
  482. os << *it;
  483. }
  484. return os;
  485. }
  486. std::ostream& operator<<(std::ostream& os, const MediaType &m)
  487. {
  488. MORDOR_ASSERT(!m.type.empty());
  489. MORDOR_ASSERT(!m.subtype.empty());
  490. return os << m.type << "/" << m.subtype << serializeStringMapWithRequiredValue(m.parameters);
  491. }
  492. std::ostream& operator<<(std::ostream& os, const ContentRange &cr)
  493. {
  494. os << "bytes ";
  495. if (cr.first == ~0ull) {
  496. os << '*';
  497. } else {
  498. os << cr.first << '-';
  499. if (cr.last != ~0ull)
  500. os << cr.last;
  501. }
  502. os << '/';
  503. if (cr.instance == ~0ull)
  504. os << '*';
  505. else
  506. os << cr.instance;
  507. return os;
  508. }
  509. std::ostream& operator<<(std::ostream& os, const AcceptValue &v)
  510. {
  511. if (v.value.empty())
  512. os << '*';
  513. else
  514. os << v.value;
  515. if (v.qvalue != ~0u) {
  516. MORDOR_ASSERT(v.qvalue <= 1000);
  517. unsigned int qvalue = v.qvalue;
  518. unsigned int curPlace = 100;
  519. if (qvalue == 1000) {
  520. os << ";q=1";
  521. } else {
  522. os << ";q=0";
  523. while (curPlace > 0 && qvalue > 0) {
  524. if (curPlace == 100)
  525. os << '.';
  526. unsigned int cur = qvalue / curPlace;
  527. MORDOR_ASSERT(cur < 10);
  528. os << cur;
  529. qvalue -= cur * curPlace;
  530. curPlace /= 10;
  531. }
  532. }
  533. }
  534. return os;
  535. }
  536. std::ostream& operator<<(std::ostream& os, const AcceptList &l)
  537. {
  538. MORDOR_ASSERT(!l.empty());
  539. for (AcceptList::const_iterator it(l.begin());
  540. it != l.end();
  541. ++it) {
  542. if (it != l.begin())
  543. os << ", ";
  544. os << *it;
  545. }
  546. return os;
  547. }
  548. std::ostream& operator<<(std::ostream& os, const AcceptValueWithParameters &v)
  549. {
  550. MORDOR_ASSERT(!v.value.empty());
  551. os << v.value << serializeStringMapWithRequiredValue(v.parameters);
  552. if (v.qvalue != ~0u) {
  553. MORDOR_ASSERT(v.qvalue <= 1000);
  554. unsigned int qvalue = v.qvalue;
  555. unsigned int curPlace = 100;
  556. if (qvalue == 1000) {
  557. os << ";q=1";
  558. } else {
  559. os << ";q=0";
  560. while (curPlace > 0 && qvalue > 0) {
  561. if (curPlace == 100)
  562. os << '.';
  563. unsigned int cur = qvalue / curPlace;
  564. MORDOR_ASSERT(cur < 10);
  565. os << cur;
  566. qvalue -= cur * curPlace;
  567. curPlace /= 10;
  568. }
  569. }
  570. os << serializeStringMapWithOptionalValue(v.acceptParams);
  571. } else {
  572. MORDOR_ASSERT(v.acceptParams.empty());
  573. }
  574. return os;
  575. }
  576. std::ostream& operator<<(std::ostream& os, const AcceptListWithParameters &l)
  577. {
  578. MORDOR_ASSERT(!l.empty());
  579. for (AcceptListWithParameters::const_iterator it(l.begin());
  580. it != l.end();
  581. ++it) {
  582. if (it != l.begin())
  583. os << ", ";
  584. os << *it;
  585. }
  586. return os;
  587. }
  588. std::ostream& operator<<(std::ostream& os, const RequestLine &r)
  589. {
  590. // CONNECT is special cased to only do the authority
  591. if (r.method == CONNECT) {
  592. MORDOR_ASSERT(r.uri.authority.hostDefined());
  593. MORDOR_ASSERT(!r.uri.schemeDefined());
  594. MORDOR_ASSERT(r.uri.path.isEmpty());
  595. MORDOR_ASSERT(!r.uri.queryDefined());
  596. MORDOR_ASSERT(!r.uri.fragmentDefined());
  597. return os << r.method << ' ' << r.uri.authority << ' ' << r.ver;
  598. } else {
  599. if (!r.uri.isDefined()) {
  600. return os << r.method << " * " << r.ver;
  601. } else {
  602. MORDOR_ASSERT(!r.uri.fragmentDefined());
  603. #ifndef NDEBUG
  604. // Must be a absolute_URI or a path_absolute (with query allowed)
  605. if (!r.uri.schemeDefined()) {
  606. MORDOR_ASSERT(!r.uri.authority.hostDefined());
  607. MORDOR_ASSERT(r.uri.path.isAbsolute());
  608. // The first path segment (after the leading slash)
  609. // cannot be empty (unless it is the trailing slash
  610. // as well)
  611. MORDOR_ASSERT(r.uri.path.segments.size() <= 2 ||
  612. !r.uri.path.segments[1].empty())
  613. }
  614. #endif
  615. return os << r.method << " " << r.uri << " " << r.ver;
  616. }
  617. }
  618. }
  619. std::ostream& operator<<(std::ostream& os, const StatusLine &s)
  620. {
  621. MORDOR_ASSERT(!s.reason.empty());
  622. return os << s.ver << " " << s.status << " " << s.reason;
  623. }
  624. std::ostream& operator<<(std::ostream& os, const GeneralHeaders &g)
  625. {
  626. os.imbue(std::locale(os.getloc(), &rfc1123Facet_out));
  627. if (!g.connection.empty())
  628. os << "Connection: " << g.connection << "\r\n";
  629. if (!g.date.is_not_a_date_time())
  630. os << "Date: " << g.date << "\r\n";
  631. if (!g.proxyConnection.empty())
  632. os << "Proxy-Connection: " << g.proxyConnection << "\r\n";
  633. if (!g.trailer.empty())
  634. os << "Trailer: " << g.trailer << "\r\n";
  635. if (!g.transferEncoding.empty())
  636. os << "Transfer-Encoding: " << g.transferEncoding << "\r\n";
  637. if (!g.upgrade.empty())
  638. os << "Upgrade: " << g.upgrade << "\r\n";
  639. return os;
  640. }
  641. std::ostream& operator<<(std::ostream& os, const RequestHeaders &r)
  642. {
  643. os.imbue(std::locale(os.getloc(), &rfc1123Facet_out));
  644. if (!r.acceptCharset.empty())
  645. os << "Accept-Charset: " << r.acceptCharset << "\r\n";
  646. if (!r.acceptEncoding.empty())
  647. os << "Accept-Encoding: " << r.acceptEncoding << "\r\n";
  648. if (!r.authorization.scheme.empty())
  649. os << "Authorization: " << r.authorization << "\r\n";
  650. if (!r.expect.empty())
  651. os << "Expect: " << r.expect << "\r\n";
  652. if (!r.host.empty())
  653. os << "Host: " << r.host << "\r\n";
  654. if (!r.ifMatch.empty())
  655. os << "If-Match: " << r.ifMatch << "\r\n";
  656. if (!r.ifModifiedSince.is_not_a_date_time())
  657. os << "If-Modified-Since: " << r.ifModifiedSince << "\r\n";
  658. if (!r.ifNoneMatch.empty())
  659. os << "If-None-Match: " << r.ifNoneMatch << "\r\n";
  660. const ETag *ifRangeEtag = boost::get<ETag>(&r.ifRange);
  661. if (ifRangeEtag && !ifRangeEtag->unspecified)
  662. os << "If-Range: " << *ifRangeEtag << "\r\n";
  663. const boost::posix_time::ptime *ifRangeHttpDate = boost::get<boost::posix_time::ptime>(&r.ifRange);
  664. if (ifRangeHttpDate && !ifRangeHttpDate->is_not_a_date_time())
  665. os << "If-Range: " << *ifRangeHttpDate << "\r\n";
  666. if (!r.ifUnmodifiedSince.is_not_a_date_time())
  667. os << "If-Unmodified-Since: " << r.ifUnmodifiedSince << "\r\n";
  668. if (!r.proxyAuthorization.scheme.empty())
  669. os << "Proxy-Authorization: " << r.proxyAuthorization << "\r\n";
  670. if (!r.range.empty())
  671. os << "Range: " << r.range << "\r\n";
  672. if (r.referer.isDefined())
  673. os << "Referer: " << r.referer << "\r\n";
  674. if (!r.te.empty())
  675. os << "TE: " << r.te << "\r\n";
  676. if (!r.userAgent.empty())
  677. os << "User-Agent: " << r.userAgent << "\r\n";
  678. return os;
  679. }
  680. std::ostream& operator<<(std::ostream& os, const ResponseHeaders &r)
  681. {
  682. os.imbue(std::locale(os.getloc(), &rfc1123Facet_out));
  683. if (!r.acceptRanges.empty())
  684. os << "Accept-Ranges: " << r.acceptRanges << "\r\n";
  685. if (!r.eTag.unspecified)
  686. os << "ETag: " << r.eTag << "\r\n";
  687. if (r.location.isDefined())
  688. os << "Location: " << r.location << "\r\n";
  689. if (!r.proxyAuthenticate.empty())
  690. os << "Proxy-Authenticate: " << r.proxyAuthenticate << "\r\n";
  691. const boost::posix_time::ptime *retryAfterHttpDate = boost::get<boost::posix_time::ptime>(&r.retryAfter);
  692. if (retryAfterHttpDate && !retryAfterHttpDate->is_not_a_date_time())
  693. os << "Retry-After: " << *retryAfterHttpDate << "\r\n";
  694. const unsigned long long *retryAfterDeltaSeconds = boost::get<unsigned long long>(&r.retryAfter);
  695. if (retryAfterDeltaSeconds && *retryAfterDeltaSeconds != ~0ull)
  696. os << "Retry-After: " << *retryAfterDeltaSeconds << "\r\n";
  697. if (!r.server.empty())
  698. os << "Server: " << r.server << "\r\n";
  699. if (!r.wwwAuthenticate.empty())
  700. os << "WWW-Authenticate: " << r.wwwAuthenticate << "\r\n";
  701. return os;
  702. }
  703. std::ostream& operator<<(std::ostream& os, const EntityHeaders &e)
  704. {
  705. os.imbue(std::locale(os.getloc(), &rfc1123Facet_out));
  706. if (!e.allow.empty())
  707. os << "Allow: " << e.allow << "\r\n";
  708. if (!e.contentEncoding.empty())
  709. os << "Content-Encoding: " << e.contentEncoding << "\r\n";
  710. if (e.contentLength != ~0ull)
  711. os << "Content-Length: " << e.contentLength << "\r\n";
  712. if (!e.contentMD5.empty())
  713. os << "Content-MD5: " << e.contentMD5 << "\r\n";
  714. if (e.contentRange.first != ~0ull || e.contentRange.last != ~0ull || e.contentRange.instance != ~0ull)
  715. os << "Content-Range: " << e.contentRange << "\r\n";
  716. if (!e.contentType.type.empty() && !e.contentType.subtype.empty())
  717. os << "Content-Type: " << e.contentType << "\r\n";
  718. if (!e.expires.is_not_a_date_time())
  719. os << "Expires: " << e.expires << "\r\n";
  720. if (!e.lastModified.is_not_a_date_time())
  721. os << "Last-Modified: " << e.lastModified << "\r\n";
  722. for (StringMap::const_iterator it(e.extension.begin());
  723. it != e.extension.end();
  724. ++it) {
  725. os << it->first << ": " << it->second << "\r\n";
  726. }
  727. return os;
  728. }
  729. std::ostream& operator<<(std::ostream& os, const Request &r)
  730. {
  731. return os << r.requestLine << "\r\n"
  732. << r.general
  733. << r.request
  734. << r.entity << "\r\n";
  735. }
  736. std::ostream& operator<<(std::ostream& os, const Response &r)
  737. {
  738. return os << r.status << "\r\n"
  739. << r.general
  740. << r.response
  741. << r.entity << "\r\n";
  742. }
  743. }}