Vitaliy Filippov 2015-05-16 00:36:18 +03:00
commit ac1763f2c7
6 changed files with 107 additions and 25 deletions

10
.gitignore vendored
View File

@ -4,3 +4,13 @@ grive.kdev4
.project
.cproject
build/
/CMakeCache.txt
CMakeFiles
moc_*.cxx*
bgrive/ui_MainWindow.h
Makefile
*.a
bgrive/bgrive
grive/grive
libgrive/btest
*.cmake

View File

@ -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>
@ -252,7 +253,7 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync )
void Resource::FromLocal( const DateTime& last_sync )
{
fs::path path = Path() ;
assert( fs::exists( path ) ) ;
//assert( fs::exists( path ) ) ;
// root folder is always in sync
if ( !IsRoot() )
@ -270,8 +271,8 @@ void Resource::FromLocal( const DateTime& last_sync )
m_state = ( m_mtime > last_sync ? local_new : remote_deleted ) ;
m_name = path.filename().string() ;
m_kind = fs::is_directory(path) ? "folder" : "file" ;
m_md5 = fs::is_directory(path) ? "" : crypt::MD5::Get( path ) ;
//m_kind = fs::is_directory(path) ? "folder" : "file" ;
m_md5 = IsFolder() ? "" : crypt::MD5::Get( path ) ;
}
assert( m_state != unknown ) ;
@ -579,23 +580,68 @@ 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();
try {
http::StringResponse str ;
if ( post )
http->Post( link, meta, &str, hdr ) ;
else
http->Put( link, meta, &str, hdr ) ;
} catch ( Error &e ) {
std::string const *info = boost::get_error_info<xml::TreeBuilder::ExpatApiError>(e);
if ( info && (*info == "XML_Parse") ) {
Log( "Error parsing pre-upload response XML, retrying whole upload in 5s",
log::warning );
retrying = true;
continue;
} else {
throw e;
}
}
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;
try {
http_code = http->Put( uplink, &file, &xml, uphdr ) ;
} catch ( Error &e ) {
std::string const *info = boost::get_error_info<xml::TreeBuilder::ExpatApiError>(e);
if ( info && (*info == "XML_Parse") ) {
Log( "Error parsing response XML, retrying whole upload in 5s",
log::warning );
retrying = true;
continue;
} else {
throw e;
}
}
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 ;
}

View File

@ -61,7 +61,7 @@ void State::FromLocal( const fs::path& p )
bool State::IsIgnore( const std::string& filename )
{
return filename[0] == '.' ;
return filename == ".grive" || filename == ".grive_state";
}
void State::FromLocal( const fs::path& p, Resource* folder )
@ -89,19 +89,20 @@ void State::FromLocal( const fs::path& p, Resource* folder )
else
{
bool is_dir = fs::is_directory(i->path());
// if the Resource object of the child already exists, it should
// have been so no need to do anything here
Resource *c = folder->FindChild( fname ) ;
if ( c == 0 )
{
c = new Resource( fname, fs::is_directory(i->path()) ? "folder" : "file" ) ;
c = new Resource( fname, is_dir ? "folder" : "file" ) ;
folder->AddChild( c ) ;
m_res.Insert( c ) ;
}
c->FromLocal( m_last_sync ) ;
if ( fs::is_directory( i->path() ) )
if ( is_dir )
FromLocal( *i, c ) ;
}
}

View File

@ -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 ) ;

View File

@ -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) ;
}
@ -152,6 +168,7 @@ bool AuthAgent::CheckRetry( long response )
Log( "resquest failed due to auth token expired: %1%. refreshing token",
response, log::warning ) ;
os::Sleep( 5 ) ;
m_auth.Refresh() ;
return true ;
}

View File

@ -21,6 +21,7 @@
#include "Error.hh"
#include "Node.hh"
#include "util/log/Log.hh"
#include <expat.h>
@ -72,8 +73,10 @@ void TreeBuilder::ParseData( const char *data, std::size_t count, bool last )
{
is_new = false ;
if ( ::XML_Parse( m_impl->psr, data, count, last ) == 0 )
if ( ::XML_Parse( m_impl->psr, data, count, last ) == 0 ) {
Log("Error parsing XML: %1%", data, log::error);
BOOST_THROW_EXCEPTION( Error() << ExpatApiError("XML_Parse") );
}
}
Node TreeBuilder::Parse( const std::string& xml )