mirror of https://github.com/vitalif/grive2
Fix hang when upload receives HTTP 500
When an uploading PUT request got a HTTP 500 as reponse, grive hanged forever inside libcurl. This was because the File parameter was not rewound to 0 position on retry. The XmlResponse had to be cleared as well. Rewinding the File and clearing the XmlResponse were not enough to fix the problem, because when retrying after 500, HTTP 410 Gone or 412 Precondition failed is often received, and CheckHttpResponse would throw an exception that crashes grive. Therefore, I implemented a retry logic to Resource::Upload that retries the whole upload transaction if 410 or 412 was received.pull/40/head
parent
645bb2e7d4
commit
84785ec473
|
@ -36,6 +36,7 @@
|
|||
#include "xml/Node.hh"
|
||||
#include "xml/NodeSet.hh"
|
||||
#include "xml/String.hh"
|
||||
#include "xml/TreeBuilder.hh"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/exception/all.hpp>
|
||||
|
@ -599,23 +600,44 @@ bool Resource::Upload(
|
|||
% xml::Escape(m_name)
|
||||
).str() ;
|
||||
|
||||
http::StringResponse str ;
|
||||
if ( post )
|
||||
http->Post( link, meta, &str, hdr ) ;
|
||||
else
|
||||
http->Put( link, meta, &str, hdr ) ;
|
||||
|
||||
http::Header uphdr ;
|
||||
uphdr.Add( "Expect:" ) ;
|
||||
uphdr.Add( "Accept:" ) ;
|
||||
bool retrying=false;
|
||||
while ( true ) {
|
||||
if ( retrying ) {
|
||||
file.Seek( 0, SEEK_SET );
|
||||
os::Sleep( 5 );
|
||||
}
|
||||
|
||||
// the content upload URL is in the "Location" HTTP header
|
||||
std::string uplink = http->RedirLocation() ;
|
||||
http::XmlResponse xml ;
|
||||
|
||||
http->Put( uplink, &file, &xml, uphdr ) ;
|
||||
AssignIDs( Entry( xml.Response() ) ) ;
|
||||
m_mtime = Entry(xml.Response()).MTime();
|
||||
http::StringResponse str ;
|
||||
if ( post )
|
||||
http->Post( link, meta, &str, hdr ) ;
|
||||
else
|
||||
http->Put( link, meta, &str, hdr ) ;
|
||||
|
||||
http::Header uphdr ;
|
||||
uphdr.Add( "Expect:" ) ;
|
||||
uphdr.Add( "Accept:" ) ;
|
||||
|
||||
// the content upload URL is in the "Location" HTTP header
|
||||
std::string uplink = http->RedirLocation() ;
|
||||
http::XmlResponse xml ;
|
||||
|
||||
long http_code = 0;
|
||||
http_code = http->Put( uplink, &file, &xml, uphdr ) ;
|
||||
|
||||
if ( http_code == 410 || http_code == 412 ) {
|
||||
Log( "request failed with %1%, retrying whole upload in 5s", http_code,
|
||||
log::warning ) ;
|
||||
retrying = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( retrying )
|
||||
Log( "upload succeeded on retry", log::warning );
|
||||
Entry responseEntry = Entry( xml.Response() );
|
||||
AssignIDs( responseEntry ) ;
|
||||
m_mtime = responseEntry.MTime();
|
||||
break;
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,11 @@ XmlResponse::XmlResponse() : m_tb( new xml::TreeBuilder )
|
|||
{
|
||||
}
|
||||
|
||||
void XmlResponse::Clear()
|
||||
{
|
||||
m_tb.reset(new xml::TreeBuilder);
|
||||
}
|
||||
|
||||
std::size_t XmlResponse::Write( const char *data, std::size_t count )
|
||||
{
|
||||
m_tb->ParseData( data, count ) ;
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
|
||||
#include "http/Error.hh"
|
||||
#include "http/Header.hh"
|
||||
#include "http/XmlResponse.hh"
|
||||
#include "util/log/Log.hh"
|
||||
#include "util/OS.hh"
|
||||
#include "util/File.hh"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
@ -69,8 +71,22 @@ long AuthAgent::Put(
|
|||
Header auth = AppendHeader(hdr) ;
|
||||
|
||||
long response ;
|
||||
while ( CheckRetry(
|
||||
response = m_agent->Put( url, file, dest, AppendHeader(hdr) ) ) ) ;
|
||||
bool keepTrying = true;
|
||||
while ( keepTrying ) {
|
||||
response = m_agent->Put( url, file, dest, auth );
|
||||
keepTrying = CheckRetry( response );
|
||||
if ( keepTrying ) {
|
||||
file->Seek( 0, SEEK_SET );
|
||||
XmlResponse *xmlResponse = dynamic_cast<XmlResponse*>(dest);
|
||||
if( xmlResponse )
|
||||
xmlResponse->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// On 410 Gone or 412 Precondition failed, recovery may be possible so don't
|
||||
// throw an exception
|
||||
if ( response == 410 || response == 412 )
|
||||
return response;
|
||||
|
||||
return CheckHttpResponse(response, url, auth) ;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue