Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -47,10 +47,11 @@ */ @interface OFHTTPServer () - (bool)of_socket: (OFTCPSocket *)socket didAcceptSocket: (OFTCPSocket *)clientSocket + context: (id)context exception: (OFException *)exception; @end static const char * statusCodeToString(short code) @@ -340,16 +341,18 @@ - initWithSocket: (OFTCPSocket *)socket server: (OFHTTPServer *)server; - (bool)socket: (OFTCPSocket *)socket didReadLine: (OFString *)line + context: (id)context exception: (OFException *)exception; - (bool)parseProlog: (OFString *)line; - (bool)parseHeaders: (OFString *)line; - (bool)socket: (OFTCPSocket *)socket didReadIntoBuffer: (char *)buffer length: (size_t)length + context: (id)context exception: (OFException *)exception; - (bool)sendErrorAndClose: (short)statusCode; - (void)createResponse; @end @@ -393,10 +396,11 @@ [super dealloc]; } - (bool)socket: (OFTCPSocket *)socket didReadLine: (OFString *)line + context: (id)context exception: (OFException *)exception { if (line == nil || exception != nil) return false; @@ -505,11 +509,13 @@ [_socket asyncReadIntoBuffer: buffer length: BUFFER_SIZE target: self selector: @selector(socket: didReadIntoBuffer: - length:exception:)]; + length:context: + exception:) + context: nil]; [_timer setFireDate: [OFDate dateWithTimeIntervalSinceNow: 5]]; return false; } @@ -570,10 +576,11 @@ } - (bool)socket: (OFTCPSocket *)socket didReadIntoBuffer: (char *)buffer length: (size_t)length + context: (id)context exception: (OFException *)exception { if ([socket isAtEndOfStream] || exception != nil) return false; @@ -720,12 +727,13 @@ port: _port]; [_listeningSocket listen]; [_listeningSocket asyncAcceptWithTarget: self selector: @selector(of_socket: - didAcceptSocket: - exception:)]; + didAcceptSocket:context: + exception:) + context: nil]; } - (void)stop { [_listeningSocket cancelAsyncRequests]; @@ -733,10 +741,11 @@ _listeningSocket = nil; } - (bool)of_socket: (OFTCPSocket *)socket didAcceptSocket: (OFTCPSocket *)clientSocket + context: (id)context exception: (OFException *)exception { OFHTTPServer_Connection *connection; if (exception != nil) { @@ -752,10 +761,11 @@ initWithSocket: clientSocket server: self] autorelease]; [clientSocket asyncReadLineWithTarget: connection selector: @selector(socket:didReadLine: - exception:)]; + context:exception:) + context: nil]; return true; } @end Index: src/OFRunLoop+Private.h ================================================================== --- src/OFRunLoop+Private.h +++ src/OFRunLoop+Private.h @@ -27,28 +27,33 @@ #ifdef OF_HAVE_SOCKETS + (void)of_addAsyncReadForStream: (OFStream *)stream buffer: (void *)buffer length: (size_t)length target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; + (void)of_addAsyncReadForStream: (OFStream *)stream buffer: (void *)buffer exactLength: (size_t)length target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; + (void)of_addAsyncReadLineForStream: (OFStream *)stream encoding: (of_string_encoding_t)encoding target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; + (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)socket target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; + (void)of_addAsyncReceiveForUDPSocket: (OFUDPSocket *)socket buffer: (void *)buffer length: (size_t)length target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; # ifdef OF_HAVE_BLOCKS + (void)of_addAsyncReadForStream: (OFStream *)stream buffer: (void *)buffer length: (size_t)length block: (of_stream_async_read_block_t)block; Index: src/OFRunLoop.m ================================================================== --- src/OFRunLoop.m +++ src/OFRunLoop.m @@ -43,10 +43,11 @@ @interface OFRunLoop_QueueItem: OFObject { @public id _target; SEL _selector; + id _context; } - (bool)handleForObject: (id)object; @end @@ -109,10 +110,11 @@ } - (void)dealloc { [_target release]; + [_context release]; [super dealloc]; } @end @@ -133,17 +135,17 @@ # ifdef OF_HAVE_BLOCKS if (_block != NULL) return _block(object, _buffer, length, exception); else { # endif - bool (*func)(id, SEL, OFStream *, void *, size_t, + bool (*func)(id, SEL, OFStream *, void *, size_t, id, OFException *) = (bool (*)(id, SEL, OFStream *, void *, - size_t, OFException *)) + size_t, id, OFException *)) [_target methodForSelector: _selector]; return func(_target, _selector, object, _buffer, length, - exception); + _context, exception); # ifdef OF_HAVE_BLOCKS } # endif } @@ -184,17 +186,17 @@ _readLength = 0; return true; } else { # endif - bool (*func)(id, SEL, OFStream *, void *, size_t, + bool (*func)(id, SEL, OFStream *, void *, size_t, id, OFException *) = (bool (*)(id, SEL, OFStream *, void *, - size_t, OFException *)) + size_t, id, OFException *)) [_target methodForSelector: _selector]; if (!func(_target, _selector, object, _buffer, _readLength, - exception)) + _context, exception)) return false; _readLength = 0; return true; # ifdef OF_HAVE_BLOCKS @@ -231,15 +233,16 @@ # ifdef OF_HAVE_BLOCKS if (_block != NULL) return _block(object, line, exception); else { # endif - bool (*func)(id, SEL, OFStream *, OFString *, OFException *) = - (bool (*)(id, SEL, OFStream *, OFString *, OFException *)) - [_target methodForSelector: _selector]; + bool (*func)(id, SEL, OFStream *, OFString *, id, + OFException *) = (bool (*)(id, SEL, OFStream *, OFString *, + id, OFException *))[_target methodForSelector: _selector]; - return func(_target, _selector, object, line, exception); + return func(_target, _selector, object, line, _context, + exception); # ifdef OF_HAVE_BLOCKS } # endif } @@ -269,16 +272,17 @@ # ifdef OF_HAVE_BLOCKS if (_block != NULL) return _block(object, newSocket, exception); else { # endif - bool (*func)(id, SEL, OFTCPSocket *, OFTCPSocket *, + bool (*func)(id, SEL, OFTCPSocket *, OFTCPSocket *, id, OFException *) = (bool (*)(id, SEL, OFTCPSocket *, - OFTCPSocket *, OFException *)) + OFTCPSocket *, id, OFException *)) [_target methodForSelector: _selector]; - return func(_target, _selector, object, newSocket, exception); + return func(_target, _selector, object, newSocket, _context, + exception); # ifdef OF_HAVE_BLOCKS } # endif } @@ -312,17 +316,17 @@ if (_block != NULL) return _block(object, _buffer, length, address, exception); else { # endif bool (*func)(id, SEL, OFUDPSocket *, void *, size_t, - of_udp_socket_address_t address, OFException *) = + of_udp_socket_address_t address, id, OFException *) = (bool (*)(id, SEL, OFUDPSocket *, void *, size_t, - of_udp_socket_address_t, OFException *)) + of_udp_socket_address_t, id, OFException *)) [_target methodForSelector: _selector]; return func(_target, _selector, object, _buffer, length, - address, exception); + address, _context, exception); # ifdef OF_HAVE_BLOCKS } # endif } @@ -383,14 +387,16 @@ + (void)of_addAsyncReadForStream: (OFStream *)stream buffer: (void *)buffer length: (size_t)length target: (id)target selector: (SEL)selector + context: (id)context { ADD_READ(OFRunLoop_ReadQueueItem, stream, { queueItem->_target = [target retain]; queueItem->_selector = selector; + queueItem->_context = [context retain]; queueItem->_buffer = buffer; queueItem->_length = length; }) } @@ -397,52 +403,60 @@ + (void)of_addAsyncReadForStream: (OFStream *)stream buffer: (void *)buffer exactLength: (size_t)exactLength target: (id)target selector: (SEL)selector + context: (id)context { ADD_READ(OFRunLoop_ExactReadQueueItem, stream, { queueItem->_target = [target retain]; queueItem->_selector = selector; + queueItem->_context = [context retain]; queueItem->_buffer = buffer; queueItem->_exactLength = exactLength; }) } + (void)of_addAsyncReadLineForStream: (OFStream *)stream encoding: (of_string_encoding_t)encoding target: (id)target selector: (SEL)selector + context: (id)context { ADD_READ(OFRunLoop_ReadLineQueueItem, stream, { queueItem->_target = [target retain]; queueItem->_selector = selector; + queueItem->_context = [context retain]; queueItem->_encoding = encoding; }) } + (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)stream target: (id)target selector: (SEL)selector + context: (id)context { ADD_READ(OFRunLoop_AcceptQueueItem, stream, { queueItem->_target = [target retain]; queueItem->_selector = selector; + queueItem->_context = [context retain]; }) } + (void)of_addAsyncReceiveForUDPSocket: (OFUDPSocket *)socket buffer: (void *)buffer length: (size_t)length target: (id)target selector: (SEL)selector + context: (id)context { ADD_READ(OFRunLoop_UDPReceiveQueueItem, socket, { - queueItem->_buffer = buffer; - queueItem->_length = length; queueItem->_target = [target retain]; queueItem->_selector = selector; + queueItem->_context = [context retain]; + queueItem->_buffer = buffer; + queueItem->_length = length; }) } # ifdef OF_HAVE_BLOCKS + (void)of_addAsyncReadForStream: (OFStream *)stream Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -148,13 +148,13 @@ * @brief Asynchronously reads *at most* size bytes from the stream into a * buffer. * * On network streams, this might read less than the specified number of bytes. * If you want to read exactly the specified number of bytes, use - * @ref asyncReadIntoBuffer:exactLength:block:. Note that a read can even - * return 0 bytes - this does not necessarily mean that the stream ended, so - * you still need to check @ref isAtEndOfStream. + * @ref asyncReadIntoBuffer:exactLength:target:selector:context:. Note that a + * read can even return 0 bytes - this does not necessarily mean that the + * stream ended, so you still need to check @ref isAtEndOfStream. * * @note The stream must implement @ref fileDescriptorForReading and return a * valid file descriptor in order for this to work! * * @param buffer The buffer into which the data is read. @@ -167,23 +167,24 @@ * data has been received. If you want the next method in the * queue to handle the data received next, you need to return * false from the method. * @param selector The selector to call on the target. The signature must be * `bool (OFStream *stream, void *buffer, size_t length, - * OFException *exception)`. + * id context, OFException *exception)`. */ - (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; /*! * @brief Asynchronously reads exactly the specified length bytes from the * stream into a buffer. * - * Unlike @ref asyncReadIntoBuffer:length:target:selector:, this method does - * not call the method when less than the specified length has been read - + * Unlike @ref asyncReadIntoBuffer:length:target:selector:context:, this method + * does not call the method when less than the specified length has been read - * instead, it waits until it got exactly the specified length, the stream has * ended or an exception occurred. * * @note The stream must implement @ref fileDescriptorForReading and return a * valid file descriptor in order for this to work! @@ -197,16 +198,17 @@ * data has been received. If you want the next method in the * queue to handle the data received next, you need to return * false from the method. * @param selector The selector to call on the target. The signature must be * `bool (OFStream *stream, void *buffer, size_t size, - * OFException *exception)`. + * id context, OFException *exception)`. */ - (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; # ifdef OF_HAVE_BLOCKS /*! * @brief Asynchronously reads *at most* ref size bytes from the stream into a * buffer. @@ -619,15 +621,16 @@ * been received. If the method returns true, it will be called * again when the next line has been received. If you want the * next method in the queue to handle the next line, you need to * return false from the method * @param selector The selector to call on the target. The signature must be - * `bool (OFStream *stream, OFString *line, + * `bool (OFStream *stream, OFString *line, id context, * OFException *exception)`. */ - (void)asyncReadLineWithTarget: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; /*! * @brief Asynchronously reads with the specified encoding until a newline, * `\0`, end of stream or an exception occurs. * @@ -640,15 +643,16 @@ * again when the next line has been received. If you want the * next method in the queue to handle the next line, you need to * return false from the method * @param selector The selector to call on the target. The signature must be * `bool (OFStream *stream, OFString *line, - * OFException *exception)`. + * id context, OFException *exception)`. */ - (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; # ifdef OF_HAVE_BLOCKS /*! * @brief Asynchronously reads until a newline, `\0`, end of stream or an * exception occurs. Index: src/OFStream.m ================================================================== --- src/OFStream.m +++ src/OFStream.m @@ -190,28 +190,32 @@ #ifdef OF_HAVE_SOCKETS - (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length target: (id)target selector: (SEL)selector + context: (id)context { [OFRunLoop of_addAsyncReadForStream: self buffer: buffer length: length target: target - selector: selector]; + selector: selector + context: context]; } - (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length target: (id)target selector: (SEL)selector + context: (id)context { [OFRunLoop of_addAsyncReadForStream: self buffer: buffer exactLength: length target: target - selector: selector]; + selector: selector + context: context]; } # ifdef OF_HAVE_BLOCKS - (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length @@ -810,24 +814,28 @@ } #ifdef OF_HAVE_SOCKETS - (void)asyncReadLineWithTarget: (id)target selector: (SEL)selector + context: (id)context { [self asyncReadLineWithEncoding: OF_STRING_ENCODING_UTF_8 target: target - selector: selector]; + selector: selector + context: context]; } - (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding target: (id)target selector: (SEL)selector + context: (id)context { [OFRunLoop of_addAsyncReadLineForStream: self encoding: encoding target: target - selector: selector]; + selector: selector + context: context]; } # ifdef OF_HAVE_BLOCKS - (void)asyncReadLineWithBlock: (of_stream_async_read_line_block_t)block { Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -125,16 +125,18 @@ * @param host The host to connect to * @param port The port on the host to connect to * @param target The target on which to call the selector once the connection * has been established * @param selector The selector to call on the target. The signature must be - * `void (OFTCPSocket *socket, OFException *exception)`. + * `void (OFTCPSocket *socket, id context, + * OFException *exception)`. */ - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; # ifdef OF_HAVE_BLOCKS /*! * @brief Asynchronously connect the OFTCPSocket to the specified destination. * @@ -186,14 +188,15 @@ * connection has been accepted. The method returns whether the * next incoming connection should be accepted by the specified * block as well. * @param selector The selector to call on the target. The signature must be * `bool (OFTCPSocket *socket, OFTCPSocket *acceptedSocket, - * OFException *exception)`. + * id context, OFException *exception)`. */ - (void)asyncAcceptWithTarget: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; #ifdef OF_HAVE_BLOCKS /*! * @brief Asynchronously accept an incoming connection. * Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -72,10 +72,11 @@ OFTCPSocket *_socket; OFString *_host; uint16_t _port; id _target; SEL _selector; + id _context; # ifdef OF_HAVE_BLOCKS of_tcp_socket_async_connect_block_t _block; # endif OFException *_exception; } @@ -83,11 +84,12 @@ - initWithSourceThread: (OFThread *)sourceThread socket: (OFTCPSocket *)socket host: (OFString *)host port: (uint16_t)port target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (id)context; # ifdef OF_HAVE_BLOCKS - initWithSourceThread: (OFThread *)sourceThread socket: (OFTCPSocket *)socket host: (OFString *)host port: (uint16_t)port @@ -100,10 +102,11 @@ socket: (OFTCPSocket *)socket host: (OFString *)host port: (uint16_t)port target: (id)target selector: (SEL)selector + context: (id)context { self = [super init]; @try { _sourceThread = [sourceThread retain]; @@ -110,10 +113,11 @@ _socket = [socket retain]; _host = [host copy]; _port = port; _target = [target retain]; _selector = selector; + _context = [context retain]; } @catch (id e) { [self release]; @throw e; } @@ -148,10 +152,11 @@ { [_sourceThread release]; [_socket release]; [_host release]; [_target release]; + [_context release]; # ifdef OF_HAVE_BLOCKS [_block release]; # endif [_exception release]; @@ -165,15 +170,15 @@ # ifdef OF_HAVE_BLOCKS if (_block != NULL) _block(_socket, _exception); else { # endif - void (*func)(id, SEL, OFTCPSocket *, OFException *) = - (void (*)(id, SEL, OFTCPSocket *, OFException *))[_target - methodForSelector: _selector]; + void (*func)(id, SEL, OFTCPSocket *, id, OFException *) = + (void (*)(id, SEL, OFTCPSocket *, id, OFException *)) + [_target methodForSelector: _selector]; - func(_target, _selector, _socket, _exception); + func(_target, _selector, _socket, _context, _exception); # ifdef OF_HAVE_BLOCKS } # endif } @@ -314,20 +319,22 @@ #ifdef OF_HAVE_THREADS - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port target: (id)target selector: (SEL)selector + context: (id)context { void *pool = objc_autoreleasePoolPush(); [[[[OFTCPSocket_ConnectThread alloc] initWithSourceThread: [OFThread currentThread] socket: self host: host port: port target: target - selector: selector] autorelease] start]; + selector: selector + context: context] autorelease] start]; objc_autoreleasePoolPop(pool); } # ifdef OF_HAVE_BLOCKS @@ -572,14 +579,16 @@ return client; } - (void)asyncAcceptWithTarget: (id)target selector: (SEL)selector + context: (id)context { [OFRunLoop of_addAsyncAcceptForTCPSocket: self target: target - selector: selector]; + selector: selector + context: context]; } #ifdef OF_HAVE_BLOCKS - (void)asyncAcceptWithBlock: (of_tcp_socket_async_accept_block_t)block { Index: src/OFUDPSocket.h ================================================================== --- src/OFUDPSocket.h +++ src/OFUDPSocket.h @@ -125,16 +125,18 @@ * @param port The port for the resulting address * @param target The target on which to call the selector once the host has been * resolved * @param selector The selector to call on the target. The signature must be * `void (OFString *host, uint16_t port, - * of_udp_socket_address_t address, OFException *exception)`. + * of_udp_socket_address_t address, id context, + * OFException *exception)`. */ + (void)asyncResolveAddressForHost: (OFString *)host port: (uint16_t)port target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; # ifdef OF_HAVE_BLOCKS /*! * @brief Asynchronously resolves the specified host and creates an address for * the host / port pair. @@ -203,16 +205,18 @@ * when more datagrams have been received. If you want the next * method in the queue to handle the datagram received next, you * need to return false from the method. * @param selector The selector to call on the target. The signature must be * `bool (OFUDPSocket *socket, void *buffer, size_t length, - * of_udp_socket_address_t, OFException *exception)`. + * of_udp_socket_address_t, id context, + * OFException *exception)`. */ - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (nullable id)context; #ifdef OF_HAVE_BLOCKS /*! * @brief Asynchronously receives a datagram and stores it into the specified * buffer. Index: src/OFUDPSocket.m ================================================================== --- src/OFUDPSocket.m +++ src/OFUDPSocket.m @@ -49,10 +49,11 @@ OFThread *_sourceThread; OFString *_host; uint16_t _port; id _target; SEL _selector; + id _context; # ifdef OF_HAVE_BLOCKS of_udp_socket_async_resolve_block_t _block; # endif of_udp_socket_address_t _address; OFException *_exception; @@ -60,11 +61,12 @@ - initWithSourceThread: (OFThread *)sourceThread host: (OFString *)host port: (uint16_t)port target: (id)target - selector: (SEL)selector; + selector: (SEL)selector + context: (id)context; # ifdef OF_HAVE_BLOCKS - initWithSourceThread: (OFThread *)sourceThread host: (OFString *)host port: (uint16_t)port block: (of_udp_socket_async_resolve_block_t)block; @@ -75,19 +77,21 @@ - initWithSourceThread: (OFThread *)sourceThread host: (OFString *)host port: (uint16_t)port target: (id)target selector: (SEL)selector + context: (id)context { self = [super init]; @try { _sourceThread = [sourceThread retain]; _host = [host retain]; _port = port; _target = [target retain]; _selector = selector; + _context = [context retain]; } @catch (id e) { [self release]; @throw e; } @@ -119,10 +123,11 @@ - (void)dealloc { [_sourceThread release]; [_host release]; [_target release]; + [_context release]; # ifdef OF_HAVE_BLOCKS [_block release]; # endif [_exception release]; @@ -137,16 +142,17 @@ if (_block != NULL) _block(_host, _port, _address, _exception); else { # endif void (*func)(id, SEL, OFString *, uint16_t, - of_udp_socket_address_t, OFException *) = + of_udp_socket_address_t, id, OFException *) = (void (*)(id, SEL, OFString *, uint16_t, - of_udp_socket_address_t, OFException *))[_target - methodForSelector: _selector]; + of_udp_socket_address_t, id, OFException *)) + [_target methodForSelector: _selector]; - func(_target, _selector, _host, _port, _address, _exception); + func(_target, _selector, _host, _port, _address, _context, + _exception); # ifdef OF_HAVE_BLOCKS } # endif } @@ -321,19 +327,21 @@ #ifdef OF_HAVE_THREADS + (void)asyncResolveAddressForHost: (OFString *)host port: (uint16_t)port target: (id)target selector: (SEL)selector + context: (id)context { void *pool = objc_autoreleasePoolPush(); [[[[OFUDPSocket_ResolveThread alloc] initWithSourceThread: [OFThread currentThread] host: host port: port target: target - selector: selector] autorelease] start]; + selector: selector + context: context] autorelease] start]; objc_autoreleasePoolPop(pool); } # ifdef OF_HAVE_BLOCKS @@ -558,16 +566,18 @@ - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length target: (id)target selector: (SEL)selector + context: (id)context { [OFRunLoop of_addAsyncReceiveForUDPSocket: self buffer: buffer length: length target: target - selector: selector]; + selector: selector + context: context]; } #ifdef OF_HAVE_BLOCKS - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length Index: utils/ofhttp/OFHTTP.m ================================================================== --- utils/ofhttp/OFHTTP.m +++ utils/ofhttp/OFHTTP.m @@ -778,11 +778,12 @@ [response asyncReadIntoBuffer: _buffer length: [OFSystemInfo pageSize] target: self selector: @selector(stream:didReadIntoBuffer: - length:exception:)]; + length:context:exception:) + context: nil]; return; next: [_currentFileName release]; @@ -793,10 +794,11 @@ } - (bool)stream: (OFHTTPResponse *)response didReadIntoBuffer: (void *)buffer length: (size_t)length + context: (id)context exception: (OFException *)e { if (e != nil) { OFString *URL;