mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-01 12:30:50 +00:00
753 lines
19 KiB
Objective-C
753 lines
19 KiB
Objective-C
#import "GSURLPrivate.h"
|
|
#import "GSEasyHandle.h"
|
|
#import "GSTimeoutSource.h"
|
|
#import "Foundation/NSCharacterSet.h"
|
|
#import "Foundation/NSURLSession.h"
|
|
|
|
typedef NS_OPTIONS(NSUInteger, GSEasyHandlePauseState) {
|
|
GSEasyHandlePauseStateReceive = 1 << 0,
|
|
GSEasyHandlePauseStateSend = 1 << 1
|
|
};
|
|
|
|
@interface GSEasyHandle ()
|
|
|
|
- (void) resetTimer;
|
|
|
|
- (NSInteger) didReceiveData: (char*)data
|
|
size: (NSInteger)size
|
|
nmemb:(NSInteger)nmemb;
|
|
|
|
- (NSInteger) fillWriteBuffer: (char *)buffer
|
|
size: (NSInteger)size
|
|
nmemb: (NSInteger)nmemb;
|
|
|
|
- (NSInteger) didReceiveHeaderData: (char*)headerData
|
|
size: (NSInteger)size
|
|
nmemb: (NSInteger)nmemb
|
|
contentLength: (double)contentLength;
|
|
|
|
- (int) seekInputStreamWithOffset: (int64_t)offset
|
|
origin: (NSInteger)origin;
|
|
|
|
@end
|
|
|
|
static void
|
|
handleEasyCode(int code)
|
|
{
|
|
if (CURLE_OK != code)
|
|
{
|
|
NSString *reason;
|
|
NSException *e;
|
|
|
|
reason = [NSString stringWithFormat: @"An error occurred, CURLcode is %d",
|
|
code];
|
|
e = [NSException exceptionWithName: @"libcurl.easy"
|
|
reason: reason
|
|
userInfo: nil];
|
|
[e raise];
|
|
}
|
|
}
|
|
|
|
static size_t
|
|
curl_write_function(char *data, size_t size, size_t nmemb, void *userdata)
|
|
{
|
|
if (!userdata)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
GSEasyHandle *handle = (GSEasyHandle*)userdata;
|
|
|
|
[handle resetTimer]; //FIXME should be deffered after the function returns?
|
|
|
|
return [handle didReceiveData:data size:size nmemb:nmemb];
|
|
}
|
|
|
|
static size_t
|
|
curl_read_function(char *data, size_t size, size_t nmemb, void *userdata)
|
|
{
|
|
if (!userdata)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
GSEasyHandle *handle = (GSEasyHandle*)userdata;
|
|
|
|
[handle resetTimer]; //FIXME should be deffered after the function returns?
|
|
|
|
return [handle fillWriteBuffer: data size: size nmemb: nmemb];
|
|
}
|
|
|
|
size_t
|
|
curl_header_function(char *data, size_t size, size_t nmemb, void *userdata)
|
|
{
|
|
if (!userdata)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
GSEasyHandle *handle = (GSEasyHandle*)userdata;
|
|
double length;
|
|
|
|
[handle resetTimer]; //FIXME should be deffered after the function returns?
|
|
|
|
handleEasyCode(curl_easy_getinfo(handle.rawHandle,
|
|
CURLINFO_CONTENT_LENGTH_DOWNLOAD, &length));
|
|
|
|
return [handle didReceiveHeaderData: data
|
|
size: size
|
|
nmemb: nmemb
|
|
contentLength: length];
|
|
}
|
|
|
|
static int
|
|
curl_seek_function(void *userdata, curl_off_t offset, int origin)
|
|
{
|
|
if (!userdata)
|
|
{
|
|
return CURL_SEEKFUNC_FAIL;
|
|
}
|
|
|
|
GSEasyHandle *handle = (GSEasyHandle*)userdata;
|
|
|
|
return [handle seekInputStreamWithOffset: offset origin: origin];
|
|
}
|
|
|
|
static int
|
|
curl_debug_function(CURL *handle, curl_infotype type, char *data,
|
|
size_t size, void *userptr)
|
|
{
|
|
if (!userptr)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (CURLINFO_SSL_DATA_OUT == type || CURLINFO_SSL_DATA_IN == type)
|
|
{
|
|
return 0; // Don't log encrypted data here
|
|
}
|
|
|
|
NSURLSessionTask *task = (NSURLSessionTask*)userptr;
|
|
NSString *text = @"";
|
|
NSURLRequest *o = [task originalRequest];
|
|
NSURLRequest *r = [task currentRequest];
|
|
id<GSLogDelegate> d = [(nil == r ? o : r) _debugLogDelegate];
|
|
|
|
if (d != nil)
|
|
{
|
|
if (CURLINFO_DATA_IN == type || CURLINFO_HEADER_IN == type)
|
|
{
|
|
if ([d getBytes: (const uint8_t *)data ofLength: size byHandle: o])
|
|
{
|
|
return 0; // Handled
|
|
}
|
|
}
|
|
if (CURLINFO_DATA_OUT == type || CURLINFO_HEADER_OUT == type)
|
|
{
|
|
if ([d putBytes: (const uint8_t *)data ofLength: size byHandle: o])
|
|
{
|
|
return 0; // Handled
|
|
}
|
|
}
|
|
}
|
|
if (data)
|
|
{
|
|
text = [NSString stringWithUTF8String: data];
|
|
}
|
|
|
|
NSLog(@"%p %lu %d %@", o, (unsigned long)[task taskIdentifier], type, text);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
curl_socket_function(void *userdata, curl_socket_t fd, curlsocktype type)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
@implementation GSEasyHandle
|
|
{
|
|
NSURLSessionConfiguration *_config;
|
|
GSEasyHandlePauseState _pauseState;
|
|
struct curl_slist *_headerList;
|
|
}
|
|
|
|
- (instancetype) initWithDelegate: (id<GSEasyHandleDelegate>)delegate
|
|
{
|
|
if (nil != (self = [super init]))
|
|
{
|
|
_rawHandle = curl_easy_init();
|
|
_delegate = delegate;
|
|
|
|
char *eb = (char *)malloc(sizeof(char) * (CURL_ERROR_SIZE + 1));
|
|
_errorBuffer = memset(eb, 0, sizeof(char) * (CURL_ERROR_SIZE + 1));
|
|
|
|
[self setupCallbacks];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
curl_easy_cleanup(_rawHandle);
|
|
curl_slist_free_all(_headerList);
|
|
free(_errorBuffer);
|
|
DESTROY(_config);
|
|
[_timeoutTimer cancel];
|
|
DESTROY(_timeoutTimer);
|
|
DESTROY(_URL);
|
|
[super dealloc];
|
|
}
|
|
|
|
- (CURL*) rawHandle
|
|
{
|
|
return _rawHandle;
|
|
}
|
|
|
|
- (char*) errorBuffer
|
|
{
|
|
return _errorBuffer;
|
|
}
|
|
|
|
- (GSTimeoutSource*) timeoutTimer
|
|
{
|
|
return _timeoutTimer;
|
|
}
|
|
|
|
- (void) setTimeoutTimer: (GSTimeoutSource*)timer
|
|
{
|
|
[_timeoutTimer cancel];
|
|
ASSIGN(_timeoutTimer, timer);
|
|
}
|
|
|
|
- (NSURL*) URL
|
|
{
|
|
return _URL;
|
|
}
|
|
|
|
- (void) transferCompletedWithError: (NSError*)error
|
|
{
|
|
[_delegate transferCompletedWithError: error];
|
|
}
|
|
|
|
- (void) resetTimer
|
|
{
|
|
[_timeoutTimer setTimeout: [_timeoutTimer timeout]];
|
|
}
|
|
|
|
- (void) setupCallbacks
|
|
{
|
|
// write
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_WRITEDATA, self));
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_WRITEFUNCTION,
|
|
curl_write_function));
|
|
|
|
// read
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_READDATA, self));
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_READFUNCTION,
|
|
curl_read_function));
|
|
|
|
// header
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_HEADERDATA, self));
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_HEADERFUNCTION,
|
|
curl_header_function));
|
|
|
|
// socket options
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_SOCKOPTDATA, self));
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_SOCKOPTFUNCTION,
|
|
curl_socket_function));
|
|
|
|
// seeking in input stream
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_SEEKDATA, self));
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_SEEKFUNCTION,
|
|
curl_seek_function));
|
|
}
|
|
|
|
- (int) urlErrorCodeWithEasyCode: (int)easyCode
|
|
{
|
|
int failureErrno = (int)[self connectFailureErrno];
|
|
|
|
if (easyCode == CURLE_OK)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (failureErrno == ECONNREFUSED)
|
|
{
|
|
return NSURLErrorCannotConnectToHost;
|
|
}
|
|
else if (easyCode == CURLE_UNSUPPORTED_PROTOCOL)
|
|
{
|
|
return NSURLErrorUnsupportedURL;
|
|
}
|
|
else if (easyCode == CURLE_URL_MALFORMAT)
|
|
{
|
|
return NSURLErrorBadURL;
|
|
}
|
|
else if (easyCode == CURLE_COULDNT_RESOLVE_HOST)
|
|
{
|
|
return NSURLErrorCannotFindHost;
|
|
}
|
|
else if (easyCode == CURLE_RECV_ERROR && failureErrno == ECONNRESET)
|
|
{
|
|
return NSURLErrorNetworkConnectionLost;
|
|
}
|
|
else if (easyCode == CURLE_SEND_ERROR && failureErrno == ECONNRESET)
|
|
{
|
|
return NSURLErrorNetworkConnectionLost;
|
|
}
|
|
else if (easyCode == CURLE_GOT_NOTHING)
|
|
{
|
|
return NSURLErrorBadServerResponse;
|
|
}
|
|
else if (easyCode == CURLE_ABORTED_BY_CALLBACK)
|
|
{
|
|
return NSURLErrorUnknown;
|
|
}
|
|
else if (easyCode == CURLE_COULDNT_CONNECT && failureErrno == ETIMEDOUT)
|
|
{
|
|
return NSURLErrorTimedOut;
|
|
}
|
|
else if (easyCode == CURLE_OPERATION_TIMEDOUT)
|
|
{
|
|
return NSURLErrorTimedOut;
|
|
}
|
|
else
|
|
{
|
|
return NSURLErrorUnknown;
|
|
}
|
|
}
|
|
|
|
- (void) setVerboseMode: (BOOL)flag
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_VERBOSE, flag ? 1 : 0));
|
|
}
|
|
|
|
- (void) setDebugOutput: (BOOL)flag
|
|
task: (NSURLSessionTask*)task
|
|
{
|
|
if (flag)
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_DEBUGDATA, task));
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_DEBUGFUNCTION,
|
|
curl_debug_function));
|
|
}
|
|
else
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_DEBUGDATA, NULL));
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_DEBUGFUNCTION, NULL));
|
|
}
|
|
}
|
|
|
|
- (void) setPassHeadersToDataStream: (BOOL)flag
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_HEADER,
|
|
flag ? 1 : 0));
|
|
}
|
|
|
|
- (void) setFollowLocation: (BOOL)flag
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_FOLLOWLOCATION,
|
|
flag ? 1 : 0));
|
|
}
|
|
|
|
- (void) setProgressMeterOff: (BOOL)flag
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_NOPROGRESS,
|
|
flag ? 1 : 0));
|
|
}
|
|
|
|
- (void) setSkipAllSignalHandling: (BOOL)flag
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_NOSIGNAL,
|
|
flag ? 1 : 0));
|
|
}
|
|
|
|
- (void) setErrorBuffer: (char*)buffer
|
|
{
|
|
char *b = buffer ? buffer : _errorBuffer;
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_ERRORBUFFER, b));
|
|
}
|
|
|
|
- (void) setFailOnHTTPErrorCode: (BOOL)flag
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_FAILONERROR,
|
|
flag ? 1 : 0));
|
|
}
|
|
|
|
- (void) setURL: (NSURL *)URL
|
|
{
|
|
ASSIGN(_URL, URL);
|
|
if (nil != [URL absoluteString])
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_URL,
|
|
[[URL absoluteString] UTF8String]));
|
|
}
|
|
}
|
|
|
|
- (void) setPipeWait: (BOOL)flag
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_PIPEWAIT, flag ? 1 : 0));
|
|
}
|
|
|
|
- (void) setConnectToHost: (NSString*)host port: (NSInteger)port
|
|
{
|
|
if (nil != host)
|
|
{
|
|
NSString *originHost = [_URL host];
|
|
NSString *value = nil;
|
|
|
|
if (0 == port)
|
|
{
|
|
value = [NSString stringWithFormat: @"%@::%@", originHost, host];
|
|
}
|
|
else
|
|
{
|
|
value = [NSString stringWithFormat: @"%@:%lu:%@",
|
|
originHost, (unsigned long)port, host];
|
|
}
|
|
|
|
struct curl_slist *connect_to = NULL;
|
|
connect_to = curl_slist_append(NULL, [value UTF8String]);
|
|
handleEasyCode(
|
|
curl_easy_setopt(_rawHandle, CURLOPT_CONNECT_TO, connect_to));
|
|
}
|
|
}
|
|
|
|
- (void) setSessionConfig: (NSURLSessionConfiguration*)config
|
|
{
|
|
ASSIGN(_config, config);
|
|
#if defined(CURLOPT_MAXAGE_CONN)
|
|
/* This specifies the maximum age of a connection if it is to be considered
|
|
* a candidate for re-use. By default curl currently uses 118 seconds, so
|
|
* this is what we will get if the configuration does not contain a positive
|
|
* number of seconds.
|
|
*/
|
|
if ([config HTTPMaximumConnectionLifetime] > 0)
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_MAXAGE_CONN,
|
|
(long)[config HTTPMaximumConnectionLifetime]));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
- (void) setAllowedProtocolsToHTTPAndHTTPS
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_PROTOCOLS,
|
|
CURLPROTO_HTTP | CURLPROTO_HTTPS));
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_REDIR_PROTOCOLS,
|
|
CURLPROTO_HTTP | CURLPROTO_HTTPS));
|
|
}
|
|
|
|
- (void) setPreferredReceiveBufferSize: (NSInteger)size
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_BUFFERSIZE,
|
|
MIN(size, CURL_MAX_WRITE_SIZE)));
|
|
}
|
|
|
|
- (void) setCustomHeaders: (NSArray*)headers
|
|
{
|
|
NSEnumerator *e;
|
|
NSString *h;
|
|
|
|
e = [headers objectEnumerator];
|
|
while (nil != (h = [e nextObject]))
|
|
{
|
|
_headerList = curl_slist_append(_headerList, [h UTF8String]);
|
|
}
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_HTTPHEADER, _headerList));
|
|
}
|
|
|
|
- (void) setAutomaticBodyDecompression: (BOOL)flag
|
|
{
|
|
if (flag)
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle,
|
|
CURLOPT_ACCEPT_ENCODING, ""));
|
|
handleEasyCode(curl_easy_setopt(_rawHandle,
|
|
CURLOPT_HTTP_CONTENT_DECODING, 1));
|
|
}
|
|
else
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle,
|
|
CURLOPT_ACCEPT_ENCODING, NULL));
|
|
handleEasyCode(curl_easy_setopt(_rawHandle,
|
|
CURLOPT_HTTP_CONTENT_DECODING, 0));
|
|
}
|
|
}
|
|
|
|
- (void) setRequestMethod: (NSString*)method
|
|
{
|
|
if (nil == method)
|
|
{
|
|
return;
|
|
}
|
|
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_CUSTOMREQUEST,
|
|
[method UTF8String]));
|
|
}
|
|
|
|
- (void) setNoBody: (BOOL)flag
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_NOBODY,
|
|
flag ? 1 : 0));
|
|
}
|
|
|
|
- (void) setUpload: (BOOL)flag
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_UPLOAD, flag ? 1 : 0));
|
|
}
|
|
|
|
- (void) setRequestBodyLength: (int64_t)length
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_INFILESIZE_LARGE,
|
|
length));
|
|
}
|
|
|
|
- (void) setTimeout: (NSInteger)timeout
|
|
{
|
|
handleEasyCode(curl_easy_setopt(_rawHandle, CURLOPT_TIMEOUT,
|
|
(long)timeout));
|
|
}
|
|
|
|
- (void) setProxy
|
|
{
|
|
//TODO setup proxy
|
|
}
|
|
|
|
- (void) updatePauseState: (GSEasyHandlePauseState)pauseState
|
|
{
|
|
NSUInteger send = pauseState & GSEasyHandlePauseStateSend;
|
|
NSUInteger receive = pauseState & GSEasyHandlePauseStateReceive;
|
|
int bitmask;
|
|
|
|
bitmask = 0
|
|
| (send ? CURLPAUSE_SEND : CURLPAUSE_SEND_CONT)
|
|
| (receive ? CURLPAUSE_RECV : CURLPAUSE_RECV_CONT);
|
|
handleEasyCode(curl_easy_pause(_rawHandle, bitmask));
|
|
}
|
|
|
|
- (double) getTimeoutIntervalSpent
|
|
{
|
|
double timeSpent;
|
|
curl_easy_getinfo(_rawHandle, CURLINFO_TOTAL_TIME, &timeSpent);
|
|
return timeSpent / 1000;
|
|
}
|
|
|
|
- (long) connectFailureErrno
|
|
{
|
|
long _errno;
|
|
handleEasyCode(curl_easy_getinfo(_rawHandle, CURLINFO_OS_ERRNO, &_errno));
|
|
return _errno;
|
|
}
|
|
|
|
- (void) pauseSend
|
|
{
|
|
if (_pauseState & GSEasyHandlePauseStateSend)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_pauseState = _pauseState | GSEasyHandlePauseStateSend;
|
|
[self updatePauseState: _pauseState];
|
|
}
|
|
|
|
- (void) unpauseSend
|
|
{
|
|
if (!(_pauseState & GSEasyHandlePauseStateSend))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_pauseState = _pauseState ^ GSEasyHandlePauseStateSend;
|
|
[self updatePauseState: _pauseState];
|
|
}
|
|
|
|
- (void) pauseReceive
|
|
{
|
|
if (_pauseState & GSEasyHandlePauseStateReceive)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_pauseState = _pauseState | GSEasyHandlePauseStateReceive;
|
|
[self updatePauseState: _pauseState];
|
|
}
|
|
|
|
- (void) unpauseReceive
|
|
{
|
|
if (!(_pauseState & GSEasyHandlePauseStateReceive))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_pauseState = _pauseState ^ GSEasyHandlePauseStateReceive;
|
|
[self updatePauseState: _pauseState];
|
|
}
|
|
|
|
- (NSInteger) didReceiveData: (char*)data
|
|
size: (NSInteger)size
|
|
nmemb: (NSInteger)nmemb
|
|
{
|
|
NSData *buffer;
|
|
GSEasyHandleAction action;
|
|
NSUInteger bytes;
|
|
|
|
if (![_delegate respondsToSelector: @selector(didReceiveData:)])
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
bytes = size * nmemb;
|
|
buffer = AUTORELEASE([[NSData alloc] initWithBytes: data length: bytes]);
|
|
action = [_delegate didReceiveData: buffer];
|
|
switch (action)
|
|
{
|
|
case GSEasyHandleActionProceed:
|
|
return bytes;
|
|
case GSEasyHandleActionAbort:
|
|
return 0;
|
|
case GSEasyHandleActionPause:
|
|
_pauseState = _pauseState | GSEasyHandlePauseStateReceive;
|
|
return CURL_WRITEFUNC_PAUSE;
|
|
}
|
|
}
|
|
|
|
- (NSInteger) didReceiveHeaderData: (char*)headerData
|
|
size: (NSInteger)size
|
|
nmemb: (NSInteger)nmemb
|
|
contentLength: (double)contentLength
|
|
{
|
|
NSData *buffer;
|
|
GSEasyHandleAction action;
|
|
NSInteger bytes = size * nmemb;
|
|
|
|
buffer = [NSData dataWithBytes: headerData length: bytes];
|
|
|
|
[self setCookiesWithHeaderData: buffer];
|
|
|
|
if (![_delegate respondsToSelector:
|
|
@selector(didReceiveHeaderData:contentLength:)])
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
action = [_delegate didReceiveHeaderData: buffer
|
|
contentLength: (int64_t)contentLength];
|
|
switch (action)
|
|
{
|
|
case GSEasyHandleActionProceed:
|
|
return bytes;
|
|
case GSEasyHandleActionAbort:
|
|
return 0;
|
|
case GSEasyHandleActionPause:
|
|
_pauseState = _pauseState | GSEasyHandlePauseStateReceive;
|
|
return CURL_WRITEFUNC_PAUSE;
|
|
}
|
|
}
|
|
|
|
- (NSInteger) fillWriteBuffer: (char*)buffer
|
|
size: (NSInteger)size
|
|
nmemb: (NSInteger)nmemb
|
|
{
|
|
__block NSInteger d;
|
|
|
|
if (![_delegate respondsToSelector: @selector(fillWriteBufferLength:result:)])
|
|
{
|
|
return CURL_READFUNC_ABORT;
|
|
}
|
|
|
|
[_delegate fillWriteBufferLength: size * nmemb
|
|
result: ^(GSEasyHandleWriteBufferResult result, NSInteger length, NSData *data)
|
|
{
|
|
switch (result)
|
|
{
|
|
case GSEasyHandleWriteBufferResultPause:
|
|
_pauseState = _pauseState | GSEasyHandlePauseStateSend;
|
|
d = CURL_READFUNC_PAUSE;
|
|
break;
|
|
case GSEasyHandleWriteBufferResultAbort:
|
|
d = CURL_READFUNC_ABORT;
|
|
break;
|
|
case GSEasyHandleWriteBufferResultBytes:
|
|
memcpy(buffer, [data bytes], length);
|
|
d = length;
|
|
break;
|
|
}
|
|
}];
|
|
|
|
return d;
|
|
}
|
|
|
|
- (int) seekInputStreamWithOffset: (int64_t)offset
|
|
origin: (NSInteger)origin
|
|
{
|
|
NSAssert(SEEK_SET == origin, @"Unexpected 'origin' in seek.");
|
|
|
|
if (![_delegate respondsToSelector: @selector(seekInputStreamToPosition:)])
|
|
{
|
|
return CURL_SEEKFUNC_CANTSEEK;
|
|
}
|
|
|
|
if ([_delegate seekInputStreamToPosition: offset])
|
|
{
|
|
return CURL_SEEKFUNC_OK;
|
|
}
|
|
else
|
|
{
|
|
return CURL_SEEKFUNC_CANTSEEK;
|
|
}
|
|
}
|
|
|
|
- (void) setCookiesWithHeaderData: (NSData*)data
|
|
{
|
|
NSString *headerLine;
|
|
NSRange r;
|
|
NSString *head;
|
|
NSString *tail;
|
|
NSCharacterSet *set;
|
|
NSString *key;
|
|
NSString *value;
|
|
NSArray *cookies;
|
|
NSDictionary *d;
|
|
|
|
if (nil != _config
|
|
&& NSHTTPCookieAcceptPolicyNever != [_config HTTPCookieAcceptPolicy]
|
|
&& nil != [_config HTTPCookieStorage])
|
|
{
|
|
headerLine = [[NSString alloc] initWithData: data
|
|
encoding: NSUTF8StringEncoding];
|
|
if (0 == [headerLine length])
|
|
{
|
|
RELEASE(headerLine);
|
|
return;
|
|
}
|
|
|
|
r = [headerLine rangeOfString: @":"];
|
|
if (NSNotFound != r.location)
|
|
{
|
|
head = [headerLine substringToIndex:r.location];
|
|
tail = [headerLine substringFromIndex:r.location + 1];
|
|
set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
|
key = [head stringByTrimmingCharactersInSet:set];
|
|
value = [tail stringByTrimmingCharactersInSet:set];
|
|
|
|
if (nil != key && nil != value)
|
|
{
|
|
d = [NSDictionary dictionaryWithObject: value forKey: key];
|
|
cookies = [NSHTTPCookie cookiesWithResponseHeaderFields: d
|
|
forURL: _URL];
|
|
if ([cookies count] > 0)
|
|
{
|
|
[[_config HTTPCookieStorage] setCookies: cookies
|
|
forURL: _URL
|
|
mainDocumentURL: nil];
|
|
}
|
|
}
|
|
}
|
|
RELEASE(headerLine);
|
|
}
|
|
}
|
|
|
|
@end
|