Index: src/OFHTTPClient.h ================================================================== --- src/OFHTTPClient.h +++ src/OFHTTPClient.h @@ -39,26 +39,32 @@ * @brief A callback which is called when an OFHTTPClient performed a request. * * @param client The OFHTTPClient which performed the request * @param request The request the OFHTTPClient performed * @param response The response to the request performed + * @param context The context object that was passed to + * @ref asyncPerformRequest:context: */ - (void)client: (OFHTTPClient *)client didPerformRequest: (OFHTTPRequest *)request - response: (OFHTTPResponse *)response; + response: (OFHTTPResponse *)response + context: (nullable id)context; /*! * @brief A callback which is called when an OFHTTPClient encountered an * exception while performing a request. * * @param client The client which encountered an exception * @param exception The exception the client encountered * @param request The request during which the client encountered the exception + * @param context The context object that was passed to + * @ref asyncPerformRequest:context: */ - (void)client: (OFHTTPClient *)client didEncounterException: (id)exception - forRequest: (OFHTTPRequest *)request; + forRequest: (OFHTTPRequest *)request + context: (nullable id)context; @optional /*! * @brief A callback which is called when an OFHTTPClient creates a socket. * @@ -68,28 +74,34 @@ * proxy it should use for this connection. * * @param client The OFHTTPClient that created a socket * @param socket The socket created by the OFHTTPClient * @param request The request for which the socket was created + * @param context The context object that was passed to + * @ref asyncPerformRequest:context: */ - (void)client: (OFHTTPClient *)client didCreateSocket: (OF_KINDOF(OFTCPSocket *))socket - forRequest: (OFHTTPRequest *)request; + forRequest: (OFHTTPRequest *)request + context: (nullable id)context; /*! * @brief A callback which is called when an OFHTTPClient received headers. * * @param client The OFHTTPClient which received the headers * @param headers The headers received * @param statusCode The status code received * @param request The request for which the headers and status code have been * received + * @param context The context object that was passed to + * @ref asyncPerformRequest:context: */ - (void)client: (OFHTTPClient *)client didReceiveHeaders: (OFDictionary OF_GENERIC(OFString *, OFString *) *)headers statusCode: (int)statusCode - request: (OFHTTPRequest *)request; + request: (OFHTTPRequest *)request + context: (nullable id)context; /*! * @brief A callback which is called when an OFHTTPClient wants to follow a * redirect. * @@ -109,17 +121,20 @@ * You are allowed to change the request's headers from this * callback and they will be used when following the redirect * (e.g. to set the cookies for the new URL), however, keep in * mind that this will change the request you originally passed. * @param response The response indicating the redirect + * @param context The context object that was passed to + * @ref asyncPerformRequest:context: * @return A boolean whether the OFHTTPClient should follow the redirect */ - (bool)client: (OFHTTPClient *)client shouldFollowRedirect: (OFURL *)URL statusCode: (int)statusCode request: (OFHTTPRequest *)request - response: (OFHTTPResponse *)response; + response: (OFHTTPResponse *)response + context: (nullable id)context; @end /*! * @class OFHTTPClient OFHTTPClient.h ObjFW/OFHTTPClient.h * @@ -156,26 +171,32 @@ */ + (instancetype)client; /*! * @brief Asynchronously performs the specified HTTP request. + * + * @param request The request to perform + * @param context A context object to be passed to the delegate */ -- (void)asyncPerformRequest: (OFHTTPRequest *)request; +- (void)asyncPerformRequest: (OFHTTPRequest *)request + context: (nullable id)context; /*! * @brief Asynchronously performs the specified HTTP request. * * @param request The request to perform * @param redirects The maximum number of redirects after which no further * attempt is done to follow the redirect, but instead the * redirect is treated as an OFHTTPResponse + * @param context A context object to be passed to the delegate */ - (void)asyncPerformRequest: (OFHTTPRequest *)request - redirects: (unsigned int)redirects; + redirects: (unsigned int)redirects + context: (nullable id)context; /*! * @brief Closes connections that are still open due to keep-alive. */ - (void)close; @end OF_ASSUME_NONNULL_END Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -47,19 +47,21 @@ @interface OFHTTPClientRequestHandler: OFObject { OFHTTPClient *_client; OFHTTPRequest *_request; unsigned int _redirects; + id _context; bool _firstLine; OFString *_version; int _status; OFMutableDictionary OF_GENERIC(OFString *, OFString *) *_serverHeaders; } - initWithClient: (OFHTTPClient *)client request: (OFHTTPRequest *)request - redirects: (unsigned int)redirects; + redirects: (unsigned int)redirects + context: (id)context; - (void)start; @end @interface OFHTTPClientResponse: OFHTTPResponse { @@ -203,17 +205,19 @@ @implementation OFHTTPClientRequestHandler - initWithClient: (OFHTTPClient *)client request: (OFHTTPRequest *)request redirects: (unsigned int)redirects + context: (id)context { self = [super init]; @try { _client = [client retain]; _request = [request retain]; _redirects = redirects; + _context = [context retain]; _firstLine = true; _serverHeaders = [[OFMutableDictionary alloc] init]; } @catch (id e) { [self release]; @throw e; @@ -224,10 +228,11 @@ - (void)dealloc { [_client release]; [_request release]; + [_context release]; [_version release]; [_serverHeaders release]; [super dealloc]; } @@ -307,17 +312,18 @@ bool follow; newURL = [OFURL URLWithString: location relativeToURL: URL]; - if ([_client->_delegate respondsToSelector: @selector( - client:shouldFollowRedirect:statusCode:request:response:)]) + if ([_client->_delegate respondsToSelector: @selector(client: + shouldFollowRedirect:statusCode:request:response:context:)]) follow = [_client->_delegate client: _client shouldFollowRedirect: newURL statusCode: _status request: _request - response: response]; + response: response + context: _context]; else { of_http_request_method_t method = [_request method]; /* * 301, 302 and 307 should only redirect with user @@ -377,11 +383,12 @@ [newRequest setHeaders: newHeaders]; _client->_inProgress = false; [_client asyncPerformRequest: newRequest - redirects: _redirects - 1]; + redirects: _redirects - 1 + context: _context]; return; } } if (_status / 100 != 2) @@ -390,14 +397,15 @@ response: response]; _client->_inProgress = false; [_client->_delegate performSelector: @selector(client:didPerformRequest: - response:) + response:context:) withObject: _client withObject: _request withObject: response + withObject: _context afterDelay: 0]; } - (bool)handleFirstLine: (OFString *)line { @@ -436,16 +444,17 @@ @throw [OFInvalidServerReplyException exception]; if ([line length] == 0) { [_serverHeaders makeImmutable]; - if ([_client->_delegate respondsToSelector: - @selector(client:didReceiveHeaders:statusCode:request:)]) + if ([_client->_delegate respondsToSelector: @selector(client: + didReceiveHeaders:statusCode:request:context:)]) [_client->_delegate client: _client didReceiveHeaders: _serverHeaders statusCode: _status - request: _request]; + request: _request + context: _context]; [self performSelector: @selector(createResponseWithSocket:) withObject: socket afterDelay: 0]; @@ -499,11 +508,12 @@ [OFInvalidEncodingException class]]) exception = [OFInvalidServerReplyException exception]; [_client->_delegate client: _client didEncounterException: exception - forRequest: _request]; + forRequest: _request + context: _context]; return false; } @try { if (_firstLine) { @@ -513,11 +523,12 @@ return [self handleServerHeader: line socket: socket]; } @catch (id e) { [_client->_delegate client: _client didEncounterException: e - forRequest: _request]; + forRequest: _request + context: _context]; return false; } } - (size_t)socket: (OFTCPSocket *)socket @@ -527,11 +538,12 @@ exception: (id)exception { if (exception != nil) { [_client->_delegate client: _client didEncounterException: exception - forRequest: _request]; + forRequest: _request + context: _context]; return 0; } [socket asyncReadLineWithTarget: self selector: @selector(socket:didReadLine:context: @@ -557,11 +569,12 @@ return false; } [_client->_delegate client: _client didEncounterException: exception - forRequest: _request]; + forRequest: _request + context: _context]; return 0; } if ((body = [_request body]) != nil) { [socket asyncWriteBuffer: [body items] @@ -606,24 +619,26 @@ length:context:exception:) context: requestString]; } @catch (id e) { [_client->_delegate client: _client didEncounterException: e - forRequest: _request]; + forRequest: _request + context: _context]; return; } } - (void)socketDidConnect: (OFTCPSocket *)socket context: (id)context exception: (id)exception { if ([_client->_delegate respondsToSelector: - @selector(client:didCreateSocket:forRequest:)]) + @selector(client:didCreateSocket:forRequest:context:)]) [_client->_delegate client: _client didCreateSocket: socket - forRequest: _request]; + forRequest: _request + context: _context]; [self performSelector: @selector(handleSocket:) withObject: socket afterDelay: 0]; } @@ -635,11 +650,12 @@ exception: (id)exception { if (exception != nil) { [_client->_delegate client: _client didEncounterException: exception - forRequest: _request]; + forRequest: _request + context: _context]; return false; } if ([response isAtEndOfStream]) { [self freeMemory: buffer]; @@ -686,11 +702,11 @@ length: 512 target: self selector: @selector(throwAwayContent: buffer:length:context: exception:) - context: socket]; + context: socket]; } else { [_client->_lastResponse release]; _client->_lastResponse = nil; [self performSelector: @selector(handleSocket:) @@ -914,17 +930,20 @@ [super dealloc]; } - (void)asyncPerformRequest: (OFHTTPRequest *)request + context: (id)context { [self asyncPerformRequest: request - redirects: 10]; + redirects: 10 + context: context]; } - (void)asyncPerformRequest: (OFHTTPRequest *)request redirects: (unsigned int)redirects + context: (id)context { void *pool = objc_autoreleasePoolPush(); OFURL *URL = [request URL]; OFString *scheme = [URL scheme]; @@ -938,11 +957,12 @@ _inProgress = true; [[[[OFHTTPClientRequestHandler alloc] initWithClient: self request: request - redirects: redirects] autorelease] start]; + redirects: redirects + context: context] autorelease] start]; objc_autoreleasePoolPop(pool); } - (void)close Index: tests/OFHTTPClientTests.m ================================================================== --- tests/OFHTTPClientTests.m +++ tests/OFHTTPClientTests.m @@ -92,10 +92,11 @@ @implementation TestsAppDelegate (OFHTTPClientTests) - (void)client: (OFHTTPClient *)client didPerformRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response_ + context: (id)context { response = [response_ retain]; [[OFRunLoop mainRunLoop] stop]; } @@ -123,11 +124,12 @@ server->_port]]; TEST(@"-[asyncPerformRequest:]", (client = [OFHTTPClient client]) && R([client setDelegate: self]) && R(request = [OFHTTPRequest requestWithURL: URL]) && - R([client asyncPerformRequest: request])) + R([client asyncPerformRequest: request + context: nil])) [[OFRunLoop mainRunLoop] runUntilDate: [OFDate dateWithTimeIntervalSinceNow: 2]]; [response autorelease]; Index: utils/ofhttp/OFHTTP.m ================================================================== --- utils/ofhttp/OFHTTP.m +++ utils/ofhttp/OFHTTP.m @@ -498,10 +498,11 @@ } - (void)client: (OFHTTPClient *)client didCreateSocket: (OF_KINDOF(OFTCPSocket *))socket request: (OFHTTPRequest *)request + context: (id)context { if (_insecure && [socket respondsToSelector: @selector(setCertificateVerificationEnabled:)]) [socket setCertificateVerificationEnabled: false]; } @@ -509,10 +510,11 @@ - (bool)client: (OFHTTPClient *)client shouldFollowRedirect: (OFURL *)URL statusCode: (int)statusCode request: (OFHTTPRequest *)request response: (OFHTTPResponse *)response + context: (id)context { if (!_quiet) [of_stdout writeFormat: @" ➜ %d\n", statusCode]; if (_verbose) { @@ -539,10 +541,11 @@ } - (void)client: (OFHTTPClient *)client didEncounterException: (id)e forRequest: (OFHTTPRequest *)request + context: (id)context { if ([e isKindOfClass: [OFAddressTranslationFailedException class]]) { if (!_quiet) [of_stdout writeString: @"\n"]; @@ -626,16 +629,16 @@ } - (void)client: (OFHTTPClient *)client didPerformRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response + context: (id)context { OFDictionary OF_GENERIC(OFString *, OFString *) *headers; OFString *lengthString, *type; - /* Was a request to retrieve the file name */ - if (_detectFileName && _currentFileName == nil) { + if ([context isEqual: @"detectFileName"]) { _currentFileName = [fileNameFromContentDisposition( [[response headers] objectForKey: @"Content-Disposition"]) copy]; _detectedFileName = true; @@ -906,11 +909,12 @@ request = [OFHTTPRequest requestWithURL: URL]; [request setHeaders: clientHeaders]; [request setMethod: OF_HTTP_REQUEST_METHOD_HEAD]; - [_HTTPClient asyncPerformRequest: request]; + [_HTTPClient asyncPerformRequest: request + context: @"detectFileName"]; return; } _detectedFileName = false; @@ -947,13 +951,14 @@ request = [OFHTTPRequest requestWithURL: URL]; [request setHeaders: clientHeaders]; [request setMethod: _method]; [request setBody: _body]; - [_HTTPClient asyncPerformRequest: request]; + [_HTTPClient asyncPerformRequest: request + context: nil]; return; next: [self performSelector: @selector(downloadNextURL) afterDelay: 0]; } @end