Allow to cancel asynchronous HTTP requests (#332)
Usage: auto args = this->httpClient.createRequest(url, method); httpClient.performRequest(args, ...); [...] // Oops, we don't actually want to complete the request! args->cancel = true;
This commit is contained in:
		| @@ -8,6 +8,7 @@ | ||||
|  | ||||
| #include "IXProgressCallback.h" | ||||
| #include "IXWebSocketHttpHeaders.h" | ||||
| #include <atomic> | ||||
| #include <tuple> | ||||
| #include <unordered_map> | ||||
|  | ||||
| @@ -30,6 +31,7 @@ namespace ix | ||||
|         TooManyRedirects = 12, | ||||
|         ChunkReadError = 13, | ||||
|         CannotReadBody = 14, | ||||
|         Cancelled = 15, | ||||
|         Invalid = 100 | ||||
|     }; | ||||
|  | ||||
| @@ -87,6 +89,7 @@ namespace ix | ||||
|         bool compressRequest = false; | ||||
|         Logger logger; | ||||
|         OnProgressCallback onProgressCallback; | ||||
|         std::atomic<bool> cancel; | ||||
|     }; | ||||
|  | ||||
|     using HttpRequestArgsPtr = std::shared_ptr<HttpRequestArgs>; | ||||
|   | ||||
| @@ -241,17 +241,21 @@ namespace ix | ||||
|         std::string errMsg; | ||||
|  | ||||
|         // Make a cancellation object dealing with connection timeout | ||||
|         auto isCancellationRequested = | ||||
|             makeCancellationRequestWithTimeout(args->connectTimeout, _stop); | ||||
|         auto cancelled = makeCancellationRequestWithTimeout(args->connectTimeout, args->cancel); | ||||
|  | ||||
|         auto isCancellationRequested = [&]() { | ||||
|             return cancelled() || _stop; | ||||
|         }; | ||||
|  | ||||
|         bool success = _socket->connect(host, port, errMsg, isCancellationRequested); | ||||
|         if (!success) | ||||
|         { | ||||
|             auto errorCode = args->cancel ? HttpErrorCode::Cancelled : HttpErrorCode::CannotConnect; | ||||
|             std::stringstream ss; | ||||
|             ss << "Cannot connect to url: " << url << " / error : " << errMsg; | ||||
|             return std::make_shared<HttpResponse>(code, | ||||
|                                                   description, | ||||
|                                                   HttpErrorCode::CannotConnect, | ||||
|                                                   errorCode, | ||||
|                                                   headers, | ||||
|                                                   payload, | ||||
|                                                   ss.str(), | ||||
| @@ -260,7 +264,7 @@ namespace ix | ||||
|         } | ||||
|  | ||||
|         // Make a new cancellation object dealing with transfer timeout | ||||
|         isCancellationRequested = makeCancellationRequestWithTimeout(args->transferTimeout, _stop); | ||||
|         cancelled = makeCancellationRequestWithTimeout(args->transferTimeout, args->cancel); | ||||
|  | ||||
|         if (args->verbose) | ||||
|         { | ||||
| @@ -277,10 +281,11 @@ namespace ix | ||||
|  | ||||
|         if (!_socket->writeBytes(req, isCancellationRequested)) | ||||
|         { | ||||
|             auto errorCode = args->cancel ? HttpErrorCode::Cancelled : HttpErrorCode::SendError; | ||||
|             std::string errorMsg("Cannot send request"); | ||||
|             return std::make_shared<HttpResponse>(code, | ||||
|                                                   description, | ||||
|                                                   HttpErrorCode::SendError, | ||||
|                                                   errorCode, | ||||
|                                                   headers, | ||||
|                                                   payload, | ||||
|                                                   errorMsg, | ||||
| @@ -296,10 +301,11 @@ namespace ix | ||||
|  | ||||
|         if (!lineValid) | ||||
|         { | ||||
|             auto errorCode = args->cancel ? HttpErrorCode::Cancelled : HttpErrorCode::CannotReadStatusLine; | ||||
|             std::string errorMsg("Cannot retrieve status line"); | ||||
|             return std::make_shared<HttpResponse>(code, | ||||
|                                                   description, | ||||
|                                                   HttpErrorCode::CannotReadStatusLine, | ||||
|                                                   errorCode, | ||||
|                                                   headers, | ||||
|                                                   payload, | ||||
|                                                   errorMsg, | ||||
| @@ -333,10 +339,11 @@ namespace ix | ||||
|  | ||||
|         if (!headersValid) | ||||
|         { | ||||
|             auto errorCode = args->cancel ? HttpErrorCode::Cancelled : HttpErrorCode::HeaderParsingError; | ||||
|             std::string errorMsg("Cannot parse http headers"); | ||||
|             return std::make_shared<HttpResponse>(code, | ||||
|                                                   description, | ||||
|                                                   HttpErrorCode::HeaderParsingError, | ||||
|                                                   errorCode, | ||||
|                                                   headers, | ||||
|                                                   payload, | ||||
|                                                   errorMsg, | ||||
| @@ -405,10 +412,11 @@ namespace ix | ||||
|                 contentLength, args->onProgressCallback, isCancellationRequested); | ||||
|             if (!chunkResult.first) | ||||
|             { | ||||
|                 auto errorCode = args->cancel ? HttpErrorCode::Cancelled : HttpErrorCode::ChunkReadError; | ||||
|                 errorMsg = "Cannot read chunk"; | ||||
|                 return std::make_shared<HttpResponse>(code, | ||||
|                                                       description, | ||||
|                                                       HttpErrorCode::ChunkReadError, | ||||
|                                                       errorCode, | ||||
|                                                       headers, | ||||
|                                                       payload, | ||||
|                                                       errorMsg, | ||||
| @@ -424,6 +432,7 @@ namespace ix | ||||
|  | ||||
|             while (true) | ||||
|             { | ||||
|                 auto errorCode = args->cancel ? HttpErrorCode::Cancelled : HttpErrorCode::ChunkReadError; | ||||
|                 lineResult = _socket->readLine(isCancellationRequested); | ||||
|                 line = lineResult.second; | ||||
|  | ||||
| @@ -431,7 +440,7 @@ namespace ix | ||||
|                 { | ||||
|                     return std::make_shared<HttpResponse>(code, | ||||
|                                                           description, | ||||
|                                                           HttpErrorCode::ChunkReadError, | ||||
|                                                           errorCode, | ||||
|                                                           headers, | ||||
|                                                           payload, | ||||
|                                                           errorMsg, | ||||
| @@ -458,10 +467,11 @@ namespace ix | ||||
|                     (size_t) chunkSize, args->onProgressCallback, isCancellationRequested); | ||||
|                 if (!chunkResult.first) | ||||
|                 { | ||||
|                     auto errorCode = args->cancel ? HttpErrorCode::Cancelled : HttpErrorCode::ChunkReadError; | ||||
|                     errorMsg = "Cannot read chunk"; | ||||
|                     return std::make_shared<HttpResponse>(code, | ||||
|                                                           description, | ||||
|                                                           HttpErrorCode::ChunkReadError, | ||||
|                                                           errorCode, | ||||
|                                                           headers, | ||||
|                                                           payload, | ||||
|                                                           errorMsg, | ||||
| @@ -475,9 +485,10 @@ namespace ix | ||||
|  | ||||
|                 if (!lineResult.first) | ||||
|                 { | ||||
|                     auto errorCode = args->cancel ? HttpErrorCode::Cancelled : HttpErrorCode::ChunkReadError; | ||||
|                     return std::make_shared<HttpResponse>(code, | ||||
|                                                           description, | ||||
|                                                           HttpErrorCode::ChunkReadError, | ||||
|                                                           errorCode, | ||||
|                                                           headers, | ||||
|                                                           payload, | ||||
|                                                           errorMsg, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user