Skip to content

Commit

Permalink
Add response body and headers to diagnostic information on HTTP 400 a…
Browse files Browse the repository at this point in the history
…nd above

Also should fix #13 because stops AuthAgent from using the same response multiple times
  • Loading branch information
vitalif committed Jun 27, 2015
1 parent 06eb1a7 commit 70ec926
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 37 deletions.
2 changes: 1 addition & 1 deletion libgrive/src/drive/Syncer1.cc
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ bool Syncer1::Upload( Resource *res,

if ( http_code == 410 || http_code == 412 )
{
Log( "request failed with %1%, retrying whole upload in 5s", http_code, log::warning ) ;
Log( "request failed with %1%, body: %2%, retrying whole upload in 5s", http_code, m_http->LastError(), log::warning ) ;
retrying = true;
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion libgrive/src/drive2/Syncer2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ bool Syncer2::Upload( Resource *res )
long http_code = m_http->Put( upload_base + "/" + valr["id"].Str() + "?uploadType=media", &file, &vrsp, hdr ) ;
if ( http_code == 410 || http_code == 412 )
{
Log( "request failed with %1%, retrying whole upload in 5s", http_code, log::warning ) ;
Log( "request failed with %1%, body: %2%. retrying whole upload in 5s", http_code, m_http->LastError(), log::warning ) ;
os::Sleep( 5 );
}
else
Expand Down
3 changes: 3 additions & 0 deletions libgrive/src/http/Agent.hh
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public :
DataStream *dest,
const Header& hdr ) = 0 ;

virtual std::string LastError() const = 0 ;
virtual std::string LastErrorHeaders() const = 0 ;

virtual std::string RedirLocation() const = 0 ;

virtual std::string Escape( const std::string& str ) = 0 ;
Expand Down
59 changes: 46 additions & 13 deletions libgrive/src/http/CurlAgent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ struct CurlAgent::Impl
{
CURL *curl ;
std::string location ;
bool error ;
std::string error_headers ;
std::string error_data ;
DataStream *dest ;
} ;

CurlAgent::CurlAgent() :
Expand All @@ -96,11 +100,15 @@ CurlAgent::CurlAgent() :
void CurlAgent::Init()
{
::curl_easy_reset( m_pimpl->curl ) ;
::curl_easy_setopt( m_pimpl->curl, CURLOPT_SSL_VERIFYPEER, 0L ) ;
::curl_easy_setopt( m_pimpl->curl, CURLOPT_SSL_VERIFYPEER, 0L ) ;
::curl_easy_setopt( m_pimpl->curl, CURLOPT_SSL_VERIFYHOST, 0L ) ;
::curl_easy_setopt( m_pimpl->curl, CURLOPT_HEADERFUNCTION, &CurlAgent::HeaderCallback ) ;
::curl_easy_setopt( m_pimpl->curl, CURLOPT_WRITEHEADER , this ) ;
::curl_easy_setopt( m_pimpl->curl, CURLOPT_HEADER, 0L ) ;
::curl_easy_setopt( m_pimpl->curl, CURLOPT_HEADERDATA, this ) ;
::curl_easy_setopt( m_pimpl->curl, CURLOPT_HEADER, 0L ) ;
m_pimpl->error = false;
m_pimpl->error_headers = "";
m_pimpl->error_data = "";
m_pimpl->dest = NULL;
}

CurlAgent::~CurlAgent()
Expand All @@ -110,9 +118,16 @@ CurlAgent::~CurlAgent()

std::size_t CurlAgent::HeaderCallback( void *ptr, size_t size, size_t nmemb, CurlAgent *pthis )
{
char *str = reinterpret_cast<char*>(ptr) ;
char *str = static_cast<char*>(ptr) ;
std::string line( str, str + size*nmemb ) ;

// Check for error (HTTP 400 and above)
if ( line.substr( 0, 5 ) == "HTTP/" && line[9] >= '4' )
pthis->m_pimpl->error = true;

if ( pthis->m_pimpl->error )
pthis->m_pimpl->error_headers += line;

static const std::string loc = "Location: " ;
std::size_t pos = line.find( loc ) ;
if ( pos != line.npos )
Expand All @@ -124,10 +139,16 @@ std::size_t CurlAgent::HeaderCallback( void *ptr, size_t size, size_t nmemb, Cur
return size*nmemb ;
}

std::size_t CurlAgent::Receive( void* ptr, size_t size, size_t nmemb, DataStream *recv )
std::size_t CurlAgent::Receive( void* ptr, size_t size, size_t nmemb, CurlAgent *pthis )
{
assert( recv != 0 ) ;
return recv->Write( static_cast<char*>(ptr), size * nmemb ) ;
assert( pthis != 0 ) ;
if ( pthis->m_pimpl->error && pthis->m_pimpl->error_data.size() < 65536 )
{
// Do not feed error responses to destination stream
pthis->m_pimpl->error_data.append( static_cast<char*>(ptr), size * nmemb ) ;
return size * nmemb ;
}
return pthis->m_pimpl->dest->Write( static_cast<char*>(ptr), size * nmemb ) ;
}

long CurlAgent::ExecCurl(
Expand All @@ -142,21 +163,23 @@ long CurlAgent::ExecCurl(
::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error ) ;
::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CurlAgent::Receive ) ;
::curl_easy_setopt(curl, CURLOPT_WRITEDATA, dest ) ;
::curl_easy_setopt(curl, CURLOPT_WRITEDATA, this ) ;
m_pimpl->dest = dest ;

SetHeader( hdr ) ;

// dest->Clear() ;
CURLcode curl_code = ::curl_easy_perform(curl);

// get the HTTP response code
long http_code = 0;
::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
Trace( "HTTP response %1%", http_code ) ;
// reset the curl buffer to prevent it from touch our "error" buffer

// reset the curl buffer to prevent it from touching our "error" buffer
::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, 0 ) ;


m_pimpl->dest = NULL;

// only throw for libcurl errors
if ( curl_code != CURLE_OK )
{
Expand All @@ -165,7 +188,7 @@ long CurlAgent::ExecCurl(
<< CurlCode( curl_code )
<< Url( url )
<< CurlErrMsg( error )
<< HttpHeader( hdr )
<< HttpRequestHeaders( hdr )
) ;
}

Expand Down Expand Up @@ -275,6 +298,16 @@ void CurlAgent::SetHeader( const Header& hdr )
::curl_easy_setopt( m_pimpl->curl, CURLOPT_HTTPHEADER, curl_hdr ) ;
}

std::string CurlAgent::LastError() const
{
return m_pimpl->error_data ;
}

std::string CurlAgent::LastErrorHeaders() const
{
return m_pimpl->error_headers ;
}

std::string CurlAgent::RedirLocation() const
{
return m_pimpl->location ;
Expand Down
5 changes: 4 additions & 1 deletion libgrive/src/http/CurlAgent.hh
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,17 @@ public :
DataStream *dest,
const Header& hdr ) ;

std::string LastError() const ;
std::string LastErrorHeaders() const ;

std::string RedirLocation() const ;

std::string Escape( const std::string& str ) ;
std::string Unescape( const std::string& str ) ;

private :
static std::size_t HeaderCallback( void *ptr, size_t size, size_t nmemb, CurlAgent *pthis ) ;
static std::size_t Receive( void* ptr, size_t size, size_t nmemb, DataStream *recv ) ;
static std::size_t Receive( void* ptr, size_t size, size_t nmemb, CurlAgent *pthis ) ;

void SetHeader( const Header& hdr ) ;
long ExecCurl(
Expand Down
17 changes: 10 additions & 7 deletions libgrive/src/http/Error.hh
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,24 @@ namespace gr { namespace http {
struct Error : virtual Exception {} ;

// CURL error code
typedef boost::error_info<struct CurlCodeTag, int> CurlCode ;
typedef boost::error_info<struct CurlCodeTag, int> CurlCode ;

// CURL error message
typedef boost::error_info<struct CurlErrMsgTag, std::string> CurlErrMsg ;
typedef boost::error_info<struct CurlErrMsgTag, std::string> CurlErrMsg ;

// URL
typedef boost::error_info<struct UrlTag, std::string> Url ;
typedef boost::error_info<struct UrlTag, std::string> Url ;

// HTTP headers
typedef boost::error_info<struct HeaderTag, Header> HttpHeader ;
// HTTP request headers
typedef boost::error_info<struct RequestHeadersTag, Header> HttpRequestHeaders ;

// HTTP response code
typedef boost::error_info<struct HttpResponseTag, int> HttpResponse ;
typedef boost::error_info<struct ResponseCodeTag, int> HttpResponseCode ;

// HTTP response headers
typedef boost::error_info<struct ResponseHeadersTag, std::string> HttpResponseHeaders ;

// HTTP response body
typedef boost::error_info<struct HttpResponseStrTag, std::string> HttpResponseText ;
typedef boost::error_info<struct ResponseBodyTag, std::string> HttpResponseText ;

} } // end of namespace
36 changes: 22 additions & 14 deletions libgrive/src/protocol/AuthAgent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

#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"
Expand Down Expand Up @@ -77,9 +76,6 @@ long AuthAgent::Put(
keepTrying = CheckRetry( response );
if ( keepTrying ) {
file->Seek( 0, SEEK_SET );
XmlResponse *xmlResponse = dynamic_cast<XmlResponse*>(dest);
if( xmlResponse )
xmlResponse->Clear();
}
}

Expand Down Expand Up @@ -135,6 +131,16 @@ long AuthAgent::Custom(
return CheckHttpResponse(response, url, auth) ;
}

std::string AuthAgent::LastError() const
{
return m_agent->LastError() ;
}

std::string AuthAgent::LastErrorHeaders() const
{
return m_agent->LastErrorHeaders() ;
}

std::string AuthAgent::RedirLocation() const
{
return m_agent->RedirLocation() ;
Expand All @@ -152,11 +158,11 @@ std::string AuthAgent::Unescape( const std::string& str )

bool AuthAgent::CheckRetry( long response )
{
// HTTP 500 and 503 should be temperory. just wait a bit and retry
// HTTP 500 and 503 should be temporary. just wait a bit and retry
if ( response == 500 || response == 503 )
{
Log( "resquest failed due to temperory error: %1%. retrying in 5 seconds",
response, log::warning ) ;
Log( "request failed due to temporary error: %1%, body: %2%. retrying in 5 seconds",
response, m_agent->LastError(), log::warning ) ;

os::Sleep( 5 ) ;
return true ;
Expand All @@ -165,7 +171,7 @@ bool AuthAgent::CheckRetry( long response )
// HTTP 401 Unauthorized. the auth token has been expired. refresh it
else if ( response == 401 )
{
Log( "resquest failed due to auth token expired: %1%. refreshing token",
Log( "request failed due to auth token expired: %1%. refreshing token",
response, log::warning ) ;

os::Sleep( 5 ) ;
Expand All @@ -182,13 +188,15 @@ long AuthAgent::CheckHttpResponse(
const http::Header& hdr )
{
// throw for other HTTP errors
if ( response >= 400 && response < 500 )
if ( response >= 400 )
{
BOOST_THROW_EXCEPTION(
Error()
<< HttpResponse( response )
<< Url( url )
<< HttpHeader( hdr ) ) ;
BOOST_THROW_EXCEPTION(
Error()
<< HttpResponseCode( response )
<< HttpResponseHeaders( m_agent->LastErrorHeaders() )
<< HttpResponseText( m_agent->LastError() )
<< Url( url )
<< HttpRequestHeaders( hdr ) ) ;
}

return response ;
Expand Down
3 changes: 3 additions & 0 deletions libgrive/src/protocol/AuthAgent.hh
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public :
DataStream *dest,
const http::Header& hdr ) ;

std::string LastError() const ;
std::string LastErrorHeaders() const ;

std::string RedirLocation() const ;

std::string Escape( const std::string& str ) ;
Expand Down

0 comments on commit 70ec926

Please sign in to comment.