%PDF- %PDF-
Direktori : /opt/cpanel/ea-ruby27/src/passenger-release-6.0.23/src/agent/Core/Controller/ |
Current File : //opt/cpanel/ea-ruby27/src/passenger-release-6.0.23/src/agent/Core/Controller/Hooks.cpp |
/* * Phusion Passenger - https://www.phusionpassenger.com/ * Copyright (c) 2011-2017 Phusion Holding B.V. * * "Passenger", "Phusion Passenger" and "Union Station" are registered * trademarks of Phusion Holding B.V. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include <Core/Controller.h> /************************************************************************* * * Hook functions for Core::Controller. This pertains the hooks that the * parent classes (ServerKit::HttpServer and ServerKit::Server) provide, * as well as hooks by libraries such as libev. * *************************************************************************/ namespace Passenger { namespace Core { using namespace std; using namespace boost; /**************************** * * Private methods * ****************************/ ServerKit::Channel::Result Controller::onBodyBufferData(Channel *_channel, const MemoryKit::mbuf &buffer, int errcode) { FileBufferedChannel *channel = reinterpret_cast<FileBufferedChannel *>(_channel); Request *req = static_cast<Request *>(static_cast< ServerKit::BaseHttpRequest *>(channel->getHooks()->userData)); Client *client = static_cast<Client *>(req->client); Controller *self = static_cast<Controller *>(getServerFromClient(client)); SKC_LOG_EVENT_FROM_STATIC(self, Controller, client, "onBodyBufferData"); assert(req->requestBodyBuffering); return self->whenSendingRequest_onRequestBody(client, req, buffer, errcode); } #ifdef DEBUG_CC_EVENT_LOOP_BLOCKING void Controller::onEventLoopPrepare(EV_P_ struct ev_prepare *w, int revents) { Controller *self = static_cast<Controller *>(w->data); ev_now_update(EV_A); self->timeBeforeBlocking = ev_now(EV_A); } #endif void Controller::onEventLoopCheck(EV_P_ struct ev_check *w, int revents) { Controller *self = static_cast<Controller *>(w->data); self->turboCaching.updateState(ev_now(EV_A)); #ifdef DEBUG_CC_EVENT_LOOP_BLOCKING self->reportLargeTimeDiff(NULL, "Event loop slept", self->timeBeforeBlocking, ev_now(EV_A)); #endif } /**************************** * * Protected methods * ****************************/ void Controller::onClientAccepted(Client *client) { ParentClass::onClientAccepted(client); client->connectedAt = ev_now(getLoop()); } void Controller::onRequestObjectCreated(Client *client, Request *req) { ParentClass::onRequestObjectCreated(client, req); req->appSink.setContext(getContext()); req->appSink.setHooks(&req->hooks); req->appSource.setContext(getContext()); req->appSource.setHooks(&req->hooks); req->appSource.setDataCallback(_onAppSourceData); req->bodyBuffer.setContext(getContext()); req->bodyBuffer.setHooks(&req->hooks); req->bodyBuffer.setDataCallback(onBodyBufferData); } void Controller::deinitializeClient(Client *client) { ParentClass::deinitializeClient(client); client->output.clearBuffersFlushedCallback(); client->output.setDataFlushedCallback(getClientOutputDataFlushedCallback()); } void Controller::reinitializeRequest(Client *client, Request *req) { ParentClass::reinitializeRequest(client, req); // bodyBuffer is initialized in Controller::beginBufferingBody(). // appSink and appSource are initialized in Controller::checkoutSession(). req->startedAt = 0; req->state = Request::ANALYZING_REQUEST; req->dechunkResponse = false; req->requestBodyBuffering = false; req->https = false; req->stickySession = false; req->sessionCheckoutTry = 0; req->halfClosePolicy = Request::HALF_CLOSE_POLICY_UNINITIALIZED; req->appResponseInitialized = false; req->strip100ContinueHeader = false; req->hasPragmaHeader = false; req->host = NULL; req->config = requestConfig; req->bodyBytesBuffered = 0; req->cacheKey = HashedStaticString(); req->cacheControl = NULL; req->varyCookie = NULL; req->envvars = NULL; #ifdef DEBUG_CC_EVENT_LOOP_BLOCKING req->timedAppPoolGet = false; req->timeBeforeAccessingApplicationPool = 0; req->timeOnRequestHeaderSent = 0; req->timeOnResponseBegun = 0; #endif /***************/ } void Controller::deinitializeRequest(Client *client, Request *req) { req->session.reset(); req->config.reset(); req->appSink.setConsumedCallback(NULL); req->appSink.deinitialize(); req->appSource.deinitialize(); req->bodyBuffer.clearBuffersFlushedCallback(); req->bodyBuffer.deinitialize(); /***************/ /***************/ if (req->appResponseInitialized) { deinitializeAppResponse(client, req); } ParentClass::deinitializeRequest(client, req); } void Controller::reinitializeAppResponse(Client *client, Request *req) { AppResponse *resp = &req->appResponse; req->appResponseInitialized = true; resp->httpMajor = 1; resp->httpMinor = 0; resp->httpState = AppResponse::PARSING_HEADERS; resp->bodyType = AppResponse::RBT_NO_BODY; resp->wantKeepAlive = false; resp->oneHundredContinueSent = false; resp->statusCode = 0; resp->parserState.headerParser = getHeaderParserStatePool().construct(); createAppResponseHeaderParser(getContext(), req).initialize(); resp->aux.bodyInfo.contentLength = 0; // Sets the entire union to 0. resp->bodyAlreadyRead = 0; resp->date = NULL; resp->setCookie = NULL; resp->cacheControl = NULL; resp->expiresHeader = NULL; resp->lastModifiedHeader = NULL; resp->headerCacheBuffers = NULL; resp->nHeaderCacheBuffers = 0; psg_lstr_init(&resp->bodyCacheBuffer); } void Controller::deinitializeAppResponse(Client *client, Request *req) { AppResponse *resp = &req->appResponse; req->appResponseInitialized = false; if (resp->httpState == AppResponse::PARSING_HEADERS && resp->parserState.headerParser != NULL) { getHeaderParserStatePool().destroy(resp->parserState.headerParser); resp->parserState.headerParser = NULL; } ServerKit::HeaderTable::Iterator it(resp->headers); while (*it != NULL) { psg_lstr_deinit(&it->header->key); psg_lstr_deinit(&it->header->origKey); psg_lstr_deinit(&it->header->val); it.next(); } it = ServerKit::HeaderTable::Iterator(resp->secureHeaders); while (*it != NULL) { psg_lstr_deinit(&it->header->key); psg_lstr_deinit(&it->header->origKey); psg_lstr_deinit(&it->header->val); it.next(); } resp->headers.clear(); resp->secureHeaders.clear(); if (resp->setCookie != NULL) { psg_lstr_deinit(resp->setCookie); } psg_lstr_deinit(&resp->bodyCacheBuffer); } ServerKit::Channel::Result Controller::onRequestBody(Client *client, Request *req, const MemoryKit::mbuf &buffer, int errcode) { switch (req->state) { case Request::BUFFERING_REQUEST_BODY: return whenBufferingBody_onRequestBody(client, req, buffer, errcode); case Request::FORWARDING_BODY_TO_APP: return whenSendingRequest_onRequestBody(client, req, buffer, errcode); default: P_BUG("Unknown state " << req->state); return Channel::Result(0, false); } } void Controller::onNextRequestEarlyReadError(Client *client, Request *req, int errcode) { ParentClass::onNextRequestEarlyReadError(client, req, errcode); if (req->halfClosePolicy == Request::HALF_CLOSE_UPON_NEXT_REQUEST_EARLY_READ_ERROR) { SKC_TRACE(client, 3, "Half-closing application socket with SHUT_WR" " because the next request's early read error has been detected: " << ServerKit::getErrorDesc(errcode) << " (errno=" << errcode << ")"); req->halfClosePolicy = Request::HALF_CLOSE_PERFORMED; assert(req->session != NULL); ::shutdown(req->session->fd(), SHUT_WR); } } bool Controller::shouldDisconnectClientOnShutdown(Client *client) { return ParentClass::shouldDisconnectClientOnShutdown(client) || !mainConfig.gracefulExit; } bool Controller::shouldAutoDechunkBody(Client *client, Request *req) { // When buffering the body, we'll want to buffer the dechunked data, // (and when passing the request to the app we'll also add Content-Length // and remove Transfer-Encoding) so turn auto-dechunking on in that case. // // Otherwise we'll want to disable auto-dechunking because we'll // pass the raw chunked body to the app. return req->requestBodyBuffering; } bool Controller::supportsUpgrade(Client *client, Request *req) { return true; } /**************************** * * Public methods * ****************************/ unsigned int Controller::getClientName(const Client *client, char *buf, size_t size) const { char *pos = buf; const char *end = buf + size - 1; // WARNING: If you change the format, be sure to change // ApiServer::extractThreadNumberFromClientName() too. pos += uintToString(mainConfig.threadNumber, pos, end - pos); pos = appendData(pos, end, "-", 1); pos += uintToString(client->number, pos, end - pos); *pos = '\0'; return pos - buf; } StaticString Controller::getServerName() const { return mainConfig.serverLogName; } } // namespace Core } // namespace Passenger