Tweak persistent connection behaviour again to avoid persistent connections only…
… when they are explicitly turned off, or when we've got http1.0 and no connection:keep-alive header canUsePersistentConnection -> connectionCanBeReused, and add public accessor Add test for connection: close
Showing
4 changed files
with
51 additions
and
35 deletions
@@ -344,7 +344,7 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | @@ -344,7 +344,7 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | ||
344 | BOOL shouldAttemptPersistentConnection; | 344 | BOOL shouldAttemptPersistentConnection; |
345 | 345 | ||
346 | // Set to yes when an appropriate keep-alive header is found | 346 | // Set to yes when an appropriate keep-alive header is found |
347 | - BOOL canUsePersistentConnection; | 347 | + BOOL connectionCanBeReused; |
348 | 348 | ||
349 | // Populated with the number of seconds the server told us we could keep a persistent connection around | 349 | // Populated with the number of seconds the server told us we could keep a persistent connection around |
350 | // A future date is created from this and used for expiring the connection, this is stored in connectionInfo's expires value | 350 | // A future date is created from this and used for expiring the connection, this is stored in connectionInfo's expires value |
@@ -717,4 +717,5 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | @@ -717,4 +717,5 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | ||
717 | @property (assign, readonly) int retryCount; | 717 | @property (assign, readonly) int retryCount; |
718 | @property (assign) BOOL shouldAttemptPersistentConnection; | 718 | @property (assign) BOOL shouldAttemptPersistentConnection; |
719 | @property (assign) BOOL shouldUseRFC2616RedirectBehaviour; | 719 | @property (assign) BOOL shouldUseRFC2616RedirectBehaviour; |
720 | +@property (assign, readonly) BOOL connectionCanBeReused; | ||
720 | @end | 721 | @end |
@@ -21,7 +21,7 @@ | @@ -21,7 +21,7 @@ | ||
21 | #import "ASIInputStream.h" | 21 | #import "ASIInputStream.h" |
22 | 22 | ||
23 | // Automatically set on build | 23 | // Automatically set on build |
24 | -NSString *ASIHTTPRequestVersion = @"v1.5-47 2010-02-24"; | 24 | +NSString *ASIHTTPRequestVersion = @"v1.5-48 2010-02-24"; |
25 | 25 | ||
26 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; | 26 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; |
27 | 27 | ||
@@ -175,7 +175,7 @@ static BOOL isiPhoneOS2; | @@ -175,7 +175,7 @@ static BOOL isiPhoneOS2; | ||
175 | @property (assign) BOOL isSynchronous; | 175 | @property (assign) BOOL isSynchronous; |
176 | @property (assign) BOOL inProgress; | 176 | @property (assign) BOOL inProgress; |
177 | @property (assign) int retryCount; | 177 | @property (assign) int retryCount; |
178 | -@property (assign) BOOL canUsePersistentConnection; | 178 | +@property (assign) BOOL connectionCanBeReused; |
179 | @property (retain, nonatomic) NSMutableDictionary *connectionInfo; | 179 | @property (retain, nonatomic) NSMutableDictionary *connectionInfo; |
180 | @property (retain, nonatomic) NSInputStream *readStream; | 180 | @property (retain, nonatomic) NSInputStream *readStream; |
181 | @property (assign) ASIAuthenticationState authenticationNeeded; | 181 | @property (assign) ASIAuthenticationState authenticationNeeded; |
@@ -1007,7 +1007,7 @@ static BOOL isiPhoneOS2; | @@ -1007,7 +1007,7 @@ static BOOL isiPhoneOS2; | ||
1007 | 1007 | ||
1008 | 1008 | ||
1009 | if (!streamSuccessfullyOpened) { | 1009 | if (!streamSuccessfullyOpened) { |
1010 | - [self setCanUsePersistentConnection:NO]; | 1010 | + [self setConnectionCanBeReused:NO]; |
1011 | [self destroyReadStream]; | 1011 | [self destroyReadStream]; |
1012 | [[self cancelledLock] unlock]; | 1012 | [[self cancelledLock] unlock]; |
1013 | [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to start HTTP connection",NSLocalizedDescriptionKey,nil]]]; | 1013 | [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to start HTTP connection",NSLocalizedDescriptionKey,nil]]]; |
@@ -1579,7 +1579,7 @@ static BOOL isiPhoneOS2; | @@ -1579,7 +1579,7 @@ static BOOL isiPhoneOS2; | ||
1579 | [connectionsLock unlock]; | 1579 | [connectionsLock unlock]; |
1580 | [self destroyReadStream]; | 1580 | [self destroyReadStream]; |
1581 | } | 1581 | } |
1582 | - if ([self canUsePersistentConnection]) { | 1582 | + if ([self connectionCanBeReused]) { |
1583 | [[self connectionInfo] setObject:[NSDate dateWithTimeIntervalSinceNow:closeStreamTime] forKey:@"expires"]; | 1583 | [[self connectionInfo] setObject:[NSDate dateWithTimeIntervalSinceNow:closeStreamTime] forKey:@"expires"]; |
1584 | } | 1584 | } |
1585 | 1585 | ||
@@ -1773,35 +1773,39 @@ static BOOL isiPhoneOS2; | @@ -1773,35 +1773,39 @@ static BOOL isiPhoneOS2; | ||
1773 | } | 1773 | } |
1774 | 1774 | ||
1775 | // Handle connection persistence | 1775 | // Handle connection persistence |
1776 | - NSString *httpVersion = [(NSString *)CFHTTPMessageCopyVersion(message) autorelease]; | 1776 | + if ([self shouldAttemptPersistentConnection]) { |
1777 | - | 1777 | + |
1778 | - // We won't re-use this connection if this request is set to use HTTP 1.0, or the server is talking in HTTP 1.0, or persistent connections are turned off for this request | 1778 | + NSString *connectionHeader = [[[self responseHeaders] objectForKey:@"Connection"] lowercaseString]; |
1779 | - if (![self useHTTPVersionOne] && [self shouldAttemptPersistentConnection] && ![httpVersion isEqualToString:(NSString *)kCFHTTPVersion1_0]) { | 1779 | + NSString *httpVersion = [(NSString *)CFHTTPMessageCopyVersion(message) autorelease]; |
1780 | + | ||
1781 | + // Don't re-use the connection if the server is HTTP 1.0 and didn't send Connection: Keep-Alive | ||
1782 | + if (![httpVersion isEqualToString:(NSString *)kCFHTTPVersion1_0] || [connectionHeader isEqualToString:@"keep-alive"]) { | ||
1780 | 1783 | ||
1781 | - // See if server explicitly told us to close the connection | 1784 | + // See if server explicitly told us to close the connection |
1782 | - if (![[[[self responseHeaders] objectForKey:@"Connection"] lowercaseString] isEqualToString:@"close"]) { | 1785 | + if (![connectionHeader isEqualToString:@"close"]) { |
1783 | - | 1786 | + |
1784 | - NSString *keepAliveHeader = [[self responseHeaders] objectForKey:@"Keep-Alive"]; | 1787 | + NSString *keepAliveHeader = [[self responseHeaders] objectForKey:@"Keep-Alive"]; |
1785 | - | 1788 | + |
1786 | - // If we got a keep alive header, we'll reuse the connection for as long as the server tells us | 1789 | + // If we got a keep alive header, we'll reuse the connection for as long as the server tells us |
1787 | - if (keepAliveHeader) { | 1790 | + if (keepAliveHeader) { |
1788 | - int timeout = 0; | 1791 | + int timeout = 0; |
1789 | - int max = 0; | 1792 | + int max = 0; |
1790 | - NSScanner *scanner = [NSScanner scannerWithString:keepAliveHeader]; | 1793 | + NSScanner *scanner = [NSScanner scannerWithString:keepAliveHeader]; |
1791 | - [scanner scanString:@"timeout=" intoString:NULL]; | 1794 | + [scanner scanString:@"timeout=" intoString:NULL]; |
1792 | - [scanner scanInt:&timeout]; | 1795 | + [scanner scanInt:&timeout]; |
1793 | - [scanner scanUpToString:@"max=" intoString:NULL]; | 1796 | + [scanner scanUpToString:@"max=" intoString:NULL]; |
1794 | - [scanner scanString:@"max=" intoString:NULL]; | 1797 | + [scanner scanString:@"max=" intoString:NULL]; |
1795 | - [scanner scanInt:&max]; | 1798 | + [scanner scanInt:&max]; |
1796 | - if (max > 5) { | 1799 | + if (max > 5) { |
1797 | - [self setCanUsePersistentConnection:YES]; | 1800 | + [self setConnectionCanBeReused:YES]; |
1798 | - closeStreamTime = timeout; | 1801 | + closeStreamTime = timeout; |
1802 | + } | ||
1803 | + | ||
1804 | + // Otherwise, we'll assume we can keep this connection open | ||
1805 | + } else { | ||
1806 | + [self setConnectionCanBeReused:YES]; | ||
1807 | + closeStreamTime = 60; | ||
1799 | } | 1808 | } |
1800 | - | ||
1801 | - // Otherwise, we'll assume we can keep this connection open | ||
1802 | - } else { | ||
1803 | - [self setCanUsePersistentConnection:YES]; | ||
1804 | - closeStreamTime = 60; | ||
1805 | } | 1809 | } |
1806 | } | 1810 | } |
1807 | } | 1811 | } |
@@ -2582,7 +2586,7 @@ static BOOL isiPhoneOS2; | @@ -2582,7 +2586,7 @@ static BOOL isiPhoneOS2; | ||
2582 | 2586 | ||
2583 | 2587 | ||
2584 | [connectionsLock lock]; | 2588 | [connectionsLock lock]; |
2585 | - if (![self canUsePersistentConnection]) { | 2589 | + if (![self connectionCanBeReused]) { |
2586 | [self unscheduleReadStream]; | 2590 | [self unscheduleReadStream]; |
2587 | } | 2591 | } |
2588 | #if DEBUG_PERSISTENT_CONNECTIONS | 2592 | #if DEBUG_PERSISTENT_CONNECTIONS |
@@ -2653,7 +2657,7 @@ static BOOL isiPhoneOS2; | @@ -2653,7 +2657,7 @@ static BOOL isiPhoneOS2; | ||
2653 | CFReadStreamSetClient((CFReadStreamRef)[self readStream], kCFStreamEventNone, NULL, NULL); | 2657 | CFReadStreamSetClient((CFReadStreamRef)[self readStream], kCFStreamEventNone, NULL, NULL); |
2654 | [connectionsLock lock]; | 2658 | [connectionsLock lock]; |
2655 | 2659 | ||
2656 | - if (![self canUsePersistentConnection]) { | 2660 | + if (![self connectionCanBeReused]) { |
2657 | CFReadStreamUnscheduleFromRunLoop((CFReadStreamRef)[self readStream], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); | 2661 | CFReadStreamUnscheduleFromRunLoop((CFReadStreamRef)[self readStream], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); |
2658 | CFReadStreamClose((CFReadStreamRef)[self readStream]); | 2662 | CFReadStreamClose((CFReadStreamRef)[self readStream]); |
2659 | [self setReadStreamIsScheduled:NO]; | 2663 | [self setReadStreamIsScheduled:NO]; |
@@ -3734,7 +3738,7 @@ static BOOL isiPhoneOS2; | @@ -3734,7 +3738,7 @@ static BOOL isiPhoneOS2; | ||
3734 | @synthesize numberOfTimesToRetryOnTimeout; | 3738 | @synthesize numberOfTimesToRetryOnTimeout; |
3735 | @synthesize retryCount; | 3739 | @synthesize retryCount; |
3736 | @synthesize shouldAttemptPersistentConnection; | 3740 | @synthesize shouldAttemptPersistentConnection; |
3737 | -@synthesize canUsePersistentConnection; | 3741 | +@synthesize connectionCanBeReused; |
3738 | @synthesize connectionInfo; | 3742 | @synthesize connectionInfo; |
3739 | @synthesize readStream; | 3743 | @synthesize readStream; |
3740 | @synthesize readStreamIsScheduled; | 3744 | @synthesize readStreamIsScheduled; |
@@ -1345,6 +1345,16 @@ | @@ -1345,6 +1345,16 @@ | ||
1345 | 1345 | ||
1346 | } | 1346 | } |
1347 | 1347 | ||
1348 | +- (void)testCloseConnection | ||
1349 | +{ | ||
1350 | + ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/close-connection"]]; | ||
1351 | + [request startSynchronous]; | ||
1352 | + | ||
1353 | + BOOL success = ![request connectionCanBeReused]; | ||
1354 | + GHAssertTrue(success,@"Should not be able to re-use a request sent with Connection:close"); | ||
1355 | + | ||
1356 | +} | ||
1357 | + | ||
1348 | 1358 | ||
1349 | // Will be called on Mac OS | 1359 | // Will be called on Mac OS |
1350 | - (void)setDoubleValue:(double)newProgress; | 1360 | - (void)setDoubleValue:(double)newProgress; |
-
Please register or login to post a comment