Skip to content
This repository

Patch to fix a problem when using didReceiveData: delegate or dataReceivedBlock callback #319

Open
wants to merge 7 commits into from

3 participants

joewhaley erik chen Jay Graves
joewhaley

There is a problem when processing data using callbacks/delegates whereby the callback receives the body of a 401/407 response, and there is no way to tell from the callback whether the data is from the initial 40x response or from a subsequent response. This means if you are using a streaming parser with ASIHTTPRequest, you will get garbage before the actual data.

You cannot check the response status code, response headers, or any other part of the request inside the block because the values may have changed between the time the data was received and when the callback happens. The passOnReceivedData callback is enqueued on the main thread and execution is not blocked, so the callback can happen much later, after the request has successfully retried and looks like it was successful.

My patch simply disables the data callbacks when authentication is needed, so the 40x response is simply added to the rawResponseData buffer as it would be if there were no callbacks defined. Considering it is not possible with the current interface to figure out which request the data came from, the code as it stands is not useful anyway. With the patch, you can still get the 40x body through the standard interfaces if you need to access it.

I think this approach is better than changing the callback interface to include additional information like response status code, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.

Showing 2 changed files with 15 additions and 3 deletions. Show diff stats Hide diff stats

  1. +4 0 Classes/ASIHTTPRequest.h
  2. +11 3 Classes/ASIHTTPRequest.m
4 Classes/ASIHTTPRequest.h
@@ -264,6 +264,9 @@ typedef void (^ASIDataBlock)(NSData *data);
264 264 // Description of the HTTP status code
265 265 NSString *responseStatusMessage;
266 266
  267 + // HTTP version of the response
  268 + NSString *responseVersion;
  269 +
267 270 // Size of the response
268 271 unsigned long long contentLength;
269 272
@@ -944,6 +947,7 @@ typedef void (^ASIDataBlock)(NSData *data);
944 947 @property (retain) NSDictionary *proxyCredentials;
945 948 @property (assign,readonly) int responseStatusCode;
946 949 @property (retain,readonly) NSString *responseStatusMessage;
  950 +@property (retain,readonly) NSString *responseVersion;
947 951 @property (retain) NSMutableData *rawResponseData;
948 952 @property (assign) NSTimeInterval timeOutSeconds;
949 953 @property (retain, nonatomic) NSString *requestMethod;
14 Classes/ASIHTTPRequest.m
@@ -225,6 +225,7 @@ - (void)callBlock:(ASIBasicBlock)block;
225 225 @property (retain) NSString *authenticationRealm;
226 226 @property (retain) NSString *proxyAuthenticationRealm;
227 227 @property (retain) NSString *responseStatusMessage;
  228 +@property (retain) NSString *responseVersion;
228 229 @property (assign) BOOL inProgress;
229 230 @property (assign) int retryCount;
230 231 @property (assign) BOOL willRetryRequest;
@@ -389,6 +390,7 @@ - (void)dealloc
389 390 [PACurl release];
390 391 [clientCertificates release];
391 392 [responseStatusMessage release];
  393 + [responseVersion release];
392 394 [connectionInfo release];
393 395 [requestID release];
394 396 [dataDecompressor release];
@@ -2155,6 +2157,7 @@ - (void)readResponseHeaders
2155 2157 [self setResponseHeaders:[NSMakeCollectable(CFHTTPMessageCopyAllHeaderFields(message)) autorelease]];
2156 2158 [self setResponseStatusCode:(int)CFHTTPMessageGetResponseStatusCode(message)];
2157 2159 [self setResponseStatusMessage:[NSMakeCollectable(CFHTTPMessageCopyResponseStatusLine(message)) autorelease]];
  2160 + [self setResponseVersion:[NSMakeCollectable(CFHTTPMessageCopyVersion(message)) autorelease]];
2158 2161
2159 2162 if ([self downloadCache] && ([[self downloadCache] canUseCachedDataForRequest:self])) {
2160 2163
@@ -2258,10 +2261,8 @@ - (void)readResponseHeaders
2258 2261
2259 2262 NSString *connectionHeader = [[[self responseHeaders] objectForKey:@"Connection"] lowercaseString];
2260 2263
2261   - NSString *httpVersion = [NSMakeCollectable(CFHTTPMessageCopyVersion(message)) autorelease];
2262   -
2263 2264 // Don't re-use the connection if the server is HTTP 1.0 and didn't send Connection: Keep-Alive
2264   - if (![httpVersion isEqualToString:(NSString *)kCFHTTPVersion1_0] || [connectionHeader isEqualToString:@"keep-alive"]) {
  2265 + if (![self.responseVersion isEqualToString:(NSString *)kCFHTTPVersion1_0] || [connectionHeader isEqualToString:@"keep-alive"]) {
2265 2266
2266 2267 // See if server explicitly told us to close the connection
2267 2268 if (![connectionHeader isEqualToString:@"close"]) {
@@ -3331,6 +3332,12 @@ - (void)handleBytesAvailable
3331 3332 dataWillBeHandledExternally = YES;
3332 3333 }
3333 3334 #endif
  3335 +
  3336 + if ([self authenticationNeeded]) {
  3337 + // Don't pass the body of a 401/407 response to the callback.
  3338 + dataWillBeHandledExternally = NO;
  3339 + }
  3340 +
3334 3341 // Does the delegate want to handle the data manually?
3335 3342 if (dataWillBeHandledExternally) {
3336 3343
@@ -5086,6 +5093,7 @@ - (void)setRequestRedirectedBlock:(ASIBasicBlock)aRedirectBlock
5086 5093 @synthesize shouldPresentProxyAuthenticationDialog;
5087 5094 @synthesize authenticationNeeded;
5088 5095 @synthesize responseStatusMessage;
  5096 +@synthesize responseVersion;
5089 5097 @synthesize shouldPresentCredentialsBeforeChallenge;
5090 5098 @synthesize haveBuiltRequestHeaders;
5091 5099 @synthesize inProgress;

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.