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
}
Пример #2
0
void HTTPTransaction::onIngressBody(unique_ptr<IOBuf> chain,
                                    uint16_t padding) {
  DestructorGuard g(this);
  if (isIngressEOMSeen()) {
    sendAbort(ErrorCode::STREAM_CLOSED);
    return;
  }
  auto len = chain->computeChainDataLength();
  if (len == 0) {
    return;
  }
  if (!validateIngressStateTransition(
        HTTPTransactionIngressSM::Event::onBody)) {
    return;
  }
  if (expectedContentLengthRemaining_.hasValue()) {
    if (expectedContentLengthRemaining_.value() >= len) {
      expectedContentLengthRemaining_ =
        expectedContentLengthRemaining_.value() - len;
    } else {
      auto errorMsg = folly::to<std::string>(
          "Content-Length/body mismatch: received=",
          len,
          " expecting no more than ",
          expectedContentLengthRemaining_.value());
      LOG(ERROR) << *this << " " << errorMsg;
      if (handler_) {
        HTTPException ex(HTTPException::Direction::INGRESS, errorMsg);
        ex.setProxygenError(kErrorParseBody);
        onError(ex);
      }
      return;
    }
  }
  if (transportCallback_) {
    transportCallback_->bodyBytesReceived(len);
  }
  if (mustQueueIngress()) {
    // register the bytes in the receive window
    if (!recvWindow_.reserve(len + padding, useFlowControl_)) {
      LOG(ERROR) << *this << " recvWindow_.reserve failed with len=" << len <<
        " padding=" << padding << " capacity=" << recvWindow_.getCapacity() <<
        " outstanding=" << recvWindow_.getOutstanding();
      sendAbort(ErrorCode::FLOW_CONTROL_ERROR);
    } else {
      CHECK(recvWindow_.free(padding));
      recvToAck_ += padding;
      checkCreateDeferredIngress();
      deferredIngress_->emplace(id_, HTTPEvent::Type::BODY,
                               std::move(chain));
      VLOG(4) << *this << " Queued ingress event of type " <<
        HTTPEvent::Type::BODY << " size=" << len;
    }
  } else {
    processIngressBody(std::move(chain), len);
  }
}
void BehaviorNotification::abort()
{   
    //set confirmation to be parented to this so it is deleted with rest of notification
    ui->confirmation_widget_->setParent(this);

    Q_EMIT sendAbort(ui->action_label_->text(), goal_id_);
}
TEST_F(ProxygenTransportTest, push_abort_incomplete) {
  // Push a resource
  Array headers;
  uint8_t pri = 1;

  headers.add(String("hello"), String("world"));  // dict serializtion path
  pushResource(headers, pri);

  // Creates a new transaction and sends headers, but not body
  MockHTTPTransaction pushTxn(TransportDirection::DOWNSTREAM,
                              HTTPCodec::StreamID(1), 1, m_egressQueue,
                              WheelTimerInstance(m_timeouts.get()));
  HTTPPushTransactionHandler* pushHandler = nullptr;
  expectPushPromiseAndHeaders(pushTxn, pri, &pushHandler);
  m_server.deliverMessages();
  sendResponse("12345");

  EXPECT_CALL(pushTxn, sendAbort())
    .WillOnce(Invoke([pushHandler] {
          pushHandler->detachTransaction();
        }));
  // Simulate termination of the VM thread while there is an incomplete push
  // This aborts the incomplete push
  TearDown();
}
void TpReceiveTransaction::getConsecutiveFrame(ConsecutiveFrame frame)
{
    if (state == PROGRESS)
    {
        timer.stop();
        std::vector<byte> v = frame.getData();
        if ( (++consecutiveFrameCounter & 0x0F) == frame.getIndex() )
        {
            buffer.insert(pointer, v.begin(), (buffLength -  std::distance(buffer.begin(), pointer)) > 7 ?
                              v.end() : v.begin() + buffLength -  std::distance(buffer.begin(), pointer));
            pointer = buffer.end();
            consIndex++;
            if ((buffer.size() < buffLength) && (blockSize == consIndex))
                readyFlowControl();
            else
                timer.start(5000);
            if ((buffer.size() == buffLength))
            {
                timer.stop();
                state = INIT;
                emit transactionReaceived(buffer);
            }
        }
        else
        {
            state = BROKEN;
            sendAbort();
            //LOG_WRITER.write(QString(tr("IsoTp последовательность нарушена. Ожидался фрейм с индексом %1, а получен - с индексом %2")).
//                             arg(consecutiveFrameCounter & 0x0F).
//                             arg(frame.getIndex()), QColor(255, 0, 255), 1);
        }
    }
    else if (state == INIT)
    {
        //LOG_WRITER.write(tr("Неожиданный ConsecutiveFrame"), QColor(255, 0, 0), 1);
        state = BROKEN;
        sendAbort();
    }
    else if (state == BROKEN)
    {
        // silent
    }
}
void DebuggerMagager::abort() //abort execution
{
    if (ConfigVariable::getPauseLevel() != 0)
    {
        //inform debuggers
        sendAbort();

        throw ast::InternalAbort();
    }
}
Пример #7
0
void HTTPTransaction::onIngressSetSendWindow(const uint32_t newWindowSize) {
  if (!useFlowControl_) {
    return;
  }
  updateReadTimeout();
  if (sendWindow_.setCapacity(newWindowSize)) {
    notifyTransportPendingEgress();
  } else {
    LOG(ERROR) << *this << "sendWindow_.setCapacity failed with newWindowSize="
               << newWindowSize << " capacity=" << sendWindow_.getCapacity()
               << " outstanding=" << sendWindow_.getOutstanding();
    sendAbort(ErrorCode::FLOW_CONTROL_ERROR);
  }
}
Пример #8
0
void HTTPTransaction::onIngressWindowUpdate(const uint32_t amount) {
  if (!useFlowControl_) {
    return;
  }
  DestructorGuard g(this);
  VLOG(4) << *this << " Remote side ack'd " << amount << " bytes";
  updateReadTimeout();
  if (sendWindow_.free(amount)) {
    notifyTransportPendingEgress();
  } else {
    LOG(ERROR) << *this << "sendWindow_.free failed with amount=" << amount <<
      " capacity=" << sendWindow_.getCapacity() <<
      " outstanding=" << sendWindow_.getOutstanding();
    sendAbort(ErrorCode::FLOW_CONTROL_ERROR);
  }
}
Пример #9
0
void HTTPTransaction::onIngressEOM() {
  if (isIngressEOMSeen()) {
    // This can happen when HTTPSession calls onIngressEOF()
    sendAbort(ErrorCode::STREAM_CLOSED);
    return;
  }
  if (expectedContentLengthRemaining_.hasValue() &&
      expectedContentLengthRemaining_.value() > 0) {
    auto errorMsg = folly::to<std::string>(
        "Content-Length/body mismatch: expecting another ",
        expectedContentLengthRemaining_.value());
    LOG(ERROR) << *this << " " << errorMsg;
    if (handler_) {
      HTTPException ex(HTTPException::Direction::INGRESS, errorMsg);
      ex.setProxygenError(kErrorParseBody);
      onError(ex);
    }
    return;
  }

  // TODO: change the codec to not give an EOM callback after a 100 response?
  // We could then delete the below 'if'
  if (isUpstream() && extraResponseExpected()) {
    VLOG(4) << "Ignoring EOM on initial 100 response on " << *this;
    return;
  }
  if (!validateIngressStateTransition(
        HTTPTransactionIngressSM::Event::onEOM)) {
    return;
  }
  // We need to update the read timeout here.  We're not likely to be
  // expecting any more ingress, and the timer should be cancelled
  // immediately.  If we are expecting more, this will reset the timer.
  updateReadTimeout();
  if (mustQueueIngress()) {
    checkCreateDeferredIngress();
    deferredIngress_->emplace(id_, HTTPEvent::Type::MESSAGE_COMPLETE);
    VLOG(4) << *this << " Queued ingress event of type " <<
      HTTPEvent::Type::MESSAGE_COMPLETE;
  } else {
    processIngressEOM();
  }
}
void TpReceiveTransaction::getFirstFrame(FirstFrame frame)
{
    if (state == INIT || state == BROKEN)
    {
        timer.stop();
        state = PROGRESS;
        buffer.clear();
        buffLength = frame.getPacketSize();
        consecutiveFrameCounter = 0;
        std::vector<byte> v = frame.getData();
        pointer = buffer.begin();
        buffer.insert(pointer, v.begin(), v.end());
        pointer = buffer.end();
        readyFlowControl();
    }
    else if (state == PROGRESS)
    {
        //LOG_WRITER.write(tr("Неожиданный FirstFrame"), QColor(255, 0, 255), 1);
        state = BROKEN;
        sendAbort();
    }
}
Пример #11
0
void ProxygenTransport::messageAvailable(ResponseMessage&& message) {
  if (!m_clientTxn) {
    return;
  }

  HTTPMessage *msg = nullptr;
  bool newPushOk = (message.m_type == ResponseMessage::Type::HEADERS);
  HTTPTransaction *txn = getTransaction(message.m_pushId, &msg, newPushOk);
  if (!txn) {
    // client is gone, just eat the msg
    return;
  }
  switch (message.m_type) {
    case ResponseMessage::Type::HEADERS:
      CHECK(msg);
      txn->sendHeaders(*msg);
      if (!message.m_chunk && !message.m_eom) {
        break;
      } // else fall through
    case ResponseMessage::Type::BODY:
      if (message.m_chunk && m_method != Transport::Method::HEAD) {
        // TODO: experiment with disabling this chunked flag and letting
        // proxygen framework do the chunking
        if (message.m_chunked) {
          txn->sendChunkHeader(message.m_chunk->length());
          txn->sendBody(std::move(message.m_chunk));
          txn->sendChunkTerminator();
        } else {
          txn->sendBody(std::move(message.m_chunk));
        }
      }
      if (!message.m_eom) {
        break;
      } // else fall through
    case ResponseMessage::Type::EOM:
      cancelTimeout();
      txn->sendEOM();
      break;
    case ResponseMessage::Type::FINISH:
      // need to make sure the last reference is deleted in this thread

      // The VM thread is done, any outstanding push txns need aborts.
      // It's possible that we could drive pushes from somewhere other
      // than the VM thread, in which case we'll need a different saftey
      // mechanism
      {
        Lock lock(this);
        for (auto& it: m_pushHandlers) {
          auto pushTxn = it.second->getTransaction();
          if (pushTxn && !pushTxn->isEgressEOMSeen()) {
            LOG(ERROR) << "Aborting unfinished push txn=" << *pushTxn;
            pushTxn->sendAbort();
          }
        }
      }
      break;
    case ResponseMessage::Type::RESUME_INGRESS:
      txn->resumeIngress();
      break;
  }
}
Пример #12
0
void HTTPTransaction::sendAbort() {
  sendAbort(isUpstream() ? ErrorCode::CANCEL
                         : ErrorCode::INTERNAL_ERROR);
}
Пример #13
0
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);
  }
}
void TpReceiveTransaction::timeout()
{
    timer.stop();
    sendAbort();
    emit watingTimeOut();
}