mirror of https://github.com/vitalif/grive2
NSURLSession-based HTTP agent
parent
ffb744a59b
commit
1ec7d119e2
|
@ -14,6 +14,7 @@ bgrive/bgrive
|
||||||
grive/grive
|
grive/grive
|
||||||
libgrive/btest
|
libgrive/btest
|
||||||
*.cmake
|
*.cmake
|
||||||
|
.vscode/
|
||||||
|
|
||||||
debian/debhelper-build-stamp
|
debian/debhelper-build-stamp
|
||||||
debian/files
|
debian/files
|
||||||
|
|
|
@ -23,7 +23,11 @@
|
||||||
#include "base/Drive.hh"
|
#include "base/Drive.hh"
|
||||||
#include "drive2/Syncer2.hh"
|
#include "drive2/Syncer2.hh"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "http/NSURLSessionAgent.hh"
|
||||||
|
#else
|
||||||
#include "http/CurlAgent.hh"
|
#include "http/CurlAgent.hh"
|
||||||
|
#endif
|
||||||
#include "protocol/AuthAgent.hh"
|
#include "protocol/AuthAgent.hh"
|
||||||
#include "protocol/OAuth2.hh"
|
#include "protocol/OAuth2.hh"
|
||||||
#include "json/Val.hh"
|
#include "json/Val.hh"
|
||||||
|
@ -80,19 +84,19 @@ void InitLog( const po::variables_map& vm )
|
||||||
file_log->Enable( log::warning ) ;
|
file_log->Enable( log::warning ) ;
|
||||||
file_log->Enable( log::error ) ;
|
file_log->Enable( log::error ) ;
|
||||||
file_log->Enable( log::critical ) ;
|
file_log->Enable( log::critical ) ;
|
||||||
|
|
||||||
// log grive version to log file
|
// log grive version to log file
|
||||||
file_log->Log( log::Fmt("grive version " VERSION " " __DATE__ " " __TIME__), log::verbose ) ;
|
file_log->Log( log::Fmt("grive version " VERSION " " __DATE__ " " __TIME__), log::verbose ) ;
|
||||||
file_log->Log( log::Fmt("current time: %1%") % DateTime::Now(), log::verbose ) ;
|
file_log->Log( log::Fmt("current time: %1%") % DateTime::Now(), log::verbose ) ;
|
||||||
|
|
||||||
comp_log->Add( file_log ) ;
|
comp_log->Add( file_log ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( vm.count( "verbose" ) )
|
if ( vm.count( "verbose" ) )
|
||||||
{
|
{
|
||||||
console_log->Enable( log::verbose ) ;
|
console_log->Enable( log::verbose ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( vm.count( "debug" ) )
|
if ( vm.count( "debug" ) )
|
||||||
{
|
{
|
||||||
console_log->Enable( log::verbose ) ;
|
console_log->Enable( log::verbose ) ;
|
||||||
|
@ -104,7 +108,7 @@ void InitLog( const po::variables_map& vm )
|
||||||
int Main( int argc, char **argv )
|
int Main( int argc, char **argv )
|
||||||
{
|
{
|
||||||
InitGCrypt() ;
|
InitGCrypt() ;
|
||||||
|
|
||||||
// construct the program options
|
// construct the program options
|
||||||
po::options_description desc( "Grive options" );
|
po::options_description desc( "Grive options" );
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
|
@ -131,7 +135,7 @@ int Main( int argc, char **argv )
|
||||||
( "download-speed,D", po::value<unsigned>(), "Limit download speed in kbytes per second" )
|
( "download-speed,D", po::value<unsigned>(), "Limit download speed in kbytes per second" )
|
||||||
( "progress-bar,P", "Enable progress bar for upload/download of files")
|
( "progress-bar,P", "Enable progress bar for upload/download of files")
|
||||||
;
|
;
|
||||||
|
|
||||||
po::variables_map vm;
|
po::variables_map vm;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -143,7 +147,7 @@ int Main( int argc, char **argv )
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
po::notify( vm );
|
po::notify( vm );
|
||||||
|
|
||||||
// simple commands that doesn't require log or config
|
// simple commands that doesn't require log or config
|
||||||
if ( vm.count("help") )
|
if ( vm.count("help") )
|
||||||
{
|
{
|
||||||
|
@ -159,12 +163,16 @@ int Main( int argc, char **argv )
|
||||||
|
|
||||||
// initialize logging
|
// initialize logging
|
||||||
InitLog( vm ) ;
|
InitLog( vm ) ;
|
||||||
|
|
||||||
Config config( vm ) ;
|
Config config( vm ) ;
|
||||||
|
|
||||||
Log( "config file name %1%", config.Filename(), log::verbose );
|
Log( "config file name %1%", config.Filename(), log::verbose );
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::unique_ptr<http::Agent> http( new http::NSURLSessionAgent );
|
||||||
|
#else
|
||||||
std::unique_ptr<http::Agent> http( new http::CurlAgent );
|
std::unique_ptr<http::Agent> http( new http::CurlAgent );
|
||||||
|
#endif
|
||||||
if ( vm.count( "log-http" ) )
|
if ( vm.count( "log-http" ) )
|
||||||
http->SetLog( new http::ResponseLog( vm["log-http"].as<std::string>(), ".txt" ) );
|
http->SetLog( new http::ResponseLog( vm["log-http"].as<std::string>(), ".txt" ) );
|
||||||
|
|
||||||
|
@ -185,34 +193,34 @@ int Main( int argc, char **argv )
|
||||||
: default_secret ;
|
: default_secret ;
|
||||||
|
|
||||||
OAuth2 token( http.get(), id, secret ) ;
|
OAuth2 token( http.get(), id, secret ) ;
|
||||||
|
|
||||||
if ( vm.count("print-url") )
|
if ( vm.count("print-url") )
|
||||||
{
|
{
|
||||||
std::cout << token.MakeAuthURL() << std::endl ;
|
std::cout << token.MakeAuthURL() << std::endl ;
|
||||||
return 0 ;
|
return 0 ;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout
|
std::cout
|
||||||
<< "-----------------------\n"
|
<< "-----------------------\n"
|
||||||
<< "Please go to this URL and get an authentication code:\n\n"
|
<< "Please go to this URL and get an authentication code:\n\n"
|
||||||
<< token.MakeAuthURL()
|
<< token.MakeAuthURL()
|
||||||
<< std::endl ;
|
<< std::endl ;
|
||||||
|
|
||||||
std::cout
|
std::cout
|
||||||
<< "\n-----------------------\n"
|
<< "\n-----------------------\n"
|
||||||
<< "Please input the authentication code here: " << std::endl ;
|
<< "Please input the authentication code here: " << std::endl ;
|
||||||
std::string code ;
|
std::string code ;
|
||||||
std::cin >> code ;
|
std::cin >> code ;
|
||||||
|
|
||||||
token.Auth( code ) ;
|
token.Auth( code ) ;
|
||||||
|
|
||||||
// save to config
|
// save to config
|
||||||
config.Set( "id", Val( id ) ) ;
|
config.Set( "id", Val( id ) ) ;
|
||||||
config.Set( "secret", Val( secret ) ) ;
|
config.Set( "secret", Val( secret ) ) ;
|
||||||
config.Set( "refresh_token", Val( token.RefreshToken() ) ) ;
|
config.Set( "refresh_token", Val( token.RefreshToken() ) ) ;
|
||||||
config.Save() ;
|
config.Save() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string refresh_token ;
|
std::string refresh_token ;
|
||||||
std::string id ;
|
std::string id ;
|
||||||
std::string secret ;
|
std::string secret ;
|
||||||
|
@ -228,10 +236,10 @@ int Main( int argc, char **argv )
|
||||||
"Please run grive with the \"-a\" option if this is the "
|
"Please run grive with the \"-a\" option if this is the "
|
||||||
"first time you're accessing your Google Drive!",
|
"first time you're accessing your Google Drive!",
|
||||||
log::critical ) ;
|
log::critical ) ;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
OAuth2 token( http.get(), refresh_token, id, secret ) ;
|
OAuth2 token( http.get(), refresh_token, id, secret ) ;
|
||||||
AuthAgent agent( token, http.get() ) ;
|
AuthAgent agent( token, http.get() ) ;
|
||||||
v2::Syncer2 syncer( &agent );
|
v2::Syncer2 syncer( &agent );
|
||||||
|
@ -257,7 +265,7 @@ int Main( int argc, char **argv )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
drive.DryRun() ;
|
drive.DryRun() ;
|
||||||
|
|
||||||
config.Save() ;
|
config.Save() ;
|
||||||
Log( "Finished!", log::info ) ;
|
Log( "Finished!", log::info ) ;
|
||||||
return 0 ;
|
return 0 ;
|
||||||
|
|
|
@ -3,13 +3,19 @@ project(libgrive)
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
||||||
|
|
||||||
find_package(LibGcrypt REQUIRED)
|
find_package(LibGcrypt REQUIRED)
|
||||||
find_package(CURL REQUIRED)
|
if (NOT APPLE)
|
||||||
|
find_package(CURL REQUIRED)
|
||||||
|
endif(NOT APPLE)
|
||||||
find_package(Backtrace)
|
find_package(Backtrace)
|
||||||
find_package(Boost 1.40.0 COMPONENTS program_options filesystem unit_test_framework regex system REQUIRED)
|
find_package(Boost 1.40.0 COMPONENTS program_options filesystem unit_test_framework regex system REQUIRED)
|
||||||
find_package(BFD)
|
find_package(BFD)
|
||||||
find_package(CppUnit)
|
find_package(CppUnit)
|
||||||
find_package(Iberty)
|
find_package(Iberty)
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
find_library(MAC_FRAME_FOUNDATION Foundation ${CMAKE_SYSTEM_FRAMEWORK_PATH} REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
pkg_check_modules(YAJL REQUIRED yajl)
|
pkg_check_modules(YAJL REQUIRED yajl)
|
||||||
|
|
||||||
|
@ -27,13 +33,13 @@ if ( BFD_FOUND AND Backtrace_FOUND )
|
||||||
src/bfd/*.cc
|
src/bfd/*.cc
|
||||||
)
|
)
|
||||||
add_definitions( -DHAVE_BFD )
|
add_definitions( -DHAVE_BFD )
|
||||||
|
|
||||||
endif ( BFD_FOUND AND Backtrace_FOUND )
|
endif ( BFD_FOUND AND Backtrace_FOUND )
|
||||||
|
|
||||||
if ( IBERTY_FOUND )
|
if ( IBERTY_FOUND )
|
||||||
set( OPT_LIBS ${OPT_LIBS} ${IBERTY_LIBRARY} )
|
set( OPT_LIBS ${OPT_LIBS} ${IBERTY_LIBRARY} )
|
||||||
else ( IBERTY_FOUND )
|
else ( IBERTY_FOUND )
|
||||||
set( IBERTY_LIBRARY "" )
|
set( IBERTY_LIBRARY "" )
|
||||||
endif ( IBERTY_FOUND )
|
endif ( IBERTY_FOUND )
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
@ -45,15 +51,15 @@ include_directories(
|
||||||
)
|
)
|
||||||
|
|
||||||
file (GLOB PROTOCOL_HEADERS
|
file (GLOB PROTOCOL_HEADERS
|
||||||
${libgrive_SOURCE_DIR}/src/protocol/*.hh
|
${libgrive_SOURCE_DIR}/src/protocol/*.hh
|
||||||
)
|
)
|
||||||
|
|
||||||
file (GLOB UTIL_HEADERS
|
file (GLOB UTIL_HEADERS
|
||||||
${libgrive_SOURCE_DIR}/src/util/*.hh
|
${libgrive_SOURCE_DIR}/src/util/*.hh
|
||||||
)
|
)
|
||||||
|
|
||||||
file (GLOB XML_HEADERS
|
file (GLOB XML_HEADERS
|
||||||
${libgrive_SOURCE_DIR}/src/xml/*.hh
|
${libgrive_SOURCE_DIR}/src/xml/*.hh
|
||||||
)
|
)
|
||||||
|
|
||||||
file (GLOB LIBGRIVE_SRC
|
file (GLOB LIBGRIVE_SRC
|
||||||
|
@ -66,13 +72,17 @@ file (GLOB LIBGRIVE_SRC
|
||||||
src/util/log/*.cc
|
src/util/log/*.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
file (GLOB LIBGRIVE_SRC_OBJC src/http/*.mm)
|
||||||
|
endif(APPLE)
|
||||||
|
|
||||||
add_definitions(
|
add_definitions(
|
||||||
-DTEST_DATA="${libgrive_SOURCE_DIR}/test/data/"
|
-DTEST_DATA="${libgrive_SOURCE_DIR}/test/data/"
|
||||||
-DSRC_DIR="${libgrive_SOURCE_DIR}/src"
|
-DSRC_DIR="${libgrive_SOURCE_DIR}/src"
|
||||||
)
|
)
|
||||||
|
|
||||||
#add_library( grive SHARED ${LIBGRIVE_SRC} ${OPT_SRC} )
|
#add_library( grive SHARED ${LIBGRIVE_SRC} ${OPT_SRC} ${LIBGRIVE_SRC_OBJC} )
|
||||||
add_library( grive STATIC ${LIBGRIVE_SRC} ${OPT_SRC} )
|
add_library( grive STATIC ${LIBGRIVE_SRC} ${OPT_SRC} ${LIBGRIVE_SRC_OBJC} )
|
||||||
|
|
||||||
target_link_libraries( grive
|
target_link_libraries( grive
|
||||||
${YAJL_LIBRARIES}
|
${YAJL_LIBRARIES}
|
||||||
|
@ -85,6 +95,9 @@ target_link_libraries( grive
|
||||||
${IBERTY_LIBRARY}
|
${IBERTY_LIBRARY}
|
||||||
${OPT_LIBS}
|
${OPT_LIBS}
|
||||||
)
|
)
|
||||||
|
if (APPLE)
|
||||||
|
target_link_libraries(grive ${MAC_FRAME_FOUNDATION})
|
||||||
|
endif(APPLE)
|
||||||
|
|
||||||
#set_target_properties(grive PROPERTIES
|
#set_target_properties(grive PROPERTIES
|
||||||
# SOVERSION 0 VERSION ${GRIVE_VERSION}
|
# SOVERSION 0 VERSION ${GRIVE_VERSION}
|
||||||
|
@ -108,8 +121,7 @@ endif()
|
||||||
IF ( CPPUNIT_FOUND )
|
IF ( CPPUNIT_FOUND )
|
||||||
message("-- Building unitary tests along with the library and the binary")
|
message("-- Building unitary tests along with the library and the binary")
|
||||||
set( OPT_INCS ${CPPUNIT_INCLUDE_DIR} )
|
set( OPT_INCS ${CPPUNIT_INCLUDE_DIR} )
|
||||||
|
# list of test source files here
|
||||||
# list of test source files here
|
|
||||||
file(GLOB TEST_SRC
|
file(GLOB TEST_SRC
|
||||||
test/base/*.cc
|
test/base/*.cc
|
||||||
test/util/*.cc
|
test/util/*.cc
|
||||||
|
@ -124,7 +136,7 @@ IF ( CPPUNIT_FOUND )
|
||||||
grive
|
grive
|
||||||
${CPPUNIT_LIBRARY}
|
${CPPUNIT_LIBRARY}
|
||||||
)
|
)
|
||||||
|
|
||||||
ENDIF ( CPPUNIT_FOUND )
|
ENDIF ( CPPUNIT_FOUND )
|
||||||
|
|
||||||
file(GLOB BTEST_SRC
|
file(GLOB BTEST_SRC
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
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 "Agent.hh"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace gr {
|
||||||
|
|
||||||
|
class DataStream;
|
||||||
|
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
/*! \brief agent to provide HTTP access
|
||||||
|
|
||||||
|
This class provides functions to send HTTP request in many methods (e.g.
|
||||||
|
get, post and put). Normally the HTTP response is returned in a Receivable.
|
||||||
|
*/
|
||||||
|
class NSURLSessionAgent : public Agent {
|
||||||
|
public:
|
||||||
|
NSURLSessionAgent();
|
||||||
|
~NSURLSessionAgent();
|
||||||
|
ResponseLog *GetLog() const;
|
||||||
|
void SetLog( ResponseLog *log );
|
||||||
|
void SetProgressReporter( Progress *progress );
|
||||||
|
long Request( const std::string &method,
|
||||||
|
const std::string &url,
|
||||||
|
SeekStream *in,
|
||||||
|
DataStream *dest,
|
||||||
|
const Header &hdr,
|
||||||
|
u64_t downloadFileBytes = 0 );
|
||||||
|
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:
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Impl;
|
||||||
|
std::unique_ptr<Impl> m_pimpl;
|
||||||
|
std::unique_ptr<ResponseLog> m_log;
|
||||||
|
Progress *m_pb;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace http
|
||||||
|
} // namespace gr
|
|
@ -0,0 +1,147 @@
|
||||||
|
#include "NSURLSessionAgent.hh"
|
||||||
|
|
||||||
|
#include <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#include "Error.hh"
|
||||||
|
#include "Header.hh"
|
||||||
|
#include "util/log/Log.hh"
|
||||||
|
|
||||||
|
namespace gr {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
struct NSURLSessionAgent::Impl {
|
||||||
|
NSURLSession *session;
|
||||||
|
std::string location;
|
||||||
|
bool error;
|
||||||
|
std::string error_headers;
|
||||||
|
std::string error_data;
|
||||||
|
DataStream *dest;
|
||||||
|
u64_t total_download, total_upload;
|
||||||
|
};
|
||||||
|
|
||||||
|
NSURLSessionAgent::NSURLSessionAgent()
|
||||||
|
: Agent(), m_pimpl( new Impl ), m_pb( 0 ) {
|
||||||
|
m_pimpl->session = NSURLSession.sharedSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURLSessionAgent::~NSURLSessionAgent() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSURLSessionAgent::Init() {
|
||||||
|
m_pimpl->error = false;
|
||||||
|
m_pimpl->error_headers = "";
|
||||||
|
m_pimpl->error_data = "";
|
||||||
|
m_pimpl->dest = NULL;
|
||||||
|
m_pimpl->total_download = m_pimpl->total_upload = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseLog *NSURLSessionAgent::GetLog() const {
|
||||||
|
return m_log.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSURLSessionAgent::SetLog( ResponseLog *log ) {
|
||||||
|
m_log.reset( log );
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSURLSessionAgent::SetProgressReporter( Progress *progress ) {
|
||||||
|
m_pb = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
long NSURLSessionAgent::Request( const std::string &method,
|
||||||
|
const std::string &url,
|
||||||
|
SeekStream *in,
|
||||||
|
DataStream *dest,
|
||||||
|
const Header &hdr,
|
||||||
|
u64_t downloadFileBytes ) {
|
||||||
|
Trace( "HTTP %1% \"%2%\"", method, url );
|
||||||
|
|
||||||
|
Init();
|
||||||
|
m_pimpl->total_download = downloadFileBytes;
|
||||||
|
m_pimpl->dest = dest;
|
||||||
|
|
||||||
|
NSURL *nsurl =
|
||||||
|
[NSURL URLWithString:[NSString stringWithUTF8String:url.c_str()]];
|
||||||
|
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:nsurl];
|
||||||
|
req.HTTPMethod = [NSString stringWithUTF8String:method.c_str()];
|
||||||
|
|
||||||
|
const auto colon = std::string( ":" );
|
||||||
|
for ( auto it = hdr.begin(); it != hdr.end(); it++ ) {
|
||||||
|
const auto index = it->find_first_of( colon );
|
||||||
|
[req setValue:[[NSString
|
||||||
|
stringWithUTF8String:it->substr( index + 1 ).c_str()]
|
||||||
|
stringByTrimmingCharactersInSet:
|
||||||
|
NSCharacterSet.whitespaceAndNewlineCharacterSet]
|
||||||
|
forHTTPHeaderField:
|
||||||
|
[[NSString stringWithUTF8String:it->substr( 0, index ).c_str()]
|
||||||
|
stringByTrimmingCharactersInSet:
|
||||||
|
NSCharacterSet.whitespaceAndNewlineCharacterSet]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( in ) {
|
||||||
|
char *ptr = static_cast<char *>( malloc( in->Size() ) );
|
||||||
|
std::size_t n = in->Read( ptr, in->Size() );
|
||||||
|
assert( n == in->Size() );
|
||||||
|
req.HTTPBody = [NSData dataWithBytes:ptr
|
||||||
|
length:( NSUInteger )in->Size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
__block NSInteger statusCode = 0;
|
||||||
|
dispatch_semaphore_t sema = dispatch_semaphore_create( 0 );
|
||||||
|
[[m_pimpl->session
|
||||||
|
dataTaskWithRequest:req
|
||||||
|
completionHandler:^(
|
||||||
|
NSData *data, NSURLResponse *response, NSError *error ) {
|
||||||
|
m_pimpl->total_download += data.length;
|
||||||
|
if ( error ) {
|
||||||
|
m_pimpl->error = true;
|
||||||
|
m_pimpl->error_data.append(
|
||||||
|
error.localizedDescription.UTF8String,
|
||||||
|
error.localizedDescription.length );
|
||||||
|
m_pimpl->error_headers = hdr.Str();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert( data.bytes != nil );
|
||||||
|
statusCode = ( ( NSHTTPURLResponse * )response ).statusCode;
|
||||||
|
if ( statusCode < 200 || statusCode > 299 ) {
|
||||||
|
m_pimpl->error = true;
|
||||||
|
m_pimpl->error_data.append(
|
||||||
|
static_cast<const char *>( data.bytes ) );
|
||||||
|
}
|
||||||
|
m_pimpl->dest->Write( static_cast<const char *>( data.bytes ),
|
||||||
|
data.length );
|
||||||
|
dispatch_semaphore_signal( sema );
|
||||||
|
}] resume];
|
||||||
|
dispatch_semaphore_wait( sema, dispatch_time( DISPATCH_TIME_NOW, 30e9 ) );
|
||||||
|
|
||||||
|
if ( m_pimpl->error ) {
|
||||||
|
BOOST_THROW_EXCEPTION( Error()
|
||||||
|
<< Url( url ) << HttpRequestHeaders( hdr )
|
||||||
|
<< HttpResponseCode( statusCode )
|
||||||
|
<< HttpResponseText( m_pimpl->error_data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NSURLSessionAgent::LastError() const {
|
||||||
|
return m_pimpl->error_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NSURLSessionAgent::LastErrorHeaders() const {
|
||||||
|
return m_pimpl->error_headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NSURLSessionAgent::RedirLocation() const {
|
||||||
|
return m_pimpl->location;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NSURLSessionAgent::Escape( const std::string &str ) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NSURLSessionAgent::Unescape( const std::string &str ) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue