Skip to content

Commit

Permalink
When performRedirect is called we should destroy the old readStream b…
Browse files Browse the repository at this point in the history
…efore rebuilding the request with the new stream in case the existing stream had not finished, which could be the case if the full data for the old stream was found in the cache after its first bits had returned but before it had finished. Here is a detailed example of a way this situation can occur:

* Consider you have two reusable requests R1 and R2 that both request the same URL
* Start these request one right after the other

(in chronological order of how events play out)

R1:
        * Starts with an initial readStream R1S1. The request is not in the download cache so it goes and starts pulling the stream
R2:
        * Starts with an initial readStream R2S1 (same url as R1S1). The request is not in the download cache so it goes and starts pulling the stream
R1:
        * The R1S1 stream finishes downloading its data (so no more data will be coming in on R1S1)
        * It calls handleStreamComplete and the data for the url gets stored in the cache
        * handleStreamComplete sees it is a redirect request
        * [self main] reuses R1 and sets up a new readStream which we'll call R1S2 with the redirected url
        * Redirected url is not in the download cache so it goes and starts pulling the stream
R2:
        * First bits of data return on R2S1 stream
        * handleBytesAvailable calls readResponseHeaders
        * readResponseHeaders check if request was previously cached and it WAS (since R1 cached it after R1S1 finished).
        * readResponseHeaders calls useDataFromCache which calls performRedirect which calls [self main]
        * [self main] reuses R2 and sets up a new readstream R2S2 with the redirected url
        * When the new readStream R2S2 is set it overwrites the old R2S1 stream but R2S1 WAS NOT FINISHED pulling data
        *** This is because so far it has only returned its first bytes of data and when it was found in the cache we moved on
        * The redirected url for R2S2 is not in the download cache so it goes and starts pulling the stream

* R1 and R2 finish their R1S2 and R2S2 streams which each pull the contents of the redirected url and both requests are closed
* The R2S1 stream returns with the rest of the content of its request but R2 has already been finished and dealloced
* Crash occurs in ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventType type, void *clientCallBackInfo) because clientCallBackInfo is deallocated.
  • Loading branch information
Brandon Pung committed Jun 3, 2011
1 parent 404bbfe commit 744a8fe
Showing 1 changed file with 1 addition and 0 deletions.
1 change: 1 addition & 0 deletions Classes/ASIHTTPRequest.m
Expand Up @@ -1436,6 +1436,7 @@ - (void)performRedirect
{
[self setURL:[self redirectURL]];
[self setComplete:YES];
[self destroyReadStream];
[self setNeedsRedirect:NO];
[self setRedirectCount:[self redirectCount]+1];

Expand Down

1 comment on commit 744a8fe

@respectTheCode
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to have fixed a crash that I was having. My app relies on caching and redirects in download queues that can sometimes be created and canceled rapidly.

Please sign in to comment.