/* * Phusion Passenger - https://www.phusionpassenger.com/ * Copyright (c) 2011-2015 Phusion * * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui. * * 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. */ // This file is included inside the RequestHandler class. public: virtual unsigned int getClientName(const Client *client, char *buf, size_t size) const { char *pos = buf; const char *end = buf + size - 1; pos += uintToString(threadNumber, pos, end - pos); pos = appendData(pos, end, ".", 1); pos += uintToString(client->number, pos, end - pos); *pos = '\0'; return pos - buf; } virtual StaticString getServerName() const { return serverLogName; } protected: virtual void onClientAccepted(Client *client) { ParentClass::onClientAccepted(client); client->connectedAt = ev_now(getLoop()); } virtual void 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); } virtual void deinitializeClient(Client *client) { ParentClass::deinitializeClient(client); client->output.setBuffersFlushedCallback(NULL); client->output.setDataFlushedCallback(getClientOutputDataFlushedCallback()); } virtual void reinitializeRequest(Client *client, Request *req) { ParentClass::reinitializeRequest(client, req); // bodyBuffer is initialized in RequestHandler::beginBufferingBody(). // appSink and appSource are initialized in RequestHandler::checkoutSession(). req->startedAt = 0; req->state = Request::ANALYZING_REQUEST; req->dechunkResponse = false; req->requestBodyBuffering = false; req->https = false; req->stickySession = false; req->halfCloseAppConnection = false; req->sessionCheckoutTry = 0; req->strip100ContinueHeader = false; req->hasPragmaHeader = false; req->host = NULL; req->bodyBytesBuffered = 0; req->cacheKey = HashedStaticString(); req->cacheControl = NULL; req->varyCookie = NULL; #ifdef DEBUG_RH_EVENT_LOOP_BLOCKING req->timedAppPoolGet = false; req->timeBeforeAccessingApplicationPool = 0; req->timeOnRequestHeaderSent = 0; req->timeOnResponseBegun = 0; #endif /***************/ } virtual void deinitializeRequest(Client *client, Request *req) { req->session.reset(); req->endScopeLog(&req->scopeLogs.requestProxying, false); req->endScopeLog(&req->scopeLogs.getFromPool, false); req->endScopeLog(&req->scopeLogs.bufferingRequestBody, false); req->endScopeLog(&req->scopeLogs.requestProcessing, false); req->appSink.setConsumedCallback(NULL); req->appSink.deinitialize(); req->appSource.deinitialize(); req->bodyBuffer.deinitialize(); /***************/ /***************/ deinitializeAppResponse(client, req); ParentClass::deinitializeRequest(client, req); } void reinitializeAppResponse(Client *client, Request *req) { AppResponse *resp = &req->appResponse; 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 deinitializeAppResponse(Client *client, Request *req) { AppResponse *resp = &req->appResponse; 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->val); it.next(); } it = ServerKit::HeaderTable::Iterator(resp->secureHeaders); while (*it != NULL) { psg_lstr_deinit(&it->header->key); psg_lstr_deinit(&it->header->val); it.next(); } resp->headers.clear(); resp->secureHeaders.clear(); psg_lstr_deinit(&resp->bodyCacheBuffer); } virtual Channel::Result 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); } } virtual bool shouldDisconnectClientOnShutdown(Client *client) { return ParentClass::shouldDisconnectClientOnShutdown(client) || !gracefulExit; } private: static Channel::Result onBodyBufferData(Channel *_channel, const MemoryKit::mbuf &buffer, int errcode) { FileBufferedChannel *channel = reinterpret_cast(_channel); Request *req = static_cast(static_cast< ServerKit::BaseHttpRequest *>(channel->getHooks()->userData)); Client *client = static_cast(req->client); RequestHandler *self = static_cast(getServerFromClient(client)); SKC_LOG_EVENT_FROM_STATIC(self, RequestHandler, client, "onBodyBufferData"); assert(req->requestBodyBuffering); return self->whenSendingRequest_onRequestBody(client, req, buffer, errcode); } #ifdef DEBUG_RH_EVENT_LOOP_BLOCKING static void onEventLoopPrepare(EV_P_ struct ev_prepare *w, int revents) { RequestHandler *self = static_cast(w->data); ev_now_update(EV_A); self->timeBeforeBlocking = ev_now(EV_A); } #endif static void onEventLoopCheck(EV_P_ struct ev_check *w, int revents) { RequestHandler *self = static_cast(w->data); self->turboCaching.updateState(ev_now(EV_A)); #ifdef DEBUG_RH_EVENT_LOOP_BLOCKING self->reportLargeTimeDiff(NULL, "Event loop slept", self->timeBeforeBlocking, ev_now(EV_A)); #endif }