@@ -49,15 +49,16 @@ #import "OFUnsupportedVersionException.h" #import "OFWriteFailedException.h" #define REDIRECTS_DEFAULT 10 -@interface OFHTTPClientRequestHandler: OFObject +@interface OFHTTPClientRequestHandler: OFObject { @public OFHTTPClient *_client; OFHTTPRequest *_request; + OFString *_requestString; unsigned int _redirects; id _context; bool _firstLine; OFString *_version; int _status; @@ -276,10 +277,11 @@ - (void)dealloc { [_client release]; [_request release]; + [_requestString release]; [_context release]; [_version release]; [_serverHeaders release]; [super dealloc]; @@ -476,10 +478,12 @@ [_client->_delegate client: _client didReceiveHeaders: _serverHeaders statusCode: _status request: _request context: _context]; + + [sock setDelegate: nil]; [self performSelector: @selector(createResponseWithSocket:) withObject: sock afterDelay: 0]; @@ -521,26 +525,15 @@ forKey: key]; return true; } -- (bool)socket: (OFTCPSocket *)sock +- (bool)stream: (OF_KINDOF(OFStream *))sock didReadLine: (OFString *)line - context: (id)context - exception: (id)exception { bool ret; - if (exception != nil) { - if ([exception isKindOfClass: - [OFInvalidEncodingException class]]) - exception = [OFInvalidServerReplyException exception]; - - [self raiseException: exception]; - return false; - } - @try { if (_firstLine) { _firstLine = false; ret = [self handleFirstLine: line]; } else @@ -552,32 +545,38 @@ } return ret; } -- (size_t)socket: (OFTCPSocket *)sock - didWriteRequest: (const void **)request - length: (size_t)length - context: (id)context - exception: (id)exception -{ - if (exception != nil) { - if ([exception isKindOfClass: [OFWriteFailedException class]] && - ([exception errNo] == ECONNRESET || - [exception errNo] == EPIPE)) { - /* In case a keep-alive connection timed out */ - [self closeAndReconnect]; - return 0; - } - - [self raiseException: exception]; - return 0; - } - +- (void)stream: (OF_KINDOF(OFStream *))sock + didFailWithException: (id)exception +{ + if ([exception isKindOfClass: [OFWriteFailedException class]] && + ([exception errNo] == ECONNRESET || [exception errNo] == EPIPE)) { + /* In case a keep-alive connection timed out */ + [self closeAndReconnect]; + return; + } + + if ([exception isKindOfClass: [OFInvalidEncodingException class]]) + exception = [OFInvalidServerReplyException exception]; + + [self raiseException: exception]; +} + +- (size_t)stream: (OF_KINDOF(OFStream *))sock + didWriteBuffer: (const void **)request + length: (size_t)length +{ _firstLine = true; + + [_requestString release]; + _requestString = nil; if ([[_request headers] objectForKey: @"Content-Length"] != nil) { + [sock setDelegate: nil]; + OFStream *requestBody = [[[OFHTTPClientRequestBodyStream alloc] initWithHandler: self socket: sock] autorelease]; if ([_client->_delegate respondsToSelector: @@ -586,14 +585,11 @@ wantsRequestBody: requestBody request: _request context: _context]; } else - [sock asyncReadLineWithTarget: self - selector: @selector(socket:didReadLine: - context:exception:) - context: nil]; + [sock asyncReadLine]; return 0; } - (void)handleSocket: (OFTCPSocket *)sock @@ -606,22 +602,15 @@ * We do not use the socket's write buffer in case we need to resend * the entire request (e.g. in case a keep-alive connection timed out). */ @try { - OFString *requestString = constructRequestString(_request); - - /* - * Pass requestString as context to retain it so that the - * underlying buffer lives long enough. - */ - [sock asyncWriteBuffer: [requestString UTF8String] - length: [requestString UTF8StringLength] - target: self - selector: @selector(socket:didWriteRequest: - length:context:exception:) - context: requestString]; + [_requestString release]; + _requestString = [constructRequestString(_request) retain]; + + [sock asyncWriteBuffer: [_requestString UTF8String] + length: [_requestString UTF8StringLength]]; } @catch (id e) { [self raiseException: e]; return; } } @@ -632,10 +621,12 @@ { if (exception != nil) { [self raiseException: exception]; return; } + + [sock setDelegate: self]; if ([_client->_delegate respondsToSelector: @selector(client:didCreateSocket:request:context:)]) [_client->_delegate client: _client didCreateSocket: sock @@ -645,46 +636,22 @@ [self performSelector: @selector(handleSocket:) withObject: sock afterDelay: 0]; } -- (bool)throwAwayContent: (OFHTTPClientResponse *)response - buffer: (char *)buffer - length: (size_t)length - context: (OFTCPSocket *)sock - exception: (id)exception -{ - if (exception != nil) { - [self raiseException: exception]; - return false; - } - - if ([response isAtEndOfStream]) { - [self freeMemory: buffer]; - - [_client->_lastResponse release]; - _client->_lastResponse = nil; - - [self performSelector: @selector(handleSocket:) - withObject: sock - afterDelay: 0]; - return false; - } - - return true; -} - - (void)start { OFURL *URL = [_request URL]; OFTCPSocket *sock; /* Can we reuse the last socket? */ if (_client->_socket != nil && ![_client->_socket isAtEndOfStream] && [[_client->_lastURL scheme] isEqual: [URL scheme]] && [[_client->_lastURL host] isEqual: [URL host]] && - [_client->_lastURL port] == [URL port]) { + [_client->_lastURL port] == [URL port] && + (_client->_lastWasHEAD || + [_client->_lastResponse isAtEndOfStream])) { /* * Set _socket to nil, so that in case of an error it won't be * reused. If everything is successful, we set _socket again * at the end. */ @@ -692,31 +659,16 @@ _client->_socket = nil; [_client->_lastURL release]; _client->_lastURL = nil; - if (!_client->_lastWasHEAD && - ![_client->_lastResponse isAtEndOfStream]) { - /* Throw away content that has not been read yet */ - char *buffer = [self allocMemoryWithSize: 512]; - - [_client->_lastResponse - asyncReadIntoBuffer: buffer - length: 512 - target: self - selector: @selector(throwAwayContent: - buffer:length:context: - exception:) - context: sock]; - } else { - [_client->_lastResponse release]; - _client->_lastResponse = nil; - - [self performSelector: @selector(handleSocket:) - withObject: sock - afterDelay: 0]; - } + [_client->_lastResponse release]; + _client->_lastResponse = nil; + + [self performSelector: @selector(handleSocket:) + withObject: sock + afterDelay: 0]; } else [self closeAndReconnect]; } - (void)closeAndReconnect @@ -854,14 +806,12 @@ return; if (_toWrite > 0) @throw [OFTruncatedDataException exception]; - [_socket asyncReadLineWithTarget: _handler - selector: @selector(socket:didReadLine:context: - exception:) - context: nil]; + [_socket setDelegate: _handler]; + [_socket asyncReadLine]; [_socket release]; _socket = nil; }