diff --git a/libgrive/src/drive/Drive.cc b/libgrive/src/drive/Drive.cc index 1c34bb5..a025d5f 100644 --- a/libgrive/src/drive/Drive.cc +++ b/libgrive/src/drive/Drive.cc @@ -23,7 +23,7 @@ #include "Entry.hh" #include "http/Agent.hh" -// #include "http/ResponseLog.hh" +#include "http/ResponseLog.hh" #include "http/XmlResponse.hh" #include "protocol/Json.hh" #include "protocol/OAuth2.hh" @@ -56,8 +56,8 @@ Drive::Drive( OAuth2& auth, const Json& options ) : m_auth( auth ), m_state( state_file, options ) { - m_http_hdr.push_back( "Authorization: Bearer " + m_auth.AccessToken() ) ; - m_http_hdr.push_back( "GData-Version: 3.0" ) ; + m_http_hdr.Add( "Authorization: Bearer " + m_auth.AccessToken() ) ; + m_http_hdr.Add( "GData-Version: 3.0" ) ; Log( "Reading local directories", log::info ) ; m_state.FromLocal( "." ) ; @@ -127,7 +127,8 @@ void Drive::SyncFolders( http::Agent *http ) Log( "Synchronizing folders", log::info ) ; http::XmlResponse xml ; - http->Get( feed_base + "/-/folder?max-results=50&showroot=true", &xml, m_http_hdr ) ; + http::ResponseLog log( "dir-", ".xml", &xml ) ; + http->Get( feed_base + "/-/folder?max-results=50&showroot=true", &log, m_http_hdr ) ; xml::Node resp = xml.Response() ; diff --git a/libgrive/src/drive/Drive.hh b/libgrive/src/drive/Drive.hh index a7def44..c831f8a 100644 --- a/libgrive/src/drive/Drive.hh +++ b/libgrive/src/drive/Drive.hh @@ -21,6 +21,7 @@ #include "State.hh" +#include "http/Header.hh" #include "util/Exception.hh" #include @@ -52,11 +53,11 @@ private : void file(); private : - OAuth2& m_auth ; - std::vector m_http_hdr ; + OAuth2& m_auth ; + http::Header m_http_hdr ; - std::string m_resume_link ; - State m_state ; + std::string m_resume_link ; + State m_state ; } ; } // end of namespace diff --git a/libgrive/src/drive/Resource.cc b/libgrive/src/drive/Resource.cc index c1f459c..bffc5cd 100644 --- a/libgrive/src/drive/Resource.cc +++ b/libgrive/src/drive/Resource.cc @@ -20,6 +20,7 @@ #include "Resource.hh" #include "CommonUri.hh" +#include "http/Agent.hh" #include "http/Download.hh" // #include "http/ResponseLog.hh" #include "http/StringResponse.hh" @@ -33,6 +34,8 @@ #include "xml/Node.hh" #include "xml/NodeSet.hh" +#include + #include // for debugging @@ -291,7 +294,7 @@ Resource* Resource::FindChild( const std::string& name ) } // try to change the state to "sync" -void Resource::Sync( http::Agent *http, const http::Headers& auth ) +void Resource::Sync( http::Agent *http, const http::Header& auth ) { assert( m_state != unknown ) ; @@ -370,25 +373,27 @@ void Resource::DeleteLocal() fs::rename( Path(), dest ) ; } -void Resource::DeleteRemote( http::Agent *http, const http::Headers& auth ) +void Resource::DeleteRemote( http::Agent *http, const http::Header& auth ) { - http::Headers hdr( auth ) ; - hdr.push_back( "If-Match: " + m_entry.ETag() ) ; + http::Header hdr( auth ) ; + hdr.Add( "If-Match: " + m_entry.ETag() ) ; http::StringResponse str ; try { http->Custom( "DELETE", http->Unescape(m_entry.SelfHref()) , &str, hdr ) ; } - catch ( Exception& ) + catch ( Exception& e ) { // don't rethrow here. there are some cases that I don't know why // the delete will fail. - Trace( "response = %1%", str.Response() ) ; + Trace( "Exception %1% %2%", + boost::diagnostic_information(e), + str.Response() ) ; } } -void Resource::Download( http::Agent* http, const fs::path& file, const http::Headers& auth ) const +void Resource::Download( http::Agent* http, const fs::path& file, const http::Header& auth ) const { http::Download dl( file.string(), http::Download::NoChecksum() ) ; long r = http->Get( m_entry.ContentSrc(), &dl, auth ) ; @@ -396,7 +401,7 @@ void Resource::Download( http::Agent* http, const fs::path& file, const http::He os::SetFileTime( file, m_entry.MTime() ) ; } -bool Resource::EditContent( http::Agent* http, const http::Headers& auth ) +bool Resource::EditContent( http::Agent* http, const http::Header& auth ) { assert( m_parent != 0 ) ; @@ -414,7 +419,7 @@ bool Resource::EditContent( http::Agent* http, const http::Headers& auth ) return Upload( http, m_entry.EditLink(), auth, false ) ; } -bool Resource::Create( http::Agent* http, const http::Headers& auth ) +bool Resource::Create( http::Agent* http, const http::Header& auth ) { assert( m_parent != 0 ) ; assert( m_parent->IsFolder() ) ; @@ -431,8 +436,8 @@ bool Resource::Create( http::Agent* http, const http::Headers& auth ) std::string meta = (boost::format(xml_meta) % "folder" % Name() ).str() ; - http::Headers hdr( auth ) ; - hdr.push_back( "Content-Type: application/atom+xml" ) ; + http::Header hdr( auth ) ; + hdr.Add( "Content-Type: application/atom+xml" ) ; http::XmlResponse xml ; // http::ResponseLog log( "create", ".xml", &xml ) ; @@ -452,7 +457,7 @@ bool Resource::Create( http::Agent* http, const http::Headers& auth ) } } -bool Resource::Upload( http::Agent* http, const std::string& link, const http::Headers& auth, bool post ) +bool Resource::Upload( http::Agent* http, const std::string& link, const http::Header& auth, bool post ) { StdioFile file( Path() ) ; @@ -466,12 +471,12 @@ bool Resource::Upload( http::Agent* http, const std::string& link, const http::H std::ostringstream xcontent_len ; xcontent_len << "X-Upload-Content-Length: " << data.size() ; - http::Headers hdr( auth ) ; - hdr.push_back( "Content-Type: application/atom+xml" ) ; - hdr.push_back( "X-Upload-Content-Type: application/octet-stream" ) ; - hdr.push_back( xcontent_len.str() ) ; - hdr.push_back( "If-Match: " + m_entry.ETag() ) ; - hdr.push_back( "Expect:" ) ; + http::Header hdr( auth ) ; + hdr.Add( "Content-Type: application/atom+xml" ) ; + hdr.Add( "X-Upload-Content-Type: application/octet-stream" ) ; + hdr.Add( xcontent_len.str() ) ; + hdr.Add( "If-Match: " + m_entry.ETag() ) ; + hdr.Add( "Expect:" ) ; std::string meta = (boost::format( xml_meta ) % m_entry.Kind() % Name()).str() ; @@ -481,9 +486,9 @@ bool Resource::Upload( http::Agent* http, const std::string& link, const http::H else http->Put( link, meta, &str, hdr ) ; - http::Headers uphdr ; - uphdr.push_back( "Expect:" ) ; - uphdr.push_back( "Accept:" ) ; + http::Header uphdr ; + uphdr.Add( "Expect:" ) ; + uphdr.Add( "Accept:" ) ; // the content upload URL is in the "Location" HTTP header std::string uplink = http->RedirLocation() ; diff --git a/libgrive/src/drive/Resource.hh b/libgrive/src/drive/Resource.hh index 1c3a4e4..968b6f5 100644 --- a/libgrive/src/drive/Resource.hh +++ b/libgrive/src/drive/Resource.hh @@ -20,7 +20,6 @@ #pragma once #include "Entry.hh" -#include "http/Agent.hh" #include "util/Exception.hh" #include "util/FileSystem.hh" @@ -30,6 +29,12 @@ namespace gr { +namespace http +{ + class Agent ; + class Header ; +} + class Json ; /*! \brief A resource can be a file or a folder in the google drive @@ -72,7 +77,7 @@ public : void FromRemote( const Entry& remote, const DateTime& last_sync ) ; void FromLocal( const DateTime& last_sync ) ; - void Sync( http::Agent *http, const http::Headers& auth ) ; + void Sync( gr::http::Agent* http, const http::Header& auth ) ; Json Serialize() const ; @@ -119,16 +124,16 @@ private : friend std::ostream& operator<<( std::ostream& os, State s ) ; private : - void Download( http::Agent* http, const fs::path& file, const http::Headers& auth ) const ; - bool EditContent( http::Agent* http, const http::Headers& auth ) ; - bool Create( http::Agent* http, const http::Headers& auth ) ; - bool Upload( http::Agent* http, const std::string& link, const http::Headers& auth, bool post ) ; + void Download( http::Agent* http, const fs::path& file, const http::Header& auth ) const ; + bool EditContent( http::Agent* http, const http::Header& auth ) ; + bool Create( http::Agent* http, const http::Header& auth ) ; + bool Upload( http::Agent* http, const std::string& link, const http::Header& auth, bool post ) ; void FromRemoteFolder( const Entry& remote, const DateTime& last_sync ) ; void FromRemoteFile( const Entry& remote, const DateTime& last_sync ) ; void DeleteLocal() ; - void DeleteRemote( http::Agent* http, const http::Headers& auth ) ; + void DeleteRemote( http::Agent* http, const http::Header& auth ) ; private : Entry m_entry ; diff --git a/libgrive/src/drive/State.cc b/libgrive/src/drive/State.cc index 192b053..bdf5bac 100644 --- a/libgrive/src/drive/State.cc +++ b/libgrive/src/drive/State.cc @@ -22,6 +22,7 @@ #include "Resource.hh" #include "CommonUri.hh" +#include "http/Agent.hh" #include "util/Crypt.hh" #include "util/Log.hh" #include "protocol/Json.hh" @@ -219,7 +220,7 @@ void State::Write( const fs::path& filename ) const fs << result ; } -void State::Sync( http::Agent *http, const http::Headers& auth ) +void State::Sync( http::Agent *http, const http::Header& auth ) { std::for_each( m_res.begin(), m_res.end(), boost::bind( &Resource::Sync, _1, http, auth ) ) ; diff --git a/libgrive/src/drive/State.hh b/libgrive/src/drive/State.hh index c17699f..7a8fc68 100644 --- a/libgrive/src/drive/State.hh +++ b/libgrive/src/drive/State.hh @@ -21,7 +21,6 @@ #include "ResourceTree.hh" -#include "http/Agent.hh" #include "util/DateTime.hh" #include "util/FileSystem.hh" @@ -29,6 +28,12 @@ namespace gr { +namespace http +{ + class Agent ; + class Header ; +} + class Json ; class Resource ; class Entry ; @@ -52,7 +57,7 @@ public : Resource* FindByID( const std::string& id ) ; Resource* Find( const fs::path& path ) ; - void Sync( http::Agent *http, const http::Headers& auth ) ; + void Sync( http::Agent *http, const http::Header& auth ) ; iterator begin() ; iterator end() ; diff --git a/libgrive/src/http/Agent.cc b/libgrive/src/http/Agent.cc index c12905b..0866826 100644 --- a/libgrive/src/http/Agent.cc +++ b/libgrive/src/http/Agent.cc @@ -126,9 +126,9 @@ std::size_t Agent::Receive( void* ptr, size_t size, size_t nmemb, Receivable *re } long Agent::ExecCurl( - const std::string& url, - Receivable *dest, - const http::Headers& hdr ) + const std::string& url, + Receivable *dest, + const http::Header& hdr ) { CURL *curl = m_pimpl->curl ; assert( curl != 0 ) ; @@ -158,6 +158,7 @@ long Agent::ExecCurl( << HttpResponse( http_code ) << Url( url ) << expt::ErrMsg( error ) + << HttpHeader( hdr ) ) ; } @@ -168,7 +169,7 @@ long Agent::Put( const std::string& url, const std::string& data, Receivable *dest, - const http::Headers& hdr ) + const Header& hdr ) { Trace("HTTP PUT \"%1%\"", url ) ; @@ -189,7 +190,7 @@ long Agent::Put( long Agent::Get( const std::string& url, Receivable *dest, - const http::Headers& hdr ) + const Header& hdr ) { Trace("HTTP GET \"%1%\"", url ) ; @@ -206,7 +207,7 @@ long Agent::Post( const std::string& url, const std::string& data, Receivable *dest, - const http::Headers& hdr ) + const Header& hdr ) { Trace("HTTP POST \"%1%\" with \"%2%\"", url, data ) ; @@ -228,22 +229,23 @@ long Agent::Custom( const std::string& method, const std::string& url, Receivable *dest, - const http::Headers& hdr ) + const Header& hdr ) { Trace("HTTP %2% \"%1%\"", url, method ) ; CURL *curl = m_pimpl->curl ; ::curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method.c_str() ); + ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1 ); return ExecCurl( url, dest, hdr ) ; } -void Agent::SetHeader( const http::Headers& hdr ) +void Agent::SetHeader( const Header& hdr ) { // set headers struct curl_slist *curl_hdr = 0 ; - for ( Headers::const_iterator i = hdr.begin() ; i != hdr.end() ; ++i ) + for ( Header::iterator i = hdr.begin() ; i != hdr.end() ; ++i ) curl_hdr = curl_slist_append( curl_hdr, i->c_str() ) ; ::curl_easy_setopt( m_pimpl->curl, CURLOPT_HTTPHEADER, curl_hdr ) ; diff --git a/libgrive/src/http/Agent.hh b/libgrive/src/http/Agent.hh index 59e1ba2..b764b62 100644 --- a/libgrive/src/http/Agent.hh +++ b/libgrive/src/http/Agent.hh @@ -19,14 +19,14 @@ #pragma once +#include "Header.hh" + #include #include #include namespace gr { namespace http { -typedef std::vector Headers ; - class Receivable ; /*! \class Agent @@ -44,27 +44,27 @@ public : void SetLogFile( const std::string& prefix ) ; long Put( - const std::string& url, - const std::string& data, - Receivable *dest, - const http::Headers& hdr = http::Headers() ) ; + const std::string& url, + const std::string& data, + Receivable *dest, + const Header& hdr = Header() ) ; long Get( - const std::string& url, - Receivable *dest, - const http::Headers& hdr = http::Headers() ) ; + const std::string& url, + Receivable *dest, + const Header& hdr = Header() ) ; long Post( - const std::string& url, - const std::string& data, - Receivable *dest, - const http::Headers& hdr = http::Headers() ) ; + const std::string& url, + const std::string& data, + Receivable *dest, + const Header& hdr = Header() ) ; long Custom( - const std::string& method, - const std::string& url, - Receivable *dest, - const http::Headers& hdr = http::Headers() ) ; + const std::string& method, + const std::string& url, + Receivable *dest, + const Header& hdr = Header() ) ; std::string RedirLocation() const ; @@ -75,11 +75,11 @@ private : static std::size_t HeaderCallback( void *ptr, size_t size, size_t nmemb, Agent *pthis ) ; static std::size_t Receive( void* ptr, size_t size, size_t nmemb, Receivable *recv ) ; - void SetHeader( const http::Headers& hdr ) ; + void SetHeader( const Header& hdr ) ; long ExecCurl( - const std::string& url, - Receivable *dest, - const http::Headers& hdr) ; + const std::string& url, + Receivable *dest, + const Header& hdr ) ; void Init() ; diff --git a/libgrive/src/http/Error.hh b/libgrive/src/http/Error.hh index 94b2c44..a513f5f 100644 --- a/libgrive/src/http/Error.hh +++ b/libgrive/src/http/Error.hh @@ -19,6 +19,7 @@ #pragma once +#include "Header.hh" #include "util/Exception.hh" namespace gr { namespace http { @@ -37,4 +38,7 @@ typedef boost::error_info HttpResponseTe // URL typedef boost::error_info Url ; +// HTTP headers +typedef boost::error_info HttpHeader ; + } } // end of namespace diff --git a/libgrive/src/http/Header.cc b/libgrive/src/http/Header.cc new file mode 100644 index 0000000..36bd245 --- /dev/null +++ b/libgrive/src/http/Header.cc @@ -0,0 +1,53 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 Wan Wai Ho + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation version 2 + of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "Header.hh" + +#include +#include +#include + +namespace gr { namespace http { + +Header::Header() +{ +} + +void Header::Add( const std::string& str ) +{ + m_vec.push_back( str ) ; +} + +Header::iterator Header::begin() const +{ + return m_vec.begin() ; +} + +Header::iterator Header::end() const +{ + return m_vec.end() ; +} + +std::ostream& operator<<( std::ostream& os, const Header& h ) +{ + std::copy( h.begin(), h.end(), std::ostream_iterator( os, "\n" ) ) ; + return os ; +} + +} } // end of namespace diff --git a/libgrive/src/http/Header.hh b/libgrive/src/http/Header.hh new file mode 100644 index 0000000..c581d7d --- /dev/null +++ b/libgrive/src/http/Header.hh @@ -0,0 +1,50 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 Wan Wai Ho + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation version 2 + of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#pragma once + +#include +#include +#include + +namespace gr { namespace http { + +class Header +{ +private : + typedef std::vector Vec ; + +public : + typedef Vec::const_iterator iterator ; + +public : + Header() ; + + void Add( const std::string& str ) ; + + iterator begin() const ; + iterator end() const ; + +private : + Vec m_vec ; +} ; + +std::ostream& operator<<( std::ostream& os, const Header& h ) ; + +}} // end of namespace diff --git a/libgrive/src/util/DefaultLog.cc b/libgrive/src/util/DefaultLog.cc index d52b356..dbecb90 100644 --- a/libgrive/src/util/DefaultLog.cc +++ b/libgrive/src/util/DefaultLog.cc @@ -39,7 +39,7 @@ DefaultLog::DefaultLog( const std::string& filename ) : m_file( filename.c_str() ), m_log( m_file ) { - m_enabled[log::debug] = false ; + m_enabled[log::debug] = true ; m_enabled[log::verbose] = true ; m_enabled[log::info] = true ; m_enabled[log::warning] = true ;