From 8c1217dbe8e1bca57c911e75532828fc63d55ff9 Mon Sep 17 00:00:00 2001 From: Matchman Green Date: Wed, 2 May 2012 00:26:48 +0800 Subject: [PATCH] use libcurl to extract headers --- src/drive/File.cc | 26 +++------- src/protocol/HTTP.cc | 95 ++++++++++++++++++++++++++++++++++++- src/protocol/HTTP.hh | 110 +++++++++++++++++++++++++------------------ 3 files changed, 165 insertions(+), 66 deletions(-) diff --git a/src/drive/File.cc b/src/drive/File.cc index 5cf41b8..71cfd29 100644 --- a/src/drive/File.cc +++ b/src/drive/File.cc @@ -138,27 +138,15 @@ void File::Upload( std::streambuf *file, const http::Headers& auth ) hdr.push_back( "If-Match: " + m_etag ) ; hdr.push_back( "Expect:" ) ; - std::istringstream ss( http::Put( m_upload_link, meta, hdr ) ) ; + Http http ; + http.Put( m_upload_link, meta, hdr ) ; // parse the header and find "Location" - std::string line ; - while ( std::getline( ss, line ) ) - { - static const std::string location = "Location: " ; - if ( line.substr( 0, location.size() ) == location ) - { - std::string uplink = line.substr( location.size() ) ; - uplink = uplink.substr( 0, uplink.size() -1 ) ; - - // interestingly this doesn't require the access token - http::Headers uphdr ; - uphdr.push_back( "Expect:" ) ; - uphdr.push_back( "Accept:" ) ; - - http::Put( uplink, data, uphdr ) ; - } - } - + http::Headers uphdr ; + uphdr.push_back( "Expect:" ) ; + uphdr.push_back( "Accept:" ) ; + + http.Put( http.RedirLocation(), data, uphdr ) ; } } // end of namespace diff --git a/src/protocol/HTTP.cc b/src/protocol/HTTP.cc index 847a689..be3ea7d 100644 --- a/src/protocol/HTTP.cc +++ b/src/protocol/HTTP.cc @@ -92,7 +92,7 @@ void DoCurl( CURL *curl ) CURLcode curl_code = curl_easy_perform(curl); - int http_code = 0; + long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); // clean up @@ -263,3 +263,96 @@ std::string Unescape( const std::string& str ) } } } // end of namespace + +namespace gr { + +struct Http::Impl +{ + CURL *curl ; + std::string location ; +} ; + +Http::Http() : + m_pimpl( new Impl ) +{ + m_pimpl->curl = ::curl_easy_init(); + +} + +Http::~Http() +{ + ::curl_easy_cleanup( m_pimpl->curl ); +} + +std::size_t Http::HeaderCallback( void *ptr, size_t size, size_t nmemb, Http *pthis ) +{ + std::string line( (char*)ptr, (char*)ptr + size*nmemb ) ; + + static const std::string loc = "Location: " ; + std::size_t pos = line.find( loc ) ; + if ( pos != line.npos ) + { + std::size_t end_pos = line.find( "\r\n", pos ) ; + pthis->m_pimpl->location = line.substr( loc.size(), end_pos - loc.size() ) ; + } + + return size*nmemb ; +} + +std::string Http::Put( + const std::string& url, + const std::string& data, + const http::Headers& hdr ) +{ + CURL *curl = m_pimpl->curl ; + + std::string put_data = data ; + std::string resp ; + + // set common options + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp ) ; + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L ) ; + curl_easy_setopt(curl, CURLOPT_READFUNCTION, &ReadCallback ) ; + curl_easy_setopt(curl, CURLOPT_READDATA , &put_data ) ; + curl_easy_setopt(curl, CURLOPT_INFILESIZE, put_data.size() ) ; + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &Http::HeaderCallback ) ; + curl_easy_setopt(curl, CURLOPT_WRITEHEADER , this ) ; + + // set headers + struct curl_slist *curl_hdr = 0 ; + for ( Headers::const_iterator i = hdr.begin() ; i != hdr.end() ; ++i ) + curl_hdr = curl_slist_append( curl_hdr, i->c_str() ) ; + curl_easy_setopt( curl, CURLOPT_HTTPHEADER, curl_hdr ) ; + + char error_buf[CURL_ERROR_SIZE] = {} ; + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buf ) ; + + CURLcode curl_code = curl_easy_perform(curl); + + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + if ( curl_code != CURLE_OK ) + { + throw Exception( curl_code, http_code, error_buf ) ; + } + else if (http_code >= 400 ) + { + std::cout << "http error " << http_code << " " << resp << std::endl ; + throw Exception( curl_code, http_code, error_buf ) ; + } + + return resp ; +} + +std::string Http::RedirLocation() const +{ + return m_pimpl->location ; +} + +} // end of namespace diff --git a/src/protocol/HTTP.hh b/src/protocol/HTTP.hh index cd2b779..b549253 100644 --- a/src/protocol/HTTP.hh +++ b/src/protocol/HTTP.hh @@ -19,61 +19,79 @@ #pragma once +#include #include #include #include -namespace gr { namespace http -{ - typedef std::vector Headers ; +namespace gr { + namespace http + { + typedef std::vector Headers ; + + std::string Get( const std::string& url, const Headers& hdr = Headers() ) ; + void GetFile( + const std::string& url, + const std::string& filename, + const Headers& hdr = Headers() ) ; + + void GetFile( + const std::string& url, + const std::string& filename, + std::string& md5sum, + const Headers& hdr = Headers() ) ; + + std::string PostData( + const std::string& url, + const std::string& data, + const Headers& hdr = Headers() ) ; + std::string PostDataWithHeader( + const std::string& url, + const std::string& data, + const Headers& hdr = Headers() ) ; + std::string PostFile( + const std::string& url, + const std::string& filename, + const Headers& hdr = Headers() ) ; + + std::string Put( + const std::string& url, + const std::string& data, + const Headers& hdr = Headers() ) ; + + std::string Escape( const std::string& str ) ; + std::string Unescape( const std::string& str ) ; + + class Exception : public std::runtime_error + { + public : + Exception( int curl_code, int http_code, const char *err_buf ) ; + + private : + static std::string Format( int curl_code, int http_code, const char *err_buf ) ; + } ; + } + class Http { public : + Http() ; + ~Http() ; + + std::string Put( + const std::string& url, + const std::string& data, + const http::Headers& hdr = http::Headers() ) ; + + std::string RedirLocation() const ; + + private : + static std::size_t HeaderCallback( void *ptr, size_t size, size_t nmemb, Http *pthis ) ; + private : struct Impl ; - } ; - - std::string Get( const std::string& url, const Headers& hdr = Headers() ) ; - void GetFile( - const std::string& url, - const std::string& filename, - const Headers& hdr = Headers() ) ; - - void GetFile( - const std::string& url, - const std::string& filename, - std::string& md5sum, - const Headers& hdr = Headers() ) ; - - std::string PostData( - const std::string& url, - const std::string& data, - const Headers& hdr = Headers() ) ; - std::string PostDataWithHeader( - const std::string& url, - const std::string& data, - const Headers& hdr = Headers() ) ; - std::string PostFile( - const std::string& url, - const std::string& filename, - const Headers& hdr = Headers() ) ; - - std::string Put( - const std::string& url, - const std::string& data, - const Headers& hdr = Headers() ) ; - - std::string Escape( const std::string& str ) ; - std::string Unescape( const std::string& str ) ; - - class Exception : public std::runtime_error - { - public : - Exception( int curl_code, int http_code, const char *err_buf ) ; - - private : - static std::string Format( int curl_code, int http_code, const char *err_buf ) ; + std::auto_ptr m_pimpl ; } ; -} } // end of namespace +} // end of namespace