PageRenderTime 71ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/mordor/http/server.cpp

http://github.com/mozy/mordor
C++ | 1290 lines | 1127 code | 71 blank | 92 comment | 367 complexity | b3895f7c835b636b5460d48104ced277 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "server.h"
  3. #include <boost/bind.hpp>
  4. #include "mordor/fiber.h"
  5. #include "mordor/scheduler.h"
  6. #include "mordor/socket.h"
  7. #include "mordor/streams/null.h"
  8. #include "mordor/streams/transfer.h"
  9. #include "mordor/timer.h"
  10. #include "multipart.h"
  11. #include "parser.h"
  12. namespace Mordor {
  13. namespace HTTP {
  14. static Logger::ptr g_log = Log::lookup("mordor:http:server");
  15. ServerConnection::ServerConnection(Stream::ptr stream, boost::function<void (ServerRequest::ptr)> dg, const std::string &id)
  16. : Connection(stream),
  17. m_dg(dg),
  18. m_requestCount(0),
  19. m_priorRequestFailed(~0ull),
  20. m_priorRequestClosed(~0ull),
  21. m_priorResponseClosed(~0ull),
  22. m_clientClosed(false)
  23. {
  24. MORDOR_ASSERT(m_dg);
  25. std::ostringstream os;
  26. os << id << std::hex << (unsigned long long) this;
  27. m_context = os.str();
  28. }
  29. void
  30. ServerConnection::onClientConnectionClose(weak_ptr self)
  31. {
  32. ServerConnection::ptr strongSelf = self.lock();
  33. if (!strongSelf) {
  34. return;
  35. }
  36. MORDOR_LOG_TRACE(g_log) << m_context << " remote closed";
  37. m_clientClosed = true;
  38. }
  39. void
  40. ServerConnection::processRequests()
  41. {
  42. m_stream->onRemoteClose(boost::bind(&ServerConnection::onClientConnectionClose, this, weak_ptr(shared_from_this())));
  43. boost::recursive_mutex::scoped_lock lock(m_mutex);
  44. invariant();
  45. scheduleNextRequest(NULL);
  46. }
  47. std::vector<ServerRequest::const_ptr>
  48. ServerConnection::requests()
  49. {
  50. std::vector<ServerRequest::const_ptr> result;
  51. boost::recursive_mutex::scoped_lock lock(m_mutex);
  52. invariant();
  53. for (std::list<ServerRequest *>::const_iterator it(m_pendingRequests.begin());
  54. it != m_pendingRequests.end();
  55. ++it) {
  56. result.push_back((*it)->shared_from_this());
  57. }
  58. return result;
  59. }
  60. void
  61. ServerConnection::scheduleNextRequest(ServerRequest *request)
  62. {
  63. // MORDOR_ASSERT(m_mutex.locked());
  64. MORDOR_ASSERT(request || m_requestCount == 0);
  65. if (m_requestCount == 0 ||
  66. (request && request->m_requestNumber == m_requestCount &&
  67. request->m_requestState == ServerRequest::COMPLETE &&
  68. m_priorRequestFailed == ~0ull && m_priorRequestClosed == ~0ull &&
  69. m_priorResponseClosed == ~0ull)) {
  70. ServerRequest::ptr nextRequest(new ServerRequest(shared_from_this()));
  71. m_pendingRequests.push_back(nextRequest.get());
  72. MORDOR_LOG_TRACE(g_log) << nextRequest->context() << " scheduling request";
  73. Scheduler::getThis()->schedule(boost::bind(&ServerRequest::doRequest,
  74. nextRequest));
  75. }
  76. }
  77. void
  78. ServerConnection::requestComplete(ServerRequest *request)
  79. {
  80. MORDOR_ASSERT(request);
  81. bool close = false;
  82. {
  83. boost::recursive_mutex::scoped_lock lock(m_mutex);
  84. invariant();
  85. MORDOR_ASSERT(!m_pendingRequests.empty());
  86. MORDOR_ASSERT(request == m_pendingRequests.back());
  87. MORDOR_ASSERT(request->m_requestState == ServerRequest::HEADERS ||
  88. request->m_requestState == ServerRequest::BODY);
  89. MORDOR_LOG_TRACE(g_log) << request->context() << " request complete";
  90. request->m_requestState = ServerRequest::COMPLETE;
  91. close = request->m_willClose;
  92. if (request->m_responseState >= ServerRequest::COMPLETE) {
  93. MORDOR_ASSERT(request == m_pendingRequests.front());
  94. m_pendingRequests.pop_front();
  95. if (!close)
  96. scheduleNextRequest(request);
  97. }
  98. if (!close) {
  99. if (request->m_pipeline)
  100. scheduleNextRequest(request);
  101. } else {
  102. m_priorRequestClosed = request->m_requestNumber;
  103. MORDOR_LOG_TRACE(g_log) << m_context << " closing";
  104. }
  105. }
  106. if (close && m_stream->supportsHalfClose())
  107. m_stream->close(Stream::READ);
  108. }
  109. void
  110. ServerConnection::responseComplete(ServerRequest *request)
  111. {
  112. if (request->m_willClose) {
  113. MORDOR_LOG_TRACE(g_log) << m_context << " closing";
  114. try {
  115. m_stream->close();
  116. } catch (...) {
  117. MORDOR_LOG_DEBUG(g_log) << request->context()
  118. << " Unexpected exception: "
  119. << boost::current_exception_diagnostic_information();
  120. if (m_clientClosed) {
  121. MORDOR_LOG_DEBUG(g_log) << request->context()
  122. << " exception ignored: client already closed";
  123. } else {
  124. request->cancel();
  125. throw;
  126. }
  127. }
  128. } else {
  129. MORDOR_LOG_TRACE(g_log) << m_context << " flushing";
  130. m_stream->flush();
  131. }
  132. {
  133. boost::recursive_mutex::scoped_lock lock(m_mutex);
  134. invariant();
  135. MORDOR_ASSERT(request->m_responseState == ServerRequest::HEADERS ||
  136. ServerRequest::BODY);
  137. MORDOR_ASSERT(!m_pendingRequests.empty());
  138. MORDOR_LOG_TRACE(g_log) << request->context() << " response complete";
  139. std::list<ServerRequest *>::iterator it = m_pendingRequests.begin();
  140. MORDOR_ASSERT(request == *it);
  141. ++it;
  142. if (it != m_pendingRequests.end()) {
  143. std::set<ServerRequest *>::iterator waitIt(m_waitingResponses.find(*it));
  144. if (waitIt != m_waitingResponses.end()) {
  145. request->m_responseState = ServerRequest::COMPLETE;
  146. if (request->m_requestState >= ServerRequest::COMPLETE) {
  147. m_pendingRequests.pop_front();
  148. scheduleNextRequest(request);
  149. }
  150. request = *it;
  151. request->m_responseState = ServerRequest::HEADERS;
  152. m_waitingResponses.erase(waitIt);
  153. MORDOR_LOG_TRACE(g_log) << request->context() << " scheduling response";
  154. request->m_scheduler->schedule(request->m_fiber);
  155. return;
  156. }
  157. } else {
  158. if (request->m_requestState >= ServerRequest::COMPLETE)
  159. scheduleNextRequest(request);
  160. }
  161. if (request->m_willClose) {
  162. m_priorResponseClosed = request->m_requestNumber;
  163. }
  164. }
  165. boost::recursive_mutex::scoped_lock lock(m_mutex);
  166. invariant();
  167. MORDOR_ASSERT(!m_pendingRequests.empty());
  168. MORDOR_ASSERT(request == m_pendingRequests.front());
  169. request->m_responseState = ServerRequest::COMPLETE;
  170. if (request->m_requestState >= ServerRequest::COMPLETE)
  171. m_pendingRequests.pop_front();
  172. // Someone else may have queued up while we were flushing
  173. if (!m_pendingRequests.empty()) {
  174. request = m_pendingRequests.front();
  175. std::set<ServerRequest *>::iterator waitIt(m_waitingResponses.find(request));
  176. if (waitIt != m_waitingResponses.end()) {
  177. m_waitingResponses.erase(waitIt);
  178. request->m_responseState = ServerRequest::HEADERS;
  179. MORDOR_LOG_TRACE(g_log) << request->context() << " scheduling response";
  180. request->m_scheduler->schedule(request->m_fiber);
  181. return;
  182. }
  183. }
  184. }
  185. void
  186. ServerConnection::scheduleAllWaitingResponses()
  187. {
  188. MORDOR_ASSERT(m_priorRequestFailed != ~0ull || m_priorResponseClosed != ~0ull);
  189. // MORDOR_ASSERT(m_mutex.locked());
  190. MORDOR_LOG_TRACE(g_log) << m_context << " scheduling all responses";
  191. unsigned long long firstFailedRequest = (std::min)(m_priorRequestFailed,
  192. m_priorResponseClosed);
  193. for (std::list<ServerRequest *>::iterator it(m_pendingRequests.begin());
  194. it != m_pendingRequests.end();
  195. ++it) {
  196. ServerRequest *request = *it;
  197. if (request->m_requestNumber < firstFailedRequest)
  198. continue;
  199. std::set<ServerRequest *>::iterator waiting = m_waitingResponses.find(request);
  200. if (waiting != m_waitingResponses.end()) {
  201. MORDOR_LOG_TRACE(g_log) << request->context() << " scheduling response";
  202. request->m_scheduler->schedule(request->m_fiber);
  203. it = m_pendingRequests.erase(it);
  204. --it;
  205. m_waitingResponses.erase(waiting);
  206. }
  207. }
  208. }
  209. void
  210. ServerConnection::invariant() const
  211. {
  212. // MORDOR_ASSERT(m_mutex.locked());
  213. bool seenResponseNotDone = false;
  214. for (std::list<ServerRequest *>::const_iterator it(m_pendingRequests.begin());
  215. it != m_pendingRequests.end();
  216. ++it) {
  217. ServerRequest *request = *it;
  218. MORDOR_ASSERT(request->m_requestState < ServerRequest::COMPLETE ||
  219. request->m_responseState < ServerRequest::COMPLETE);
  220. if (seenResponseNotDone) {
  221. MORDOR_ASSERT(request->m_responseState < ServerRequest::COMPLETE);
  222. } else {
  223. seenResponseNotDone = request->m_responseState
  224. < ServerRequest::COMPLETE;
  225. }
  226. if (request->m_requestState < ServerRequest::COMPLETE) {
  227. ++it;
  228. MORDOR_ASSERT(it == m_pendingRequests.end());
  229. break;
  230. }
  231. }
  232. for (std::set<ServerRequest *>::const_iterator it(m_waitingResponses.begin());
  233. it != m_waitingResponses.end();
  234. ++it) {
  235. MORDOR_ASSERT((*it)->m_responseState == ServerRequest::WAITING);
  236. }
  237. }
  238. void
  239. ServerConnection::cancel()
  240. {
  241. boost::recursive_mutex::scoped_lock lock(m_mutex);
  242. MORDOR_LOG_VERBOSE(g_log) << m_context << " server connection cancelled";
  243. m_stream->cancelRead();
  244. m_stream->cancelWrite();
  245. }
  246. ServerRequest::ServerRequest(ServerConnection::ptr conn)
  247. : m_conn(conn),
  248. m_requestNumber(++conn->m_requestCount),
  249. m_scheduler(NULL),
  250. m_requestState(HEADERS),
  251. m_responseState(PENDING),
  252. m_willClose(false),
  253. m_pipeline(false),
  254. m_startTime(0)
  255. {
  256. std::ostringstream os;
  257. os << m_conn->context() << "-" << m_requestNumber;
  258. m_context = os.str();
  259. }
  260. ServerRequest::~ServerRequest()
  261. {
  262. MORDOR_LOG_TRACE(g_log) << this << " " << context() << " server request destroyed";
  263. cancel();
  264. }
  265. bool
  266. ServerRequest::hasRequestBody() const
  267. {
  268. if (m_requestStream)
  269. return true;
  270. return Connection::hasMessageBody(m_request.general,
  271. m_request.entity,
  272. m_request.requestLine.method,
  273. INVALID);
  274. }
  275. Stream::ptr
  276. ServerRequest::requestStream()
  277. {
  278. MORDOR_ASSERT(!m_requestMultipart);
  279. MORDOR_ASSERT(m_request.entity.contentType.type != "multipart");
  280. if (m_requestStream)
  281. return m_requestStream;
  282. return m_requestStream = m_conn->getStream(m_request.general, m_request.entity,
  283. m_request.requestLine.method, INVALID,
  284. boost::bind(&ServerRequest::requestDone, this),
  285. boost::bind(&ServerRequest::cancel, this), true);
  286. }
  287. Multipart::ptr
  288. ServerRequest::requestMultipart()
  289. {
  290. if (m_requestMultipart)
  291. return m_requestMultipart;
  292. MORDOR_ASSERT(m_request.entity.contentType.type == "multipart");
  293. MORDOR_ASSERT(!m_requestStream);
  294. StringMap::const_iterator it = m_request.entity.contentType.parameters.find("boundary");
  295. if (it == m_request.entity.contentType.parameters.end() || it->second.empty()) {
  296. throw std::runtime_error("No boundary with multipart");
  297. }
  298. m_requestStream = m_conn->getStream(m_request.general, m_request.entity,
  299. m_request.requestLine.method, INVALID,
  300. NULL,
  301. boost::bind(&ServerRequest::cancel, this), true);
  302. m_requestMultipart.reset(new Multipart(m_requestStream, it->second));
  303. m_requestMultipart->multipartFinished = boost::bind(&ServerRequest::requestDone, this);
  304. return m_requestMultipart;
  305. }
  306. const EntityHeaders &
  307. ServerRequest::requestTrailer() const
  308. {
  309. // If transferEncoding is not empty, it must include chunked,
  310. // and it must include chunked in order to have a trailer
  311. MORDOR_ASSERT(!m_request.general.transferEncoding.empty());
  312. MORDOR_ASSERT(m_requestState == COMPLETE);
  313. return m_requestTrailer;
  314. }
  315. bool
  316. ServerRequest::hasResponseBody() const
  317. {
  318. if (m_responseStream)
  319. return true;
  320. return Connection::hasMessageBody(m_response.general,
  321. m_response.entity,
  322. m_request.requestLine.method,
  323. m_response.status.status,
  324. false);
  325. }
  326. Stream::ptr
  327. ServerRequest::responseStream()
  328. {
  329. MORDOR_ASSERT(!m_responseMultipart);
  330. MORDOR_ASSERT(m_response.entity.contentType.type != "multipart");
  331. if (m_responseStream)
  332. return m_responseStream;
  333. commit();
  334. return m_responseStream = m_conn->getStream(m_response.general, m_response.entity,
  335. m_request.requestLine.method, m_response.status.status,
  336. boost::bind(&ServerRequest::responseDone, this),
  337. boost::bind(&ServerRequest::cancel, this), false);
  338. }
  339. Multipart::ptr
  340. ServerRequest::responseMultipart()
  341. {
  342. if (m_responseMultipart)
  343. return m_responseMultipart;
  344. MORDOR_ASSERT(m_response.entity.contentType.type == "multipart");
  345. MORDOR_ASSERT(!m_responseStream);
  346. StringMap::const_iterator it = m_response.entity.contentType.parameters.find("boundary");
  347. if (it == m_response.entity.contentType.parameters.end()) {
  348. throw std::runtime_error("No boundary with multipart");
  349. }
  350. commit();
  351. m_responseStream = m_conn->getStream(m_response.general, m_response.entity,
  352. m_request.requestLine.method, m_response.status.status,
  353. boost::bind(&ServerRequest::responseDone, this),
  354. boost::bind(&ServerRequest::cancel, this), false);
  355. m_responseMultipart.reset(new Multipart(m_responseStream, it->second));
  356. m_responseMultipart->multipartFinished = boost::bind(&ServerRequest::responseMultipartDone, this);
  357. return m_responseMultipart;
  358. }
  359. EntityHeaders &
  360. ServerRequest::responseTrailer()
  361. {
  362. MORDOR_ASSERT(!m_response.general.transferEncoding.empty());
  363. return m_responseTrailer;
  364. }
  365. void
  366. ServerRequest::processNextRequest()
  367. {
  368. boost::recursive_mutex::scoped_lock lock(m_conn->m_mutex);
  369. m_pipeline = true;
  370. m_conn->invariant();
  371. m_conn->scheduleNextRequest(this);
  372. }
  373. void
  374. ServerRequest::cancel()
  375. {
  376. if (m_requestState >= COMPLETE && m_responseState >= COMPLETE)
  377. return;
  378. boost::recursive_mutex::scoped_lock lock(m_conn->m_mutex);
  379. MORDOR_LOG_INFO(g_log) << m_context
  380. << " aborting with requestState: " << m_requestState
  381. << " responseState: " << m_responseState
  382. << " priorRequestFailed: " << m_conn->m_priorRequestFailed;
  383. m_conn->invariant();
  384. if (m_requestState < COMPLETE)
  385. m_requestState = ERROR;
  386. if (m_responseState < COMPLETE)
  387. m_responseState = ERROR;
  388. m_conn->m_stream->cancelRead();
  389. m_conn->m_stream->cancelWrite();
  390. m_conn->m_priorRequestFailed = (std::min)(m_conn->m_priorRequestFailed,
  391. m_requestNumber);
  392. std::list<ServerRequest *>::iterator it =
  393. std::find(m_conn->m_pendingRequests.begin(),
  394. m_conn->m_pendingRequests.end(), this);
  395. if (it != m_conn->m_pendingRequests.end())
  396. m_conn->m_pendingRequests.erase(it);
  397. m_conn->scheduleAllWaitingResponses();
  398. }
  399. void
  400. ServerRequest::readFinish()
  401. {
  402. boost::recursive_mutex::scoped_lock lock(m_conn->m_mutex);
  403. MORDOR_LOG_INFO(g_log) << m_context << " server request read finish";
  404. m_conn->invariant();
  405. m_requestState = COMPLETE;
  406. m_responseState = COMPLETE;
  407. m_conn->m_stream->cancelRead();
  408. std::list<ServerRequest *>::iterator it =
  409. std::find(m_conn->m_pendingRequests.begin(),
  410. m_conn->m_pendingRequests.end(), this);
  411. if (it != m_conn->m_pendingRequests.end())
  412. m_conn->m_pendingRequests.erase(it);
  413. }
  414. void
  415. ServerRequest::finish()
  416. {
  417. if (m_responseState < COMPLETE) {
  418. if (hasResponseBody())
  419. MORDOR_LOG_WARNING(g_log) << m_context
  420. << " incomplete response";
  421. if (committed() && hasResponseBody()) {
  422. MORDOR_LOG_INFO(g_log) << m_context
  423. << " committed and hasResponseBody, cancel...";
  424. cancel();
  425. return;
  426. }
  427. commit();
  428. if (hasResponseBody()) {
  429. MORDOR_LOG_INFO(g_log) << m_context
  430. << " commit and hasResponseBody, cancel...";
  431. cancel();
  432. return;
  433. }
  434. }
  435. discardRequestBody();
  436. }
  437. void
  438. ServerRequest::doRequest()
  439. {
  440. MORDOR_ASSERT(m_requestState == HEADERS);
  441. try {
  442. // Read and parse headers
  443. RequestParser parser(m_request);
  444. try {
  445. unsigned long long consumed = parser.run(m_conn->m_stream);
  446. m_startTime = TimerManager::now();
  447. if (consumed == 0 && !parser.error() && !parser.complete()) {
  448. // EOF
  449. MORDOR_LOG_TRACE(g_log) << m_conn->context() << " No more request";
  450. readFinish();
  451. return;
  452. }
  453. if (parser.error() || !parser.complete()) {
  454. MORDOR_LOG_WARNING(g_log) << m_context
  455. << " parser error: " << parser.error()
  456. << " parser complete: " << parser.complete();
  457. m_requestState = ERROR;
  458. m_conn->m_priorRequestClosed = m_requestNumber;
  459. m_request.requestLine.method = "INVALID";
  460. respondError(shared_from_this(), BAD_REQUEST, "Unable to parse request.", true);
  461. return;
  462. }
  463. } catch (SocketException &) {
  464. MORDOR_LOG_WARNING(g_log) << m_context
  465. << " Unexpected SocketException";
  466. cancel();
  467. return;
  468. } catch (BrokenPipeException &) {
  469. MORDOR_LOG_WARNING(g_log) << m_context
  470. << " Unexpected BrokenPipeException";
  471. cancel();
  472. return;
  473. } catch (UnexpectedEofException &) {
  474. MORDOR_LOG_WARNING(g_log) << m_context
  475. << " Unexpected BrokenPipeException";
  476. cancel();
  477. return;
  478. }
  479. if (g_log->enabled(Log::DEBUG)) {
  480. std::string webAuth, proxyAuth;
  481. bool hideAuth = false, hideProxyAuth = false;
  482. if (stricmp(m_request.request.authorization.scheme.c_str(), "Basic") == 0) {
  483. webAuth = m_request.request.authorization.param;
  484. m_request.request.authorization.param = "<hidden>";
  485. hideAuth = true;
  486. }
  487. if (stricmp(m_request.request.proxyAuthorization.scheme.c_str(), "Basic") == 0) {
  488. proxyAuth = m_request.request.proxyAuthorization.param;
  489. m_request.request.proxyAuthorization.param = "<hidden>";
  490. hideProxyAuth = true;
  491. }
  492. MORDOR_LOG_DEBUG(g_log) << m_context << " " << m_request;
  493. if (hideAuth)
  494. m_request.request.authorization.param = webAuth;
  495. if (hideProxyAuth)
  496. m_request.request.proxyAuthorization.param = proxyAuth;
  497. } else {
  498. MORDOR_LOG_VERBOSE(g_log) << m_context
  499. << " " << m_request.requestLine;
  500. }
  501. if (m_request.requestLine.ver.major != 1) {
  502. m_requestState = ERROR;
  503. respondError(shared_from_this(), HTTP_VERSION_NOT_SUPPORTED, "", true);
  504. return;
  505. }
  506. StringSet &connection = m_request.general.connection;
  507. if (m_request.requestLine.ver == Version(1, 0) &&
  508. connection.find("Keep-Alive") == connection.end())
  509. m_willClose = true;
  510. if (connection.find("close") != connection.end())
  511. m_willClose = true;
  512. // Host header required with HTTP/1.1
  513. if (m_request.requestLine.ver >= Version(1, 1) && m_request.request.host.empty()) {
  514. m_requestState = ERROR;
  515. respondError(shared_from_this(), BAD_REQUEST, "Host header is required with HTTP/1.1", true);
  516. return;
  517. }
  518. ParameterizedList &transferEncoding = m_request.general.transferEncoding;
  519. // Remove identity from the Transfer-Encodings
  520. for (ParameterizedList::iterator it(transferEncoding.begin());
  521. it != transferEncoding.end();
  522. ++it) {
  523. if (stricmp(it->value.c_str(), "identity") == 0) {
  524. it = transferEncoding.erase(it);
  525. --it;
  526. }
  527. }
  528. if (!transferEncoding.empty()) {
  529. if (stricmp(transferEncoding.back().value.c_str(), "chunked") != 0) {
  530. m_requestState = ERROR;
  531. respondError(shared_from_this(), BAD_REQUEST, "The last transfer-coding is not chunked.", true);
  532. return;
  533. }
  534. if (!transferEncoding.back().parameters.empty()) {
  535. m_requestState = ERROR;
  536. respondError(shared_from_this(), NOT_IMPLEMENTED, "Unknown parameter to chunked transfer-coding.", true);
  537. return;
  538. }
  539. for (ParameterizedList::const_iterator it(transferEncoding.begin());
  540. it + 1 != transferEncoding.end();
  541. ++it) {
  542. if (stricmp(it->value.c_str(), "chunked") == 0) {
  543. m_requestState = ERROR;
  544. respondError(shared_from_this(), BAD_REQUEST, "chunked transfer-coding applied multiple times.", true);
  545. return;
  546. } else if (stricmp(it->value.c_str(), "deflate") == 0 ||
  547. stricmp(it->value.c_str(), "gzip") == 0 ||
  548. stricmp(it->value.c_str(), "x-gzip") == 0) {
  549. // Supported transfer-codings
  550. } else if (stricmp(it->value.c_str(), "compress") == 0 ||
  551. stricmp(it->value.c_str(), "x-compress") == 0) {
  552. m_requestState = ERROR;
  553. respondError(shared_from_this(), NOT_IMPLEMENTED,
  554. "compress transfer-coding is not supported");
  555. return;
  556. } else {
  557. m_requestState = ERROR;
  558. respondError(shared_from_this(), NOT_IMPLEMENTED,
  559. "Unrecognized transfer-coding: " + it->value);
  560. return;
  561. }
  562. }
  563. }
  564. // Check expectations
  565. const ParameterizedKeyValueList &expect = m_request.request.expect;
  566. for (ParameterizedKeyValueList::const_iterator it(expect.begin());
  567. it != expect.end();
  568. ++it) {
  569. if (stricmp(it->key.c_str(), "100-continue") == 0) {
  570. if (!it->value.empty() || !it->parameters.empty()) {
  571. m_requestState = ERROR;
  572. respondError(shared_from_this(), EXPECTATION_FAILED,
  573. "Unrecognized parameters to 100-continue expectation");
  574. return;
  575. }
  576. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3
  577. // A client MUST NOT send an Expect request-header field (section
  578. // 14.20) with the "100-continue" expectation if it does not intend
  579. // to send a request body.
  580. if (!Connection::hasMessageBody(m_request.general, m_request.entity,
  581. m_request.requestLine.method, INVALID, false)) {
  582. m_requestState = ERROR;
  583. respondError(shared_from_this(), BAD_REQUEST,
  584. "Cannot use 100-continue expectation without a request body");
  585. return;
  586. }
  587. } else {
  588. m_requestState = ERROR;
  589. respondError(shared_from_this(), EXPECTATION_FAILED,
  590. "Unrecognized expectation: " + it->key);
  591. return;
  592. }
  593. }
  594. // TE is a connection-specific header
  595. if (!m_request.request.te.empty())
  596. m_request.general.connection.insert("TE");
  597. if (!Connection::hasMessageBody(m_request.general, m_request.entity,
  598. m_request.requestLine.method, INVALID)) {
  599. MORDOR_LOG_TRACE(g_log) << m_context << " no request body";
  600. m_conn->requestComplete(this);
  601. } else {
  602. m_requestState = BODY;
  603. }
  604. m_conn->m_dg(shared_from_this());
  605. finish();
  606. } catch (OperationAbortedException &) {
  607. // Do nothing (this occurs when a pipelined request fails because a
  608. // prior request closed the connection)
  609. } catch (PriorRequestFailedException &) {
  610. MORDOR_LOG_ERROR(g_log) << m_context << " Prior request failed since: "
  611. << m_conn << "-" << m_conn->m_priorRequestFailed;
  612. } catch (Assertion &) {
  613. if (m_requestState == ERROR || m_responseState == ERROR)
  614. throw;
  615. MORDOR_LOG_ERROR(g_log) << m_context
  616. << " Unexpected exception: "
  617. << boost::current_exception_diagnostic_information();
  618. if (m_responseState < COMPLETE) {
  619. try {
  620. if (!committed())
  621. respondError(shared_from_this(), INTERNAL_SERVER_ERROR);
  622. finish();
  623. // Somebody got our 500; they should report the error, so drop
  624. // the assertion
  625. return;
  626. } catch(...) {
  627. // Swallow any exceptions that happen while trying to report
  628. // the error - re-throw the assertion instead
  629. }
  630. }
  631. throw;
  632. } catch (...) {
  633. if (m_requestState == ERROR || m_responseState == ERROR)
  634. return;
  635. MORDOR_LOG_ERROR(g_log) << m_context
  636. << " Unexpected exception: "
  637. << boost::current_exception_diagnostic_information();
  638. if (m_responseState < COMPLETE) {
  639. try {
  640. if (!committed())
  641. respondError(shared_from_this(), INTERNAL_SERVER_ERROR);
  642. finish();
  643. } catch(...) {
  644. // Swallow any exceptions that happen while trying to report the error
  645. }
  646. }
  647. }
  648. }
  649. void
  650. ServerRequest::commit()
  651. {
  652. if (m_responseState != PENDING)
  653. return;
  654. if (m_response.general.connection.find("close") != m_response.general.connection.end())
  655. m_willClose = true;
  656. if (m_response.status.ver == Version()) {
  657. m_response.status.ver = m_request.requestLine.ver;
  658. // only support HTTP 1.0 and 1.1, default 1.1
  659. if (m_response.status.ver != Version(1, 0))
  660. m_response.status.ver = Version(1, 1);
  661. }
  662. MORDOR_ASSERT(m_response.status.ver == Version(1, 0) ||
  663. m_response.status.ver == Version(1, 1));
  664. // Use chunked encoding for undelimited bodies on 1.1, or force the
  665. // connection to close on 1.0
  666. if (m_response.entity.contentLength == ~0ull &&
  667. m_response.general.transferEncoding.empty() &&
  668. m_response.entity.contentType.type != "multipart") {
  669. if (m_response.status.ver == Version(1, 1) && isAcceptable(m_request.request.te,
  670. AcceptValueWithParameters("chunked"), true))
  671. m_response.general.transferEncoding.push_back("chunked");
  672. else
  673. m_willClose = true;
  674. }
  675. if (m_willClose)
  676. m_response.general.connection.insert("close");
  677. else if (m_response.status.ver == Version(1, 0))
  678. m_response.general.connection.insert("Keep-Alive");
  679. if (m_response.status.reason.empty())
  680. m_response.status.reason = reason(m_response.status.status);
  681. const ParameterizedList &transferEncoding = m_request.general.transferEncoding;
  682. // Transfer encodings only allowed on HTTP/1.1+
  683. MORDOR_ASSERT(m_response.status.ver >= Version(1, 1) || transferEncoding.empty());
  684. // If any transfer encodings, must include chunked, must have chunked only once, and must be the last one
  685. if (!transferEncoding.empty()) {
  686. MORDOR_ASSERT(m_response.status.ver == Version(1, 1));
  687. MORDOR_ASSERT(stricmp(transferEncoding.back().value.c_str(), "chunked") == 0);
  688. for (ParameterizedList::const_iterator it(transferEncoding.begin());
  689. it + 1 != transferEncoding.end();
  690. ++it) {
  691. // Only the last one can be chunked
  692. MORDOR_ASSERT(stricmp(it->value.c_str(), "chunked") != 0);
  693. // identity is only acceptable in the TE header field
  694. MORDOR_ASSERT(it->value != "identity");
  695. if (it->value == "gzip" ||
  696. it->value == "x-gzip" ||
  697. it->value == "deflate") {
  698. // Known Transfer-Codings
  699. } else if (it->value == "compress" ||
  700. it->value == "x-compress") {
  701. // Unsupported Transfer-Codings
  702. MORDOR_ASSERT(false);
  703. } else {
  704. // Unknown Transfer-Coding
  705. MORDOR_ASSERT(false);
  706. }
  707. }
  708. }
  709. if (m_response.status.status == UNAUTHORIZED) {
  710. MORDOR_ASSERT(!m_response.response.wwwAuthenticate.empty());
  711. } else if (m_response.status.status == PROXY_AUTHENTICATION_REQUIRED) {
  712. MORDOR_ASSERT(!m_response.response.proxyAuthenticate.empty());
  713. }
  714. MORDOR_ASSERT(m_response.status.status != INVALID);
  715. bool wait = false;
  716. {
  717. boost::recursive_mutex::scoped_lock lock(m_conn->m_mutex);
  718. m_conn->invariant();
  719. if (m_conn->m_priorRequestFailed < m_requestNumber ||
  720. m_conn->m_priorResponseClosed < m_requestNumber) {
  721. std::list<ServerRequest *>::iterator it;
  722. it = std::find(m_conn->m_pendingRequests.begin(), m_conn->m_pendingRequests.end(),
  723. this);
  724. MORDOR_ASSERT(it != m_conn->m_pendingRequests.end());
  725. m_conn->m_pendingRequests.erase(it);
  726. if (m_conn->m_priorRequestFailed < m_requestNumber)
  727. MORDOR_THROW_EXCEPTION(PriorRequestFailedException());
  728. else
  729. MORDOR_THROW_EXCEPTION(ConnectionVoluntarilyClosedException());
  730. }
  731. MORDOR_ASSERT(!m_conn->m_pendingRequests.empty());
  732. ServerRequest *request = m_conn->m_pendingRequests.front();
  733. if (request != this) {
  734. m_responseState = WAITING;
  735. MORDOR_VERIFY(m_conn->m_waitingResponses.insert(this).second);
  736. m_scheduler = Scheduler::getThis();
  737. m_fiber = Fiber::getThis();
  738. wait = true;
  739. MORDOR_LOG_TRACE(g_log) << m_context << " waiting to respond";
  740. } else {
  741. m_responseState = HEADERS;
  742. MORDOR_LOG_TRACE(g_log) << m_context << " responding";
  743. if (m_willClose) {
  744. m_conn->m_priorResponseClosed = m_requestNumber;
  745. m_conn->scheduleAllWaitingResponses();
  746. }
  747. }
  748. }
  749. // If we weren't the first response in the queue, wait for someone
  750. // else to schedule us
  751. if (wait) {
  752. Scheduler::yieldTo();
  753. m_scheduler = NULL;
  754. m_fiber.reset();
  755. MORDOR_LOG_TRACE(g_log) << m_context << " responding";
  756. // Check for problems that occurred while we were waiting
  757. boost::recursive_mutex::scoped_lock lock(m_conn->m_mutex);
  758. m_conn->invariant();
  759. if (m_conn->m_priorRequestFailed <= m_requestNumber)
  760. MORDOR_THROW_EXCEPTION(PriorRequestFailedException());
  761. else if (m_conn->m_priorResponseClosed <= m_requestNumber)
  762. MORDOR_THROW_EXCEPTION(ConnectionVoluntarilyClosedException());
  763. MORDOR_ASSERT(!m_conn->m_pendingRequests.empty());
  764. MORDOR_ASSERT(m_conn->m_pendingRequests.front() == this);
  765. if (m_willClose) {
  766. m_conn->m_priorResponseClosed = m_requestNumber;
  767. m_conn->scheduleAllWaitingResponses();
  768. }
  769. m_responseState = HEADERS;
  770. }
  771. try {
  772. // Write the headers
  773. std::ostringstream os;
  774. os << m_response;
  775. std::string str = os.str();
  776. if (g_log->enabled(Log::DEBUG)) {
  777. MORDOR_LOG_DEBUG(g_log) << m_context << " " << str;
  778. } else {
  779. MORDOR_LOG_VERBOSE(g_log) << m_context << " " << m_response.status;
  780. }
  781. m_conn->m_stream->write(str.c_str(), str.size());
  782. if (!Connection::hasMessageBody(m_response.general, m_response.entity,
  783. m_request.requestLine.method, m_response.status.status, false)) {
  784. MORDOR_LOG_TRACE(g_log) << m_context << " no response body";
  785. responseDone();
  786. } else {
  787. m_responseState = BODY;
  788. }
  789. } catch(...) {
  790. boost::recursive_mutex::scoped_lock lock(m_conn->m_mutex);
  791. m_conn->invariant();
  792. m_conn->m_priorRequestFailed = (std::min)(m_conn->m_priorRequestFailed,
  793. m_requestNumber);
  794. m_conn->scheduleAllWaitingResponses();
  795. throw;
  796. }
  797. }
  798. void
  799. ServerRequest::requestDone()
  800. {
  801. MORDOR_LOG_TRACE(g_log) << m_context << " request complete";
  802. m_requestStream.reset();
  803. if (!m_request.general.transferEncoding.empty()) {
  804. // Read and parse the trailer
  805. TrailerParser parser(m_requestTrailer);
  806. parser.run(m_conn->m_stream);
  807. if (parser.error()) {
  808. cancel();
  809. throw std::runtime_error("Error parsing trailer");
  810. }
  811. // it is possible that the TrailerParser is not error but not complete
  812. // if there is nothing to read from the stream
  813. // according to https://tools.ietf.org/html/rfc7230#section-4.1.2
  814. // chunked trailer is optional
  815. if (parser.complete()) {
  816. MORDOR_LOG_DEBUG(g_log) << m_context << " " << m_requestTrailer;
  817. } else if (!m_request.general.trailer.empty()) {
  818. MORDOR_LOG_WARNING(g_log) << m_context
  819. << " request has non empty trailer header but no trailer part";
  820. }
  821. }
  822. m_conn->requestComplete(this);
  823. }
  824. void
  825. ServerRequest::responseMultipartDone()
  826. {
  827. MORDOR_ASSERT(m_responseStream);
  828. m_responseStream->close();
  829. }
  830. void
  831. ServerRequest::responseDone()
  832. {
  833. MORDOR_LOG_TRACE(g_log) << m_context << " response complete";
  834. if (m_responseStream && m_responseStream->supportsSize() && m_responseStream->supportsTell())
  835. MORDOR_ASSERT(m_responseStream->size() == m_responseStream->tell());
  836. m_responseStream.reset();
  837. if (!m_response.general.transferEncoding.empty() &&
  838. m_request.requestLine.method != HEAD) {
  839. std::ostringstream os;
  840. os << m_responseTrailer << "\r\n";
  841. std::string str = os.str();
  842. MORDOR_LOG_DEBUG(g_log) << m_context << " " << str;
  843. m_conn->m_stream->write(str.c_str(), str.size());
  844. }
  845. MORDOR_LOG_INFO(g_log) << m_context << " "
  846. << m_request.requestLine << " " << m_response.status.status;
  847. m_conn->responseComplete(this);
  848. }
  849. void
  850. ServerRequest::discardRequestBody()
  851. {
  852. if (m_requestState == BODY && !m_willClose) {
  853. if (m_request.entity.contentType.type == "multipart") {
  854. if (!m_requestMultipart)
  855. m_requestMultipart = requestMultipart();
  856. while(m_requestMultipart->nextPart());
  857. } else {
  858. if (!m_requestStream)
  859. m_requestStream = requestStream();
  860. MORDOR_ASSERT(m_requestStream);
  861. transferStream(m_requestStream, NullStream::get());
  862. }
  863. }
  864. }
  865. void
  866. respondError(ServerRequest::ptr request, Status status,
  867. const std::string &message, bool closeConnection, bool clearETag)
  868. {
  869. MORDOR_ASSERT(!request->committed());
  870. request->response().status.status = status;
  871. if (closeConnection)
  872. request->response().general.connection.insert("close");
  873. request->response().general.transferEncoding.clear();
  874. request->response().general.trailer.clear();
  875. request->response().entity.contentLength = message.size();
  876. request->response().entity.contentType.type.clear();
  877. if (clearETag)
  878. request->response().response.eTag = ETag();
  879. if (!message.empty()) {
  880. request->response().entity.contentType.type = "text";
  881. request->response().entity.contentType.subtype = "plain";
  882. if (request->request().requestLine.method == HEAD) {
  883. request->finish();
  884. } else {
  885. Stream::ptr responseStream = request->responseStream();
  886. responseStream->write(message.c_str(), message.size());
  887. responseStream->close();
  888. }
  889. } else {
  890. request->finish();
  891. }
  892. }
  893. void
  894. respondStream(ServerRequest::ptr request, Stream &response)
  895. {
  896. MORDOR_ASSERT(!request->committed());
  897. unsigned long long size = ~0ull;
  898. if (response.supportsSize())
  899. size = response.size();
  900. bool trailers = (size == ~0ull &&
  901. isAcceptable(request->request().request.te, "trailers"));
  902. // Only advertise byte range request if it would be possible on the current
  903. // request
  904. if (trailers || size != ~0ull)
  905. request->response().response.acceptRanges.insert("bytes");
  906. ParameterizedList &transferEncoding =
  907. request->response().general.transferEncoding;
  908. transferEncoding.clear();
  909. const RangeSet &range = request->request().request.range;
  910. bool fullEntity = range.empty();
  911. // Validate range request
  912. // If we don't know the size, and we don't support trailers, have to send
  913. // the whole thing
  914. if (size == ~0ull && !trailers)
  915. fullEntity = true;
  916. // If we're using trailers, it only works for a single range
  917. if (trailers && range.size() > 1)
  918. fullEntity = true;
  919. const ETag *ifRange =
  920. boost::get<ETag>(&request->request().request.ifRange);
  921. if (!fullEntity && ifRange && !ifRange->unspecified &&
  922. !ifRange->strongCompare(request->response().response.eTag))
  923. fullEntity = true;
  924. // Timestamps with If-Range is not supported (at this level we can't know
  925. // if it was possible for the entity to have changed multiple times in a
  926. // single second; see
  927. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.3)
  928. const boost::posix_time::ptime *httpDate =
  929. boost::get<boost::posix_time::ptime>(
  930. &request->request().request.ifRange);
  931. if (httpDate && !httpDate->is_not_a_date_time())
  932. fullEntity = true;
  933. // TODO: sort and merge overlapping ranges
  934. unsigned long long previousLast = 0;
  935. for (RangeSet::const_iterator it(range.begin());
  936. it != range.end();
  937. ++it) {
  938. if (fullEntity)
  939. break;
  940. // Invalid; first is after last
  941. if (it->first > it->second && it->first != ~0ull) {
  942. fullEntity = true;
  943. break;
  944. }
  945. // Unsupported - suffix range when we can't determine the size
  946. if (it->first == ~0ull && size == ~0ull) {
  947. fullEntity = true;
  948. break;
  949. }
  950. // First byte is beyond end of stream
  951. if (it->first >= size && size != ~0ull && it->first != ~0ull) {
  952. respondError(request, REQUESTED_RANGE_NOT_SATISFIABLE);
  953. return;
  954. }
  955. // Suffix range is greater than entire stream
  956. if (it->first == ~0ull && it->second >= size) {
  957. fullEntity = true;
  958. break;
  959. }
  960. // Regular range contains entire stream
  961. if (it->first == 0 && it->second >= size - 1) {
  962. fullEntity = true;
  963. break;
  964. }
  965. // Unsupported: un-ordered range and stream doesn't support seeking
  966. if (it != range.begin()) {
  967. if (it->first <= previousLast && !response.supportsSeek()) {
  968. fullEntity = true;
  969. break;
  970. }
  971. }
  972. if (it->first == ~0ull)
  973. previousLast = size - 1;
  974. else
  975. previousLast = it->second;
  976. }
  977. // We can satisfy the range request
  978. if (!fullEntity) {
  979. // Multiple ranges; must use multipart; we don't support chunked
  980. // encoding (does it make sense?), so don't advertise or worry about
  981. // trailers or transfer encodings
  982. if (range.size() > 1) {
  983. MediaType contentType = request->response().entity.contentType;
  984. request->response().entity.contentLength = ~0;
  985. request->response().entity.contentType.type = "multipart";
  986. request->response().entity.contentType.subtype = "byteranges";
  987. request->response().entity.contentType.parameters["boundary"] =
  988. Multipart::randomBoundary();
  989. request->response().status.status = PARTIAL_CONTENT;
  990. unsigned long long currentPos = 0;
  991. if (request->request().requestLine.method != HEAD) {
  992. // force use chunked encoding. Reason:
  993. // - Content-Type: multipart/byteranges itself can't tell
  994. // when the response body end, and
  995. // - Content-Length is not applicable here as well.
  996. if (transferEncoding.empty())
  997. transferEncoding.push_back("chunked");
  998. Multipart::ptr multipart = request->responseMultipart();
  999. for (RangeSet::const_iterator it(range.begin());
  1000. it != range.end();
  1001. ++it) {
  1002. BodyPart::ptr part = multipart->nextPart();
  1003. part->headers().contentType = contentType;
  1004. ContentRange &cr = part->headers().contentRange;
  1005. cr.instance = size;
  1006. if (it->first == ~0ull) {
  1007. if (it->second > size)
  1008. cr.first = 0;
  1009. else
  1010. cr.first = size - it->second;
  1011. } else {
  1012. cr.first = it->first;
  1013. cr.last = (std::min)(it->second, size - 1);
  1014. }
  1015. if (response.supportsSeek())
  1016. response.seek(cr.first);
  1017. else
  1018. transferStream(response, NullStream::get(), cr.first - currentPos);
  1019. transferStream(response, part->stream(), cr.last - cr.first + 1);
  1020. part->stream()->close();
  1021. currentPos = cr.last + 1;
  1022. }
  1023. multipart->finish();
  1024. }
  1025. } else {
  1026. // Single range; we'll support compression (advertise it, and use
  1027. // it if requested) and trailers (if necessary)
  1028. request->response().status.status = PARTIAL_CONTENT;
  1029. if (request->request().requestLine.ver >= Version(1, 1)) {
  1030. AcceptListWithParameters available;
  1031. available.push_back(AcceptValueWithParameters("deflate", 1000));
  1032. available.push_back(AcceptValueWithParameters("gzip", 500));
  1033. available.push_back(AcceptValueWithParameters("x-gzip", 500));
  1034. const AcceptValueWithParameters *preferredEncoding =
  1035. preferred(request->request().request.te, available);
  1036. if (preferredEncoding) {
  1037. transferEncoding.push_back(preferredEncoding->value);
  1038. transferEncoding.push_back("chunked");
  1039. }
  1040. }
  1041. // Set up headers (for trailers, or not for trailers)
  1042. ContentRange *cr;
  1043. if (trailers) {
  1044. request->response().general.trailer.insert("Content-Range");
  1045. if (transferEncoding.empty())
  1046. transferEncoding.push_back("chunked");
  1047. cr = &request->responseTrailer().contentRange;
  1048. cr->first = range.front().first;
  1049. cr->last = range.front().second;
  1050. MORDOR_ASSERT(cr->first != ~0ull);
  1051. } else {
  1052. cr = &request->response().entity.contentRange;
  1053. cr->instance = size;
  1054. if (range.front().first == ~0ull) {
  1055. if (range.front().second > size)
  1056. cr->first = 0;
  1057. else
  1058. cr->first = size - range.front().second;
  1059. cr->last = size - 1;
  1060. } else {
  1061. cr->first = range.front().first;
  1062. cr->last = (std::min)(range.front().second, size - 1);
  1063. }
  1064. request->response().entity.contentLength = cr->last - cr->first + 1;
  1065. }
  1066. bool isHead = (request->request().requestLine.method == HEAD);
  1067. // Seek to the correct position
  1068. // Skip the seek if it's a HEAD, and we don't need to check for
  1069. // out-of-range because we already know the size
  1070. if (!isHead || trailers) {
  1071. if (response.supportsSeek()) {
  1072. response.seek(cr->first, Stream::BEGIN);
  1073. } else {
  1074. // Can't seek, have to do this the old fashioned way
  1075. unsigned long long transferred = transferStream(
  1076. response, NullStream::get(), cr->first, UNTILEOF);
  1077. // Make sure we're not out-of-range
  1078. if (transferred != cr->first) {
  1079. respondError(request, REQUESTED_RANGE_NOT_SATISFIABLE);
  1080. return;
  1081. }
  1082. }
  1083. }
  1084. if (isHead) {
  1085. // On a head, when we don't know the size of the stream, we
  1086. // just need to verify that the Range isn't beyond the end of
  1087. // the stream (by reading a single byte)
  1088. if (trailers) {
  1089. char byte;
  1090. if (response.read(&byte, 1) == 0) {
  1091. respondError(request, REQUESTED_RANGE_NOT_SATISFIABLE);
  1092. return;
  1093. }
  1094. }
  1095. } else {
  1096. unsigned long long transferred = 0;
  1097. // There's an edge case where either the stream is seekable,
  1098. // but not sizable, or just not sizeable, and so we're pointing
  1099. // exactly at eof (or beyond), and don't know it; need to read
  1100. // a byte without committing to see if we can actually satisfy
  1101. // the request
  1102. if (trailers) {
  1103. char byte;
  1104. transferred = response.read(&byte, 1);
  1105. if (transferred == 0) {
  1106. respondError(request, REQUESTED_RANGE_NOT_SATISFIABLE);
  1107. return;
  1108. }
  1109. request->responseStream()->write(&byte, 1);
  1110. }
  1111. // Actually transfer the requested range
  1112. transferred += transferStream(response,
  1113. request->responseStream(),
  1114. cr->last - cr->first + 1 - transferred,
  1115. trailers ? UNTILEOF : EXACT);
  1116. if (trailers) {
  1117. // Set how much was actually transferred
  1118. cr->last = cr->first + transferred - 1;
  1119. // And discard the rest of the stream to get the size
  1120. cr->instance = cr->last + transferStream(response,
  1121. NullStream::get()) + 1;
  1122. } else if (transferred != cr->last - cr->first + 1) {
  1123. // The stream LIED about its size!
  1124. MORDOR_THROW_EXCEPTION(UnexpectedEofException());
  1125. }
  1126. request->responseStream()->close();
  1127. }
  1128. }
  1129. } else {
  1130. // User only asked for, or it's only possible to send the full entity
  1131. request->response().entity.contentLength = size;
  1132. if (request->request().requestLine.ver >= Version(1, 1)) {
  1133. AcceptListWithParameters available;
  1134. available.push_back(AcceptValueWithParameters("deflate", 1000));
  1135. available.push_back(AcceptValueWithParameters("gzip", 500));
  1136. available.push_back(AcceptValueWithParameters("x-gzip", 500));
  1137. const AcceptValueWithParameters *preferredEncoding =
  1138. preferred(request->request().request.te, available);
  1139. if (preferredEncoding) {
  1140. transferEncoding.push_back(preferredEncoding->value);
  1141. transferEncoding.push_back("chunked");
  1142. }
  1143. }
  1144. if (request->request().requestLine.method != HEAD) {
  1145. if (size != 0u) {
  1146. transferStream(response, request->responseStream(), size);
  1147. request->responseStream()->close();
  1148. }
  1149. }
  1150. }
  1151. if (request->request().requestLine.method == HEAD)
  1152. request->finish();
  1153. }
  1154. void
  1155. respondStream(ServerRequest::ptr request, Stream::ptr response)
  1156. {
  1157. respondStream(request, *response);
  1158. }
  1159. bool ifMatch(ServerRequest::ptr request, const ETag &eTag)
  1160. {
  1161. const std::set<ETag> &ifMatch = request->request().request.ifMatch;
  1162. // Special case *; if it's there, and there's no ETag, fail
  1163. if (ifMatch.size() == 1 && ifMatch.begin()->unspecified) {
  1164. if (eTag.unspecified) {
  1165. respondError(request, PRECONDITION_FAILED);
  1166. return false;
  1167. }
  1168. } else if (!ifMatch.empty()) {
  1169. bool matched = false;
  1170. for (std::set<ETag>::const_iterator it(ifMatch.begin());
  1171. it != ifMatch.end();
  1172. ++it) {
  1173. if (it->strongCompare(eTag)) {
  1174. matched = true;
  1175. break;
  1176. }
  1177. }
  1178. if (!matched) {
  1179. respondError(request, PRECONDITION_FAILED);
  1180. return false;
  1181. }
  1182. }
  1183. const std::string &method = request->request().requestLine.method;
  1184. bool getOrHead = (method == GET || method == HEAD);
  1185. const std::set<ETag> &ifNoneMatch = request->request().request.ifNoneMatch;
  1186. // Special case *; if it's there, and there is an entity, fail
  1187. if (ifNoneMatch.size() == 1 && ifNoneMatch.begin()->unspecified) {
  1188. if (!eTag.unspecified) {
  1189. if (getOrHead)
  1190. request->response().response.eTag = eTag;
  1191. respondError(request, getOrHead ? NOT_MODIFIED : PRECONDITION_FAILED,
  1192. std::string(), false, !getOrHead);
  1193. return false;
  1194. }
  1195. } else {
  1196. bool matched = false;
  1197. for (std::set<ETag>::const_iterator it(ifNoneMatch.begin());
  1198. it != ifNoneMatch.end();
  1199. ++it) {
  1200. if (getOrHead && it->weakCompare(eTag)) {
  1201. matched = true;
  1202. break;
  1203. } else if (!getOrHead && it->strongCompare(eTag)) {
  1204. matched = true;
  1205. break;
  1206. }
  1207. }
  1208. if (matched) {
  1209. if (getOrHead)
  1210. request->response().response.eTag = eTag;
  1211. respondError(request,
  1212. getOrHead ? NOT_MODIFIED : PRECONDITION_FAILED, std::string(),
  1213. false, !getOrHead);
  1214. return false;
  1215. }
  1216. }
  1217. return true;
  1218. }
  1219. }}