Added continue / resume download support for HTTP Requests.

--HG--
branch : dev
This commit is contained in:
Martín Lucas Golini
2019-05-10 00:40:43 -03:00
parent 39ec343096
commit cf281eaa12
3 changed files with 62 additions and 3 deletions

View File

@@ -168,6 +168,12 @@ class EE_API Http : NonCopyable {
*/
void setCompressedResponse(const bool& compressedResponse);
/** Resumes download if a file is already present */
void setContinue(const bool& resume);
/** @return If must continue a download previously started. */
const bool& isContinue() const;
private:
friend class Http;
@@ -194,6 +200,7 @@ class EE_API Http : NonCopyable {
bool mValidateHostname; ///< Validates the hostname in case of an HTTPS request
bool mFollowRedirect; ///< Follows redirect response codes
bool mCompressedResponse; ///< Request comrpessed response
bool mContinue; ///< Resume download
mutable bool mCancel; ///< Cancel state of current request
ProgressCallback mProgressCallback; ///< Progress callback
unsigned int mMaxRedirections; ///< Maximun number of redirections allowed
@@ -261,6 +268,9 @@ class EE_API Http : NonCopyable {
** @return Value of the field, or empty string if not found */
const std::string& getField(const std::string& field) const;
/** @return If the field is found in the response headers. */
bool hasField(const std::string& field) const;
/** @brief Get the response status code
** The status code should be the first thing to be checked
** after receiving a response, it defines whether it is a

View File

@@ -52,6 +52,7 @@ Http::Request::Request(const std::string& uri, Method method, const std::string&
mValidateHostname( validateHostname ),
mFollowRedirect( followRedirect ),
mCompressedResponse( compressedResponse ),
mContinue( false ),
mCancel( false ),
mMaxRedirections( 10 ),
mRedirectionCount( 0 )
@@ -161,6 +162,14 @@ std::string Http::Request::prepareTunnel(const Http& http) {
return out.str();
}
void Http::Request::setContinue(const bool& resume) {
mContinue = resume;
}
const bool& Http::Request::isContinue() const {
return mContinue;
}
const bool& Http::Request::isCompressedResponse() const {
return mCompressedResponse;
}
@@ -273,6 +282,10 @@ const std::string& Http::Response::getField(const std::string& field) const {
}
}
bool Http::Response::hasField(const std::string & field) const {
return mFields.find(String::toLower(field)) != mFields.end();
}
Http::Response::Status Http::Response::getStatus() const {
return mStatus;
}
@@ -579,6 +592,33 @@ Http::Response Http::downloadRequest(const Http::Request& request, IOStream& wri
}
}
if ( request.isContinue() ) {
std::size_t continueLength = writeTo.getSize();
if ( continueLength > 0 ) {
IOStreamString responseHeadBody;
Request requestHead = request;
requestHead.setContinue( false );
requestHead.setMethod( Request::Head );
Response responseHead = downloadRequest( requestHead, responseHeadBody );
std::size_t contentLength = 0;
if ( responseHead.hasField("Accept-Ranges") &&
responseHead.hasField("Content-Length") &&
String::fromString( contentLength, responseHead.getField("Content-Length") ) &&
contentLength > 0 &&
continueLength < contentLength
)
{
writeTo.seek( continueLength );
Request newRequest( request );
newRequest.setContinue( false );
newRequest.setField( "Range", String::format( "bytes=%lu-%lu", continueLength, contentLength ) );
return downloadRequest( newRequest, writeTo, timeout );
}
}
}
// Convert the request to string and send it through the connected socket
std::string requestStr = toSend.prepare(*this);
@@ -771,8 +811,8 @@ Http::Response Http::downloadRequest(const Http::Request& request, IOStream& wri
return received;
}
Http::Response Http::downloadRequest(const Http::Request & request, std::string writePath, Time timeout) {
IOStreamFile file( writePath, "wb+" );
Http::Response Http::downloadRequest(const Http::Request& request, std::string writePath, Time timeout) {
IOStreamFile file( writePath, request.isContinue() ? "ab+" : "wb+" );
return downloadRequest( request, file, timeout );
}

View File

@@ -17,6 +17,7 @@ void printResponseHeaders( Http::Response& response ) {
EE_MAIN_FUNC int main (int argc, char * argv []) {
args::ArgumentParser parser("HTTP request program example");
args::HelpFlag help(parser, "help", "Display this help menu", {'h', "help"});
args::Flag resume(parser, "continue", "Resume getting a partially-downloaded file", {'c',"continue"});
args::Flag compressed(parser, "compressed", "Request compressed response", {"compressed"});
args::ValueFlag<std::string> postData(parser, "data", "HTTP POST data", {'d', "data"});
args::ValueFlagList<std::string> headers(parser, "header", "Pass custom header(s) to server", {'H', "header"});
@@ -130,7 +131,10 @@ EE_MAIN_FUNC int main (int argc, char * argv []) {
}
// Set the proxy for the request
if ( proxy ) {
char * http_proxy = getenv( "http_proxy" );
if ( !proxy && NULL != http_proxy ) {
http.setProxy( URI( http_proxy ) );
} else if ( proxy ) {
http.setProxy( URI( proxy.Get() ) );
}
@@ -139,6 +143,11 @@ EE_MAIN_FUNC int main (int argc, char * argv []) {
request.setCompressedResponse( true );
}
// Resume existing download
if ( resume ) {
request.setContinue( true );
}
if ( !output ) {
// Send the request
Http::Response response = http.sendRequest(request);