proxygen/httpserver/RequestHandlerAdaptor.cpp (190 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ #include <proxygen/httpserver/RequestHandlerAdaptor.h> #include <folly/Range.h> #include <proxygen/httpserver/ExMessageHandler.h> #include <proxygen/httpserver/PushHandler.h> #include <proxygen/httpserver/RequestHandler.h> #include <proxygen/httpserver/ResponseBuilder.h> namespace proxygen { RequestHandlerAdaptor::RequestHandlerAdaptor(RequestHandler* requestHandler) : ResponseHandler(requestHandler) { } void RequestHandlerAdaptor::setTransaction(HTTPTransaction* txn) noexcept { txn_ = txn; // We become that transparent layer upstream_->setResponseHandler(this); } void RequestHandlerAdaptor::detachTransaction() noexcept { if (upstream_) { auto upstream = upstream_; upstream_ = nullptr; upstream->requestComplete(); } // Otherwise we would have got some error call back and invoked onError // on RequestHandler delete this; } namespace { constexpr folly::StringPiece k100Continue{"100-continue"}; } // namespace void RequestHandlerAdaptor::onHeadersComplete( std::unique_ptr<HTTPMessage> msg) noexcept { if (!upstream_) { return; } if (msg->getHeaders().exists(HTTP_HEADER_EXPECT) && !upstream_->canHandleExpect()) { auto expectation = msg->getHeaders().getSingleOrEmpty(HTTP_HEADER_EXPECT); if (!k100Continue.equals(expectation, folly::AsciiCaseInsensitive())) { setError(kErrorUnsupportedExpectation); ResponseBuilder(this) .status(417, "Expectation Failed") .closeConnection() .sendWithEOM(); } else { ResponseBuilder(this).status(100, "Continue").send(); } } if (upstream_) { upstream_->onRequest(std::move(msg)); } } void RequestHandlerAdaptor::onBody(std::unique_ptr<folly::IOBuf> c) noexcept { if (!upstream_) { return; } upstream_->onBody(std::move(c)); } void RequestHandlerAdaptor::onChunkHeader(size_t /*length*/) noexcept { } void RequestHandlerAdaptor::onChunkComplete() noexcept { } void RequestHandlerAdaptor::onTrailers( std::unique_ptr<HTTPHeaders> /*trailers*/) noexcept { // XXX: Support trailers } void RequestHandlerAdaptor::onEOM() noexcept { if (!upstream_) { return; } upstream_->onEOM(); } void RequestHandlerAdaptor::onUpgrade(UpgradeProtocol protocol) noexcept { if (!upstream_) { return; } upstream_->onUpgrade(protocol); } void RequestHandlerAdaptor::onError(const HTTPException& error) noexcept { if (!upstream_) { return; } if (error.getProxygenError() == kErrorTimeout) { setError(kErrorTimeout); if (!txn_->canSendHeaders()) { sendAbort(); } else { ResponseBuilder(this) .status(408, "Request Timeout") .closeConnection() .sendWithEOM(); } } else if (error.getDirection() == HTTPException::Direction::INGRESS) { setError(kErrorRead); if (!txn_->canSendHeaders()) { sendAbort(); } else { ResponseBuilder(this) .status(400, "Bad Request") .closeConnection() .sendWithEOM(); } } else { setError(error.hasProxygenError() ? error.getProxygenError() : kErrorWrite); } // Wait for detachTransaction to clean up } void RequestHandlerAdaptor::onGoaway(ErrorCode code) noexcept { if (!upstream_) { return; } upstream_->onGoaway(code); } void RequestHandlerAdaptor::onEgressPaused() noexcept { if (!upstream_) { return; } upstream_->onEgressPaused(); } void RequestHandlerAdaptor::onEgressResumed() noexcept { if (!upstream_) { return; } upstream_->onEgressResumed(); } void RequestHandlerAdaptor::onExTransaction(HTTPTransaction* txn) noexcept { if (!upstream_) { return; } // Create handler for child EX transaction. auto handler = new RequestHandlerAdaptor(upstream_->getExHandler()); txn->setHandler(handler); } void RequestHandlerAdaptor::sendHeaders(HTTPMessage& msg) noexcept { txn_->sendHeaders(msg); } void RequestHandlerAdaptor::sendChunkHeader(size_t len) noexcept { txn_->sendChunkHeader(len); } void RequestHandlerAdaptor::sendBody(std::unique_ptr<folly::IOBuf> b) noexcept { txn_->sendBody(std::move(b)); } void RequestHandlerAdaptor::sendChunkTerminator() noexcept { txn_->sendChunkTerminator(); } void RequestHandlerAdaptor::sendEOM() noexcept { txn_->sendEOM(); } void RequestHandlerAdaptor::sendAbort() noexcept { txn_->sendAbort(); } void RequestHandlerAdaptor::refreshTimeout() noexcept { txn_->refreshTimeout(); } void RequestHandlerAdaptor::pauseIngress() noexcept { txn_->pauseIngress(); } void RequestHandlerAdaptor::resumeIngress() noexcept { txn_->resumeIngress(); } folly::Expected<ResponseHandler*, ProxygenError> RequestHandlerAdaptor::newPushedResponse(PushHandler* pushHandler) noexcept { ProxygenError error; auto pushTxn = txn_->newPushedTransaction(pushHandler->getHandler(), &error); if (!pushTxn) { // Codec doesn't support push VLOG(4) << "Failed to create newPushedResponse: " << static_cast<uint8_t>(error) << " " << getErrorString(error); return folly::makeUnexpected(error); } auto pushHandlerAdaptor = new RequestHandlerAdaptor(pushHandler); if (!pushHandlerAdaptor) { VLOG(4) << "Failed to create RequestHandlerAdaptor!"; return folly::makeUnexpected(kErrorUnknown); } pushHandlerAdaptor->setTransaction(pushTxn); return pushHandlerAdaptor; } ResponseHandler* RequestHandlerAdaptor::newExMessage( ExMessageHandler* exHandler, bool unidirectional) noexcept { RequestHandlerAdaptor* handler = new RequestHandlerAdaptor(exHandler); getTransaction()->newExTransaction(handler, unidirectional); return handler; } const wangle::TransportInfo& RequestHandlerAdaptor::getSetupTransportInfo() const noexcept { return txn_->getSetupTransportInfo(); } void RequestHandlerAdaptor::getCurrentTransportInfo( wangle::TransportInfo* tinfo) const { txn_->getCurrentTransportInfo(tinfo); } void RequestHandlerAdaptor::setError(ProxygenError err) noexcept { err_ = err; auto upstream = upstream_; upstream_ = nullptr; upstream->onError(err); } } // namespace proxygen