diff --git a/.gitignore b/.gitignore index da71e17..6fa3768 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/libgrive/src/drive/Resource.cc b/libgrive/src/drive/Resource.cc index 8974508..498a426 100644 --- a/libgrive/src/drive/Resource.cc +++ b/libgrive/src/drive/Resource.cc @@ -36,6 +36,7 @@ #include "xml/Node.hh" #include "xml/NodeSet.hh" #include "xml/String.hh" +#include "xml/TreeBuilder.hh" #include #include @@ -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(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(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 ; } diff --git a/libgrive/src/drive/State.cc b/libgrive/src/drive/State.cc index de53a88..3b227c9 100644 --- a/libgrive/src/drive/State.cc +++ b/libgrive/src/drive/State.cc @@ -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 ) ; } } diff --git a/libgrive/src/http/XmlResponse.cc b/libgrive/src/http/XmlResponse.cc index b25f1c4..3df42f9 100644 --- a/libgrive/src/http/XmlResponse.cc +++ b/libgrive/src/http/XmlResponse.cc @@ -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 ) ; diff --git a/libgrive/src/protocol/AuthAgent.cc b/libgrive/src/protocol/AuthAgent.cc index 745f274..30a9722 100644 --- a/libgrive/src/protocol/AuthAgent.cc +++ b/libgrive/src/protocol/AuthAgent.cc @@ -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 @@ -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(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 ; } diff --git a/libgrive/src/xml/TreeBuilder.cc b/libgrive/src/xml/TreeBuilder.cc index c1ad385..9d57501 100644 --- a/libgrive/src/xml/TreeBuilder.cc +++ b/libgrive/src/xml/TreeBuilder.cc @@ -21,6 +21,7 @@ #include "Error.hh" #include "Node.hh" +#include "util/log/Log.hh" #include @@ -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 )