void RequestHandlerAdaptor::onError(const HTTPException& error) noexcept { if (err_ != kErrorNone) { // we have already handled an error and upstream would have been deleted return; } if (error.getProxygenError() == kErrorTimeout) { setError(kErrorTimeout); if (responseStarted_) { sendAbort(); } else { ResponseBuilder(this) .status(408, "Request Timeout") .closeConnection() .sendWithEOM(); } } else if (error.getDirection() == HTTPException::Direction::INGRESS) { setError(kErrorRead); if (responseStarted_) { sendAbort(); } else { ResponseBuilder(this) .status(400, "Bad Request") .closeConnection() .sendWithEOM(); } } else { setError(kErrorWrite); } // Wait for detachTransaction to clean up }
void HTTPTransaction::onError(const HTTPException& error) { DestructorGuard g(this); const bool wasAborted = aborted_; // see comment below const bool wasEgressComplete = isEgressComplete(); const bool wasIngressComplete = isIngressComplete(); bool notify = (handler_); HTTPException::Direction direction = error.getDirection(); if (direction == HTTPException::Direction::INGRESS && isIngressEOMSeen() && isExpectingWindowUpdate()) { // we got an ingress error, we've seen the entire message, but we're // expecting more (window updates). These aren't coming, convert to // INGRESS_AND_EGRESS VLOG(4) << *this << " Converting ingress error to ingress+egress due to" " flow control, and aborting"; direction = HTTPException::Direction::INGRESS_AND_EGRESS; sendAbort(ErrorCode::FLOW_CONTROL_ERROR); } if (error.getProxygenError() == kErrorStreamAbort) { DCHECK(error.getDirection() == HTTPException::Direction::INGRESS_AND_EGRESS); aborted_ = true; } else if (error.hasCodecStatusCode()) { DCHECK(error.getDirection() == HTTPException::Direction::INGRESS_AND_EGRESS); sendAbort(error.getCodecStatusCode()); } switch (direction) { case HTTPException::Direction::INGRESS_AND_EGRESS: markEgressComplete(); markIngressComplete(); if (wasEgressComplete && wasIngressComplete && // We mark egress complete before we get acknowledgement of the // write segment finishing successfully. // TODO: instead of using DestructorGuard hacks to keep txn around, // use an explicit callback function and set egress complete after // last byte flushes (or egress error occurs), see #3912823 (error.getProxygenError() != kErrorWriteTimeout || wasAborted)) { notify = false; } break; case HTTPException::Direction::EGRESS: markEgressComplete(); if (!wasEgressComplete && isIngressEOMSeen() && ingressErrorSeen_) { // we've already seen an ingress error but we ignored it, hoping the // handler would resume and read our queued EOM. Now both sides are // dead and we need to kill this transaction. markIngressComplete(); } if (wasEgressComplete) { notify = false; } break; case HTTPException::Direction::INGRESS: if (isIngressEOMSeen()) { // Not an error, for now ingressErrorSeen_ = true; return; } markIngressComplete(); if (wasIngressComplete) { notify = false; } break; } if (notify && handler_) { // mark egress complete may result in handler detaching handler_->onError(error); } }