PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/server/libevent-server.cpp

https://gitlab.com/Blueprint-Marketing/hhvm
C++ | 689 lines | 522 code | 89 blank | 78 comment | 115 complexity | c15e384aa0fde9b648c70e8248028127 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "hphp/runtime/server/libevent-server.h"
  17. #include "hphp/runtime/base/runtime-option.h"
  18. #include "hphp/runtime/base/memory-manager.h"
  19. #include "hphp/runtime/base/crash-reporter.h"
  20. #include "hphp/runtime/base/url.h"
  21. #include "hphp/runtime/server/http-protocol.h"
  22. #include "hphp/runtime/server/server-name-indication.h"
  23. #include "hphp/runtime/server/server-stats.h"
  24. #include "hphp/util/compatibility.h"
  25. #include "hphp/util/logger.h"
  26. #include "hphp/util/timer.h"
  27. ///////////////////////////////////////////////////////////////////////////////
  28. // static handler
  29. static void on_request(struct evhttp_request *request, void *obj) {
  30. assert(obj);
  31. ((HPHP::LibEventServer*)obj)->onRequest(request);
  32. }
  33. static void on_response(int fd, short what, void *obj) {
  34. assert(obj);
  35. ((HPHP::PendingResponseQueue*)obj)->process();
  36. }
  37. static void on_timer(int fd, short events, void *context) {
  38. event_base_loopbreak((struct event_base *)context);
  39. }
  40. static void on_thread_stop(int fd, short events, void *context) {
  41. event_base_loopbreak((struct event_base *)context);
  42. }
  43. namespace HPHP {
  44. ///////////////////////////////////////////////////////////////////////////////
  45. // LibEventJob
  46. void LibEventJob::getRequestStart(struct timespec *reqStart) {
  47. #ifdef EVHTTP_CONNECTION_GET_START
  48. evhttp_connection_get_start(request->evcon, reqStart);
  49. #endif
  50. }
  51. ///////////////////////////////////////////////////////////////////////////////
  52. // LibEventTransportTraits
  53. LibEventTransportTraits::LibEventTransportTraits(
  54. std::shared_ptr<LibEventJob> job,
  55. void *opaque,
  56. int id) :
  57. server_((LibEventServer*)opaque),
  58. request_(job->request),
  59. transport_(server_, request_, id) {
  60. #ifdef _EVENT_USE_OPENSSL
  61. if (evhttp_is_connection_ssl(request_->evcon)) {
  62. transport_.setSSL();
  63. }
  64. #endif
  65. }
  66. ///////////////////////////////////////////////////////////////////////////////
  67. // constructor and destructor
  68. LibEventServer::LibEventServer(const ServerOptions &options)
  69. : Server(options.m_address, options.m_port, options.m_numThreads),
  70. m_accept_sock(options.m_serverFD),
  71. m_accept_sock_ssl(options.m_sslFD),
  72. m_dispatcher(options.m_numThreads, RuntimeOption::ServerThreadRoundRobin,
  73. RuntimeOption::ServerThreadDropCacheTimeoutSeconds,
  74. RuntimeOption::ServerThreadDropStack,
  75. this, RuntimeOption::ServerThreadJobLIFOSwitchThreshold,
  76. RuntimeOption::ServerThreadJobMaxQueuingMilliSeconds,
  77. kNumPriorities),
  78. m_dispatcherThread(this, &LibEventServer::dispatch) {
  79. m_eventBase = event_base_new();
  80. m_server = evhttp_new(m_eventBase);
  81. m_server_ssl = nullptr;
  82. evhttp_set_connection_limit(m_server, RuntimeOption::ServerConnectionLimit);
  83. evhttp_set_gencb(m_server, on_request, this);
  84. #ifdef EVHTTP_PORTABLE_READ_LIMITING
  85. evhttp_set_read_limit(m_server, RuntimeOption::RequestBodyReadLimit);
  86. #endif
  87. m_responseQueue.create(m_eventBase);
  88. if (!options.m_takeoverFilename.empty()) {
  89. m_takeover_agent.reset(new TakeoverAgent(options.m_takeoverFilename));
  90. }
  91. }
  92. LibEventServer::~LibEventServer() {
  93. assert(getStatus() == RunStatus::STOPPED ||
  94. getStatus() == RunStatus::STOPPING ||
  95. getStatus() == RunStatus::NOT_YET_STARTED);
  96. // We can't free event base when server is still working on it.
  97. // This will cause a leak with event base, but normally this happens when
  98. // process exits, so we're probably fine.
  99. if (getStatus() != RunStatus::STOPPING) {
  100. event_base_free(m_eventBase);
  101. }
  102. }
  103. ///////////////////////////////////////////////////////////////////////////////
  104. // implementing HttpServer
  105. void LibEventServer::addTakeoverListener(TakeoverListener* listener) {
  106. if (m_takeover_agent) {
  107. m_takeover_agent->addTakeoverListener(listener);
  108. }
  109. }
  110. void LibEventServer::removeTakeoverListener(TakeoverListener* listener) {
  111. if (m_takeover_agent) {
  112. m_takeover_agent->removeTakeoverListener(listener);
  113. }
  114. }
  115. int LibEventServer::useExistingFd(evhttp *server, int fd, bool needListen) {
  116. Logger::Info("inheritfd: using inherited fd %d for server", fd);
  117. int ret = -1;
  118. if (needListen) {
  119. ret = listen(fd, RuntimeOption::ServerBacklog);
  120. if (ret != 0) {
  121. Logger::Error("inheritfd: listen() failed: %s",
  122. folly::errnoStr(errno).c_str());
  123. return -1;
  124. }
  125. }
  126. ret = evhttp_accept_socket(server, fd);
  127. if (ret < 0) {
  128. Logger::Error("evhttp_accept_socket: %s",
  129. folly::errnoStr(errno).c_str());
  130. int errno_save = errno;
  131. close(fd);
  132. errno = errno_save;
  133. return -1;
  134. }
  135. return 0;
  136. }
  137. int LibEventServer::getAcceptSocket() {
  138. if (m_accept_sock >= 0) {
  139. if (useExistingFd(m_server, m_accept_sock, true /* listen */) != 0) {
  140. m_accept_sock = -1;
  141. return -1;
  142. }
  143. return 0;
  144. }
  145. const char *address = m_address.empty() ? nullptr : m_address.c_str();
  146. int ret = evhttp_bind_socket_backlog_fd(m_server, address,
  147. m_port, RuntimeOption::ServerBacklog);
  148. if (ret < 0) {
  149. if (errno == EADDRINUSE && m_takeover_agent) {
  150. ret = m_takeover_agent->takeover();
  151. if (ret < 0) {
  152. return -1;
  153. }
  154. if (useExistingFd(m_server, ret, false /* no listen */) != 0) {
  155. return -1;
  156. }
  157. } else {
  158. Logger::Error("Fail to bind port %d: %d %s",
  159. m_port, errno, folly::errnoStr(errno).c_str());
  160. return -1;
  161. }
  162. }
  163. m_accept_sock = ret;
  164. if (m_takeover_agent) {
  165. m_takeover_agent->requestShutdown();
  166. m_takeover_agent->setupFdServer(m_eventBase, m_accept_sock, this);
  167. }
  168. return 0;
  169. }
  170. int LibEventServer::onTakeoverRequest(TakeoverAgent::RequestType type) {
  171. int ret = -1;
  172. if (type == TakeoverAgent::RequestType::LISTEN_SOCKET) {
  173. // TODO: This is broken-sauce. We should continue serving
  174. // requests from this process until shutdown.
  175. // Make evhttp forget our copy of the accept socket so we don't accept any
  176. // more connections and drop them. Keep the socket open until we get the
  177. // shutdown request so that we can still serve AFDT requests (if the new
  178. // server crashes or something). The downside is that it will take the LB
  179. // longer to figure out that we are broken.
  180. ret = evhttp_del_accept_socket(m_server, m_accept_sock);
  181. if (ret < 0) {
  182. // This will fail if we get a second AFDT request, but the spurious
  183. // log message is not too harmful.
  184. Logger::Error("Unable to delete accept socket");
  185. }
  186. } else if (type == TakeoverAgent::RequestType::TERMINATE) {
  187. ret = close(m_accept_sock);
  188. if (ret < 0) {
  189. Logger::Error("Unable to close accept socket");
  190. return -1;
  191. }
  192. m_accept_sock = -1;
  193. // Close SSL server
  194. if (m_server_ssl) {
  195. assert(m_accept_sock_ssl > 0);
  196. ret = evhttp_del_accept_socket(m_server_ssl, m_accept_sock_ssl);
  197. if (ret < 0) {
  198. Logger::Error("Unable to delete accept socket for SSL in evhttp");
  199. return -1;
  200. }
  201. ret = close(m_accept_sock_ssl);
  202. if (ret < 0) {
  203. Logger::Error("Unable to close accept socket for SSL");
  204. return -1;
  205. }
  206. }
  207. }
  208. return 0;
  209. }
  210. void LibEventServer::takeoverAborted() {
  211. if (m_accept_sock >= 0) {
  212. close(m_accept_sock);
  213. m_accept_sock = -1;
  214. }
  215. }
  216. int LibEventServer::getLibEventConnectionCount() {
  217. return evhttp_get_connection_count(m_server);
  218. }
  219. void LibEventServer::start() {
  220. if (getStatus() == RunStatus::RUNNING) return;
  221. if (getAcceptSocket() != 0) {
  222. throw FailedToListenException(m_address, m_port);
  223. }
  224. if (m_server_ssl != nullptr) {
  225. if (getAcceptSocketSSL() != 0) {
  226. Logger::Error("Fail to listen on ssl port %d", m_port_ssl);
  227. throw FailedToListenException(m_address, m_port_ssl);
  228. }
  229. Logger::Info("Listen on ssl port %d",m_port_ssl);
  230. }
  231. setStatus(RunStatus::RUNNING);
  232. m_dispatcher.start();
  233. m_dispatcherThread.start();
  234. }
  235. void LibEventServer::waitForEnd() {
  236. m_dispatcherThread.waitForEnd();
  237. }
  238. void LibEventServer::dispatchWithTimeout(int timeoutSeconds) {
  239. struct timeval timeout;
  240. timeout.tv_sec = timeoutSeconds;
  241. timeout.tv_usec = 0;
  242. event eventTimeout;
  243. event_set(&eventTimeout, -1, 0, on_timer, m_eventBase);
  244. event_base_set(m_eventBase, &eventTimeout);
  245. event_add(&eventTimeout, &timeout);
  246. event_base_loop(m_eventBase, EVLOOP_ONCE);
  247. event_del(&eventTimeout);
  248. }
  249. void LibEventServer::dispatch() {
  250. m_pipeStop.open();
  251. event_set(&m_eventStop, m_pipeStop.getOut(), EV_READ|EV_PERSIST,
  252. on_thread_stop, m_eventBase);
  253. event_base_set(m_eventBase, &m_eventStop);
  254. event_add(&m_eventStop, nullptr);
  255. while (getStatus() != RunStatus::STOPPED) {
  256. event_base_loop(m_eventBase, EVLOOP_ONCE);
  257. }
  258. event_del(&m_eventStop);
  259. // flushing all responses
  260. if (!m_responseQueue.empty()) {
  261. m_responseQueue.process();
  262. }
  263. m_responseQueue.close();
  264. if (m_takeover_agent) {
  265. m_takeover_agent->stop();
  266. }
  267. // flushing all remaining events
  268. if (RuntimeOption::ServerGracefulShutdownWait) {
  269. dispatchWithTimeout(RuntimeOption::ServerGracefulShutdownWait);
  270. }
  271. }
  272. void LibEventServer::stop() {
  273. Lock lock(m_mutex);
  274. if (getStatus() != RunStatus::RUNNING || m_server == nullptr) return;
  275. #define SHUT_FBLISTEN 3
  276. /*
  277. * Modifications to the Linux kernel to support shutting down a listen
  278. * socket for new connections only, but anything which has completed
  279. * the TCP handshake will still be accepted. This allows for un-accepted
  280. * connections to be queued and then wait until all queued requests are
  281. * actively being processed.
  282. */
  283. if (RuntimeOption::ServerShutdownListenWait > 0 &&
  284. m_accept_sock != -1 && shutdown(m_accept_sock, SHUT_FBLISTEN) == 0) {
  285. int noWorkCount = 0;
  286. for (int i = 0; i < RuntimeOption::ServerShutdownListenWait; i++) {
  287. // Give the acceptor thread time to clean out all requests
  288. Logger::Info(
  289. "LibEventServer stopping port %d: [%d/%d] a/q/e %d/%d/%d",
  290. m_port, i, RuntimeOption::ServerShutdownListenWait,
  291. getActiveWorker(), getQueuedJobs(), getLibEventConnectionCount());
  292. sleep(1);
  293. // If we're not doing anything, break out quickly
  294. noWorkCount += (getQueuedJobs() == 0 && getActiveWorker() == 0);
  295. if (RuntimeOption::ServerShutdownListenNoWork > 0 &&
  296. noWorkCount >= RuntimeOption::ServerShutdownListenNoWork)
  297. break;
  298. if (getLibEventConnectionCount() == 0 &&
  299. getQueuedJobs() == 0 && getActiveWorker() == 0)
  300. break;
  301. }
  302. Logger::Info("LibEventServer stopped port %d: a/q/e %d/%d/%d",
  303. m_port, getActiveWorker(), getQueuedJobs(),
  304. getLibEventConnectionCount());
  305. }
  306. // inform LibEventServer::onRequest() to stop queuing
  307. setStatus(RunStatus::STOPPING);
  308. // stop JobQueue processing
  309. m_dispatcher.stop();
  310. // stop event loop
  311. setStatus(RunStatus::STOPPED);
  312. if (write(m_pipeStop.getIn(), "", 1) < 0) {
  313. // an error occurred but we're in shutdown already, so ignore
  314. }
  315. m_dispatcherThread.waitForEnd();
  316. for (auto listener: m_listeners) {
  317. listener->serverStopped(this);
  318. }
  319. evhttp_free(m_server);
  320. m_server = nullptr;
  321. }
  322. ///////////////////////////////////////////////////////////////////////////////
  323. // SSL handling
  324. bool LibEventServer::certHandler(const std::string &server_name,
  325. const std::string &key_file,
  326. const std::string &crt_file,
  327. bool duplicate) {
  328. #ifdef _EVENT_USE_OPENSSL
  329. // Create an SSL_CTX for this cert pair.
  330. struct ssl_config tmp_config;
  331. tmp_config.cert_file = (char *)(crt_file.c_str());
  332. tmp_config.pk_file = (char *)(key_file.c_str());
  333. SSL_CTX *tmp_ctx = (SSL_CTX*)evhttp_init_openssl(&tmp_config);
  334. if (tmp_ctx) {
  335. ServerNameIndication::insertSNICtx(server_name, tmp_ctx);
  336. return true;
  337. }
  338. #endif
  339. return false;
  340. }
  341. bool LibEventServer::enableSSL(int port) {
  342. #ifdef _EVENT_USE_OPENSSL
  343. SSL_CTX *sslCTX = nullptr;
  344. struct ssl_config config;
  345. if (RuntimeOption::SSLCertificateFile != "" &&
  346. RuntimeOption::SSLCertificateKeyFile != "") {
  347. config.cert_file = (char*)RuntimeOption::SSLCertificateFile.c_str();
  348. config.pk_file = (char*)RuntimeOption::SSLCertificateKeyFile.c_str();
  349. sslCTX = (SSL_CTX *)evhttp_init_openssl(&config);
  350. if (sslCTX && !RuntimeOption::SSLCertificateDir.empty()) {
  351. ServerNameIndication::load(RuntimeOption::SSLCertificateDir,
  352. LibEventServer::certHandler);
  353. // Register our per-request server name indication callback.
  354. // We register our callback even if there's no additional certs so that
  355. // a cert added in the future will get picked up without a restart.
  356. SSL_CTX_set_tlsext_servername_callback(
  357. sslCTX,
  358. ServerNameIndication::callback);
  359. }
  360. } else {
  361. Logger::Error("Invalid certificate file or key file");
  362. }
  363. m_server_ssl = evhttp_new_openssl_ctx(m_eventBase, sslCTX);
  364. if (m_server_ssl == nullptr) {
  365. Logger::Error("evhttp_new_openssl_ctx failed");
  366. return false;
  367. }
  368. m_port_ssl = port;
  369. evhttp_set_connection_limit(m_server_ssl,
  370. RuntimeOption::ServerConnectionLimit);
  371. evhttp_set_gencb(m_server_ssl, on_request, this);
  372. return true;
  373. #else
  374. Logger::Error("A SSL enabled libevent is required");
  375. return false;
  376. #endif
  377. }
  378. int LibEventServer::getAcceptSocketSSL() {
  379. if (m_accept_sock_ssl >= 0) {
  380. if (useExistingFd(m_server_ssl, m_accept_sock_ssl, true /*listen*/) != 0) {
  381. m_accept_sock_ssl = -1;
  382. return -1;
  383. }
  384. return 0;
  385. }
  386. const char *address = m_address.empty() ? nullptr : m_address.c_str();
  387. int ret = evhttp_bind_socket_backlog_fd(m_server_ssl, address,
  388. m_port_ssl, RuntimeOption::ServerBacklog);
  389. if (ret < 0) {
  390. Logger::Error("Failed to bind port %d for SSL", m_port_ssl);
  391. return -1;
  392. }
  393. Logger::Info("SSL enabled");
  394. m_accept_sock_ssl = ret;
  395. return 0;
  396. }
  397. ///////////////////////////////////////////////////////////////////////////////
  398. // request/response handling
  399. void LibEventServer::onRequest(struct evhttp_request *request) {
  400. // If we are in the process of crashing, we want to reject incoming work.
  401. // This will prompt the load balancers to choose another server. Using
  402. // shutdown rather than close has the advantage that it makes fewer changes
  403. // to the process (eg, it doesn't close the FD so if the FD number were
  404. // corrupted it would be mostly harmless).
  405. //
  406. // Setting accept sock to -1 will leak FDs. But we're crashing anyways.
  407. if (IsCrashing) {
  408. if (m_accept_sock != -1) {
  409. shutdown(m_accept_sock, SHUT_FBLISTEN);
  410. m_accept_sock = -1;
  411. }
  412. if (m_accept_sock_ssl != -1) {
  413. shutdown(m_accept_sock_ssl, SHUT_FBLISTEN);
  414. m_accept_sock_ssl = -1;
  415. }
  416. return;
  417. }
  418. if (RuntimeOption::EnableKeepAlive &&
  419. RuntimeOption::ConnectionTimeoutSeconds > 0) {
  420. // before processing request, set the connection timeout
  421. // it's just writing a variable in libevent
  422. evhttp_connection_set_timeout(request->evcon,
  423. RuntimeOption::ConnectionTimeoutSeconds);
  424. }
  425. if (getStatus() == RunStatus::RUNNING) {
  426. RequestPriority priority = getRequestPriority(request);
  427. m_dispatcher.enqueue(std::make_shared<LibEventJob>(request), priority);
  428. } else {
  429. Logger::Error("throwing away one new request while shutting down");
  430. }
  431. }
  432. void LibEventServer::onResponse(int worker, evhttp_request *request,
  433. int code, LibEventTransport *transport) {
  434. int nwritten = 0;
  435. bool skip_sync = false;
  436. if (request->evcon == nullptr) {
  437. evhttp_request_free(request);
  438. return;
  439. }
  440. #ifdef _EVENT_USE_OPENSSL
  441. skip_sync = evhttp_is_connection_ssl(request->evcon);
  442. #endif
  443. int totalSize = 0;
  444. if (RuntimeOption::LibEventSyncSend && !skip_sync) {
  445. auto const& reasonStr = transport->getResponseInfo();
  446. const char* reason = reasonStr.empty() ? HttpProtocol::GetReasonString(code)
  447. : reasonStr.c_str();
  448. timespec begin, end;
  449. Timer::GetMonotonicTime(begin);
  450. #ifdef EVHTTP_SYNC_SEND_REPORT_TOTAL_LEN
  451. nwritten = evhttp_send_reply_sync(request, code, reason, nullptr, &totalSize);
  452. #else
  453. nwritten = evhttp_send_reply_sync_begin(request, code, reason, nullptr);
  454. #endif
  455. Timer::GetMonotonicTime(end);
  456. int64_t delay = gettime_diff_us(begin, end);
  457. transport->onFlushBegin(totalSize);
  458. transport->onFlushProgress(nwritten, delay);
  459. }
  460. m_responseQueue.enqueue(worker, request, code, nwritten);
  461. }
  462. void LibEventServer::onChunkedResponse(int worker, evhttp_request *request,
  463. int code, evbuffer *chunk,
  464. bool firstChunk) {
  465. m_responseQueue.enqueue(worker, request, code, chunk, firstChunk);
  466. }
  467. void LibEventServer::onChunkedResponseEnd(int worker,
  468. evhttp_request *request) {
  469. m_responseQueue.enqueue(worker, request);
  470. }
  471. LibEventServer::RequestPriority LibEventServer::getRequestPriority(
  472. struct evhttp_request* request) {
  473. std::string command = URL::getCommand(URL::getServerObject(request->uri));
  474. if (RuntimeOption::ServerHighPriorityEndPoints.find(command) ==
  475. RuntimeOption::ServerHighPriorityEndPoints.end()) {
  476. return PRIORITY_NORMAL;
  477. }
  478. return PRIORITY_HIGH;
  479. }
  480. ///////////////////////////////////////////////////////////////////////////////
  481. // PendingResponseQueue
  482. PendingResponseQueue::PendingResponseQueue() {
  483. assert(RuntimeOption::ResponseQueueCount > 0);
  484. for (int i = 0; i < RuntimeOption::ResponseQueueCount; i++) {
  485. m_responseQueues.push_back(std::make_shared<ResponseQueue>());
  486. }
  487. }
  488. bool PendingResponseQueue::empty() {
  489. for (int i = 0; i < RuntimeOption::ResponseQueueCount; i++) {
  490. ResponseQueue &q = *m_responseQueues[i];
  491. Lock lock(q.m_mutex);
  492. if (!q.m_responses.empty()) return false;
  493. }
  494. return true;
  495. }
  496. void PendingResponseQueue::create(event_base *eventBase) {
  497. if (!m_ready.open()) {
  498. throw FatalErrorException("unable to create pipe for ready signal");
  499. }
  500. event_set(&m_event, m_ready.getOut(), EV_READ|EV_PERSIST, on_response, this);
  501. event_base_set(eventBase, &m_event);
  502. event_add(&m_event, nullptr);
  503. }
  504. void PendingResponseQueue::close() {
  505. event_del(&m_event);
  506. }
  507. void PendingResponseQueue::enqueue(int worker,
  508. std::shared_ptr<Response> response) {
  509. {
  510. int i = worker % RuntimeOption::ResponseQueueCount;
  511. ResponseQueue &q = *m_responseQueues[i];
  512. Lock lock(q.m_mutex);
  513. q.m_responses.push_back(response);
  514. }
  515. // signal to call process()
  516. if (write(m_ready.getIn(), &response, 1) < 0) {
  517. // an error occurred but nothing we can really do
  518. }
  519. }
  520. void PendingResponseQueue::enqueue(int worker, evhttp_request *request,
  521. int code, int nwritten) {
  522. auto res = std::make_shared<Response>();
  523. res->request = request;
  524. res->code = code;
  525. res->nwritten = nwritten;
  526. enqueue(worker, res);
  527. }
  528. void PendingResponseQueue::enqueue(int worker, evhttp_request *request,
  529. int code, evbuffer *chunk,
  530. bool firstChunk) {
  531. auto res = std::make_shared<Response>();
  532. res->request = request;
  533. res->code = code;
  534. res->chunked = true;
  535. res->chunk = chunk;
  536. res->firstChunk = firstChunk;
  537. enqueue(worker, res);
  538. }
  539. void PendingResponseQueue::enqueue(int worker, evhttp_request *request) {
  540. auto res = std::make_shared<Response>();
  541. res->request = request;
  542. res->chunked = true;
  543. enqueue(worker, res);
  544. }
  545. void PendingResponseQueue::process() {
  546. // clean up the pipe for next signals
  547. char buf[512];
  548. if (read(m_ready.getOut(), buf, sizeof(buf)) < 0) {
  549. // an error occurred but nothing we can really do
  550. }
  551. // making a copy so we don't hold up the mutex very long
  552. std::vector<std::shared_ptr<Response>> responses;
  553. for (int i = 0; i < RuntimeOption::ResponseQueueCount; i++) {
  554. ResponseQueue &q = *m_responseQueues[i];
  555. Lock lock(q.m_mutex);
  556. responses.insert(responses.end(),
  557. q.m_responses.begin(), q.m_responses.end());
  558. q.m_responses.clear();
  559. }
  560. for (unsigned int i = 0; i < responses.size(); i++) {
  561. Response &res = *responses[i];
  562. evhttp_request *request = res.request;
  563. int code = res.code;
  564. if (request->evcon == nullptr) {
  565. evhttp_request_free(request);
  566. continue;
  567. }
  568. bool skip_sync = false;
  569. #ifdef _EVENT_USE_OPENSSL
  570. skip_sync = evhttp_is_connection_ssl(request->evcon);
  571. #endif
  572. if (res.chunked) {
  573. if (res.chunk) {
  574. if (res.firstChunk) {
  575. const char *reason = HttpProtocol::GetReasonString(code);
  576. evhttp_send_reply_start(request, code, reason);
  577. }
  578. evhttp_send_reply_chunk(request, res.chunk);
  579. } else {
  580. evhttp_send_reply_end(request);
  581. }
  582. } else if (RuntimeOption::LibEventSyncSend && !skip_sync) {
  583. evhttp_send_reply_sync_end(res.nwritten, request);
  584. } else {
  585. const char *reason = HttpProtocol::GetReasonString(code);
  586. evhttp_send_reply(request, code, reason, nullptr);
  587. }
  588. }
  589. }
  590. PendingResponseQueue::Response::Response()
  591. : request(nullptr), code(0), nwritten(0),
  592. chunked(false), firstChunk(false), chunk(nullptr) {
  593. }
  594. PendingResponseQueue::Response::~Response() {
  595. if (chunk) {
  596. evbuffer_free(chunk);
  597. }
  598. }
  599. ///////////////////////////////////////////////////////////////////////////////
  600. }