/*
* Copyright 2017 Sony Corporation
*/
#include "easyhttpcpp/common/CoreLogger.h"
#include "easyhttpcpp/common/StringUtil.h"
#include "easyhttpcpp/HttpException.h"
#include "easyhttpcpp/Interceptor.h"
#include "CallInterceptorChain.h"
#include "HttpRequestExecutor.h"
#include "ResponseBodyStreamInternal.h"
using easyhttpcpp::common::StringUtil;
namespace easyhttpcpp {
static const std::string Tag = "HttpRequestExecutor";
static const int MaxRetryCount = 5;
HttpRequestExecutor::HttpRequestExecutor(EasyHttpContext::Ptr pContext, Request::Ptr pRequest) : m_pContext(pContext),
m_pUserRequest(pRequest), m_cancelled(false)
{
}
HttpRequestExecutor::~HttpRequestExecutor()
{
}
Response::Ptr HttpRequestExecutor::execute()
{
EasyHttpContext::InterceptorList& callInterceptors = m_pContext->getCallInterceptors();
EasyHttpContext::InterceptorList::iterator it = callInterceptors.begin();
EasyHttpContext::InterceptorList::const_iterator itEnd = callInterceptors.end();
if (it == itEnd) {
return executeWithRetry(m_pUserRequest);
} else {
CallInterceptorChain::Ptr chain(new CallInterceptorChain(HttpRequestExecutor::Ptr(this, true), m_pUserRequest,
it, itEnd));
return (*it)->intercept(*chain);
}
}
Response::Ptr HttpRequestExecutor::executeAfterIntercept(Request::Ptr pRequest)
{
return executeWithRetry(pRequest);
}
bool HttpRequestExecutor::cancel()
{
Poco::FastMutex::ScopedLock lock(m_cancelMutex);
EASYHTTPCPP_LOG_D(Tag, "cancel: cancelled");
m_cancelled = true;
bool ret = true;
if (m_pHttpEngine) {
if (!m_pHttpEngine->cancel()) {
ret = false;
}
}
if (m_pUserResponse) {
ResponseBody::Ptr pResponseBody = m_pUserResponse->getBody();
if (pResponseBody) {
ResponseBodyStream::Ptr pResponseBodyStream = pResponseBody->getByteStream();
if (pResponseBodyStream) {
// When call the ResponseBodyStream::close, ResponseBodyStream::read will fail.
// If you have not read to the end, not also written to the cache.
EASYHTTPCPP_LOG_D(Tag, "cancel: close stream");
pResponseBodyStream->close();
}
}
}
return ret;
}
bool HttpRequestExecutor::isCancelled() const
{
return m_cancelled;
}
HttpEngine::Ptr HttpRequestExecutor::getHttpEngine()
{
return m_pHttpEngine;
}
Response::Ptr HttpRequestExecutor::executeWithRetry(Request::Ptr pRequest)
{
Response::Ptr pPriorResponse;
Request::Ptr pCurrentRequest = pRequest;
int retryCount = 0;
do {
{
Poco::FastMutex::ScopedLock lock(m_cancelMutex);
if (m_cancelled) {
EASYHTTPCPP_LOG_D(Tag, "executeWithRetry: request is cancelled before create HttpEngine.");
throw HttpExecutionException("http request is cancelled.");
}
m_pHttpEngine = new HttpEngine(m_pContext, pCurrentRequest, pPriorResponse);
}
Response::Ptr pUserResponse = m_pHttpEngine->execute();
// check retry
Request::Ptr pRetryRequest = HttpEngine::getRetryRequest(pUserResponse);
if (pRetryRequest) {
m_pHttpEngine->readAllResponseBodyForCache(pUserResponse);
pPriorResponse = pUserResponse;
pCurrentRequest = pRetryRequest;
retryCount++;
continue;
}
{
Poco::FastMutex::ScopedLock lock(m_cancelMutex);
m_pUserResponse = pUserResponse;
}
return m_pUserResponse;
} while (retryCount