Showing
2 changed files
with
180 additions
and
173 deletions
| @@ -23,7 +23,7 @@ | @@ -23,7 +23,7 @@ | ||
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | // Automatically set on build | 25 | // Automatically set on build |
| 26 | -NSString *ASIHTTPRequestVersion = @"v1.6-15 2010-03-18"; | 26 | +NSString *ASIHTTPRequestVersion = @"v1.6-16 2010-03-19"; |
| 27 | 27 | ||
| 28 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; | 28 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; |
| 29 | 29 | ||
| @@ -1647,194 +1647,196 @@ static BOOL isiPhoneOS2; | @@ -1647,194 +1647,196 @@ static BOOL isiPhoneOS2; | ||
| 1647 | if (!message) { | 1647 | if (!message) { |
| 1648 | return; | 1648 | return; |
| 1649 | } | 1649 | } |
| 1650 | - if (CFHTTPMessageIsHeaderComplete(message)) { | 1650 | + |
| 1651 | + // Make sure we've received all the headers | ||
| 1652 | + if (!CFHTTPMessageIsHeaderComplete(message)) { | ||
| 1653 | + CFRelease(message); | ||
| 1654 | + return; | ||
| 1655 | + } | ||
| 1651 | 1656 | ||
| 1652 | -#if DEBUG_REQUEST_STATUS | 1657 | + #if DEBUG_REQUEST_STATUS |
| 1653 | - if ([self totalBytesSent] == [self postLength]) { | 1658 | + if ([self totalBytesSent] == [self postLength]) { |
| 1654 | - NSLog(@"Request %@ received response headers",self); | 1659 | + NSLog(@"Request %@ received response headers",self); |
| 1655 | - } | 1660 | + } |
| 1656 | -#endif | 1661 | + #endif |
| 1657 | 1662 | ||
| 1658 | - CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(message); | 1663 | + CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(message); |
| 1659 | - [self setResponseHeaders:(NSDictionary *)headerFields]; | 1664 | + [self setResponseHeaders:(NSDictionary *)headerFields]; |
| 1660 | 1665 | ||
| 1661 | - CFRelease(headerFields); | 1666 | + CFRelease(headerFields); |
| 1662 | - [self setResponseStatusCode:CFHTTPMessageGetResponseStatusCode(message)]; | 1667 | + [self setResponseStatusCode:CFHTTPMessageGetResponseStatusCode(message)]; |
| 1663 | - [self setResponseStatusMessage:[(NSString *)CFHTTPMessageCopyResponseStatusLine(message) autorelease]]; | 1668 | + [self setResponseStatusMessage:[(NSString *)CFHTTPMessageCopyResponseStatusLine(message) autorelease]]; |
| 1664 | 1669 | ||
| 1665 | - // Is the server response a challenge for credentials? | 1670 | + // Is the server response a challenge for credentials? |
| 1666 | - if ([self responseStatusCode] == 401) { | 1671 | + if ([self responseStatusCode] == 401) { |
| 1667 | - [self setAuthenticationNeeded:ASIHTTPAuthenticationNeeded]; | 1672 | + [self setAuthenticationNeeded:ASIHTTPAuthenticationNeeded]; |
| 1668 | - } else if ([self responseStatusCode] == 407) { | 1673 | + } else if ([self responseStatusCode] == 407) { |
| 1669 | - [self setAuthenticationNeeded:ASIProxyAuthenticationNeeded]; | 1674 | + [self setAuthenticationNeeded:ASIProxyAuthenticationNeeded]; |
| 1670 | - } | 1675 | + } |
| 1671 | 1676 | ||
| 1672 | - // Authentication succeeded, or no authentication was required | 1677 | + // Authentication succeeded, or no authentication was required |
| 1673 | - if (![self authenticationNeeded]) { | 1678 | + if (![self authenticationNeeded]) { |
| 1674 | 1679 | ||
| 1675 | - // Did we get here without an authentication challenge? (which can happen when shouldPresentCredentialsBeforeChallenge is YES and basic auth was successful) | 1680 | + // Did we get here without an authentication challenge? (which can happen when shouldPresentCredentialsBeforeChallenge is YES and basic auth was successful) |
| 1676 | - if (!requestAuthentication && [self username] && [self password] && [self useSessionPersistence]) { | 1681 | + if (!requestAuthentication && [self username] && [self password] && [self useSessionPersistence]) { |
| 1677 | - | ||
| 1678 | - NSMutableDictionary *newCredentials = [NSMutableDictionary dictionaryWithCapacity:2]; | ||
| 1679 | - [newCredentials setObject:[self username] forKey:(NSString *)kCFHTTPAuthenticationUsername]; | ||
| 1680 | - [newCredentials setObject:[self password] forKey:(NSString *)kCFHTTPAuthenticationPassword]; | ||
| 1681 | - | ||
| 1682 | - // Store the credentials in the session | ||
| 1683 | - NSMutableDictionary *sessionCredentials = [NSMutableDictionary dictionary]; | ||
| 1684 | - [sessionCredentials setObject:newCredentials forKey:@"Credentials"]; | ||
| 1685 | - [sessionCredentials setObject:[self url] forKey:@"URL"]; | ||
| 1686 | - [sessionCredentials setObject:(NSString *)kCFHTTPAuthenticationSchemeBasic forKey:@"AuthenticationScheme"]; | ||
| 1687 | - [[self class] storeAuthenticationCredentialsInSessionStore:sessionCredentials]; | ||
| 1688 | - } | ||
| 1689 | 1682 | ||
| 1683 | + NSMutableDictionary *newCredentials = [NSMutableDictionary dictionaryWithCapacity:2]; | ||
| 1684 | + [newCredentials setObject:[self username] forKey:(NSString *)kCFHTTPAuthenticationUsername]; | ||
| 1685 | + [newCredentials setObject:[self password] forKey:(NSString *)kCFHTTPAuthenticationPassword]; | ||
| 1690 | 1686 | ||
| 1691 | - // See if we got a Content-length header | 1687 | + // Store the credentials in the session |
| 1692 | - NSString *cLength = [responseHeaders valueForKey:@"Content-Length"]; | 1688 | + NSMutableDictionary *sessionCredentials = [NSMutableDictionary dictionary]; |
| 1693 | - if (cLength) { | 1689 | + [sessionCredentials setObject:newCredentials forKey:@"Credentials"]; |
| 1694 | - SInt32 length = CFStringGetIntValue((CFStringRef)cLength); | 1690 | + [sessionCredentials setObject:[self url] forKey:@"URL"]; |
| 1695 | - | 1691 | + [sessionCredentials setObject:(NSString *)kCFHTTPAuthenticationSchemeBasic forKey:@"AuthenticationScheme"]; |
| 1696 | - // Workaround for Apache HEAD requests for dynamically generated content returning the wrong Content-Length when using gzip | 1692 | + [[self class] storeAuthenticationCredentialsInSessionStore:sessionCredentials]; |
| 1697 | - if ([self mainRequest] && [self allowCompressedResponse] && length == 20 && [self showAccurateProgress] && [self shouldResetProgressIndicators]) { | 1693 | + } |
| 1698 | - [[self mainRequest] setShowAccurateProgress:NO]; | 1694 | + } |
| 1699 | - [self resetDownloadProgress:1]; | 1695 | + |
| 1700 | - | 1696 | + // See if we got a Content-length header |
| 1701 | - } else { | 1697 | + NSString *cLength = [responseHeaders valueForKey:@"Content-Length"]; |
| 1702 | - [self setContentLength:length]; | 1698 | + if (cLength) { |
| 1703 | - if ([self mainRequest]) { | 1699 | + SInt32 length = CFStringGetIntValue((CFStringRef)cLength); |
| 1704 | - [[self mainRequest] setContentLength:length]; | 1700 | + |
| 1705 | - } | 1701 | + // Workaround for Apache HEAD requests for dynamically generated content returning the wrong Content-Length when using gzip |
| 1702 | + if ([self mainRequest] && [self allowCompressedResponse] && length == 20 && [self showAccurateProgress] && [self shouldResetProgressIndicators]) { | ||
| 1703 | + [[self mainRequest] setShowAccurateProgress:NO]; | ||
| 1704 | + [self resetDownloadProgress:1]; | ||
| 1705 | + | ||
| 1706 | + } else { | ||
| 1707 | + [self setContentLength:length]; | ||
| 1708 | + if ([self mainRequest]) { | ||
| 1709 | + [[self mainRequest] setContentLength:length]; | ||
| 1710 | + } | ||
| 1706 | 1711 | ||
| 1707 | - if ([self showAccurateProgress] && [self shouldResetProgressIndicators]) { | 1712 | + if ([self showAccurateProgress] && [self shouldResetProgressIndicators]) { |
| 1708 | - [self resetDownloadProgress:[self contentLength]+[self partialDownloadSize]]; | 1713 | + [self resetDownloadProgress:[self contentLength]+[self partialDownloadSize]]; |
| 1709 | - } | ||
| 1710 | - } | ||
| 1711 | - | ||
| 1712 | - } else if ([self showAccurateProgress] && [self shouldResetProgressIndicators]) { | ||
| 1713 | - [[self mainRequest] setShowAccurateProgress:NO]; | ||
| 1714 | - [self resetDownloadProgress:1]; | ||
| 1715 | } | 1714 | } |
| 1716 | - | 1715 | + } |
| 1717 | - // Handle response text encoding | 1716 | + |
| 1718 | - // If the Content-Type header specified an encoding, we'll use that, otherwise we use defaultStringEncoding (which defaults to NSISOLatin1StringEncoding) | 1717 | + } else if ([self showAccurateProgress] && [self shouldResetProgressIndicators]) { |
| 1719 | - NSString *contentType = [[self responseHeaders] objectForKey:@"Content-Type"]; | 1718 | + [[self mainRequest] setShowAccurateProgress:NO]; |
| 1720 | - NSStringEncoding encoding = [self defaultResponseEncoding]; | 1719 | + [self resetDownloadProgress:1]; |
| 1721 | - if (contentType) { | 1720 | + } |
| 1722 | - | ||
| 1723 | - NSString *charsetSeparator = @"charset="; | ||
| 1724 | - NSScanner *charsetScanner = [NSScanner scannerWithString: contentType]; | ||
| 1725 | - NSString *IANAEncoding = nil; | ||
| 1726 | - | ||
| 1727 | - if ([charsetScanner scanUpToString: charsetSeparator intoString: NULL] && [charsetScanner scanLocation] < [contentType length]) | ||
| 1728 | - { | ||
| 1729 | - [charsetScanner setScanLocation: [charsetScanner scanLocation] + [charsetSeparator length]]; | ||
| 1730 | - [charsetScanner scanUpToString: @";" intoString: &IANAEncoding]; | ||
| 1731 | - } | ||
| 1732 | 1721 | ||
| 1733 | - if (IANAEncoding) { | 1722 | + // Handle response text encoding |
| 1734 | - CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)IANAEncoding); | 1723 | + // If the Content-Type header specified an encoding, we'll use that, otherwise we use defaultStringEncoding (which defaults to NSISOLatin1StringEncoding) |
| 1735 | - if (cfEncoding != kCFStringEncodingInvalidId) { | 1724 | + NSString *contentType = [[self responseHeaders] objectForKey:@"Content-Type"]; |
| 1736 | - encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding); | 1725 | + NSStringEncoding encoding = [self defaultResponseEncoding]; |
| 1737 | - } | 1726 | + if (contentType) { |
| 1738 | - } | 1727 | + |
| 1728 | + NSString *charsetSeparator = @"charset="; | ||
| 1729 | + NSScanner *charsetScanner = [NSScanner scannerWithString: contentType]; | ||
| 1730 | + NSString *IANAEncoding = nil; | ||
| 1731 | + | ||
| 1732 | + if ([charsetScanner scanUpToString: charsetSeparator intoString: NULL] && [charsetScanner scanLocation] < [contentType length]) | ||
| 1733 | + { | ||
| 1734 | + [charsetScanner setScanLocation: [charsetScanner scanLocation] + [charsetSeparator length]]; | ||
| 1735 | + [charsetScanner scanUpToString: @";" intoString: &IANAEncoding]; | ||
| 1736 | + } | ||
| 1737 | + | ||
| 1738 | + if (IANAEncoding) { | ||
| 1739 | + CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)IANAEncoding); | ||
| 1740 | + if (cfEncoding != kCFStringEncodingInvalidId) { | ||
| 1741 | + encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding); | ||
| 1739 | } | 1742 | } |
| 1740 | - [self setResponseEncoding:encoding]; | 1743 | + } |
| 1744 | + } | ||
| 1745 | + [self setResponseEncoding:encoding]; | ||
| 1746 | + | ||
| 1747 | + // Handle cookies | ||
| 1748 | + NSArray *newCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:responseHeaders forURL:url]; | ||
| 1749 | + [self setResponseCookies:newCookies]; | ||
| 1750 | + | ||
| 1751 | + if ([self useCookiePersistence]) { | ||
| 1752 | + | ||
| 1753 | + // Store cookies in global persistent store | ||
| 1754 | + [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:newCookies forURL:url mainDocumentURL:nil]; | ||
| 1755 | + | ||
| 1756 | + // We also keep any cookies in the sessionCookies array, so that we have a reference to them if we need to remove them later | ||
| 1757 | + NSHTTPCookie *cookie; | ||
| 1758 | + for (cookie in newCookies) { | ||
| 1759 | + [ASIHTTPRequest addSessionCookie:cookie]; | ||
| 1760 | + } | ||
| 1761 | + } | ||
| 1762 | + | ||
| 1763 | + // Do we need to redirect? | ||
| 1764 | + // Note that ASIHTTPRequest does not currently support 305 Use Proxy | ||
| 1765 | + if ([self shouldRedirect] && [responseHeaders valueForKey:@"Location"]) { | ||
| 1766 | + if (([self responseStatusCode] > 300 && [self responseStatusCode] < 304) || [self responseStatusCode] == 307) { | ||
| 1741 | 1767 | ||
| 1742 | - // Handle cookies | 1768 | + // By default, we redirect 301 and 302 response codes as GET requests |
| 1743 | - NSArray *newCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:responseHeaders forURL:url]; | 1769 | + // According to RFC 2616 this is wrong, but this is what most browsers do, so it's probably what you're expecting to happen |
| 1744 | - [self setResponseCookies:newCookies]; | 1770 | + // See also: |
| 1771 | + // http://allseeing-i.lighthouseapp.com/projects/27881/tickets/27-302-redirection-issue | ||
| 1772 | + | ||
| 1773 | + if ([self responseStatusCode] != 307 && (![self shouldUseRFC2616RedirectBehaviour] || [self responseStatusCode] == 303)) { | ||
| 1774 | + [self setRequestMethod:@"GET"]; | ||
| 1775 | + [self setPostBody:nil]; | ||
| 1776 | + [self setPostLength:0]; | ||
| 1777 | + [self setRequestHeaders:nil]; | ||
| 1778 | + [self setHaveBuiltRequestHeaders:NO]; | ||
| 1779 | + } else { | ||
| 1745 | 1780 | ||
| 1746 | - if ([self useCookiePersistence]) { | 1781 | + // Force rebuild the cookie header incase we got some new cookies from this request |
| 1747 | - | 1782 | + // All other request headers will remain as they are for 301 / 302 redirects |
| 1748 | - // Store cookies in global persistent store | 1783 | + [self applyCookieHeader]; |
| 1749 | - [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:newCookies forURL:url mainDocumentURL:nil]; | ||
| 1750 | - | ||
| 1751 | - // We also keep any cookies in the sessionCookies array, so that we have a reference to them if we need to remove them later | ||
| 1752 | - NSHTTPCookie *cookie; | ||
| 1753 | - for (cookie in newCookies) { | ||
| 1754 | - [ASIHTTPRequest addSessionCookie:cookie]; | ||
| 1755 | - } | ||
| 1756 | } | 1784 | } |
| 1757 | - // Do we need to redirect? | ||
| 1758 | - // Note that ASIHTTPRequest does not currently support 305 Use Proxy | ||
| 1759 | - if ([self shouldRedirect] && [responseHeaders valueForKey:@"Location"]) { | ||
| 1760 | - if (([self responseStatusCode] > 300 && [self responseStatusCode] < 304) || [self responseStatusCode] == 307) { | ||
| 1761 | - | ||
| 1762 | - // By default, we redirect 301 and 302 response codes as GET requests | ||
| 1763 | - // According to RFC 2616 this is wrong, but this is what most browsers do, so it's probably what you're expecting to happen | ||
| 1764 | - // See also: | ||
| 1765 | - // http://allseeing-i.lighthouseapp.com/projects/27881/tickets/27-302-redirection-issue | ||
| 1766 | - | ||
| 1767 | - if ([self responseStatusCode] != 307 && (![self shouldUseRFC2616RedirectBehaviour] || [self responseStatusCode] == 303)) { | ||
| 1768 | - [self setRequestMethod:@"GET"]; | ||
| 1769 | - [self setPostBody:nil]; | ||
| 1770 | - [self setPostLength:0]; | ||
| 1771 | - [self setRequestHeaders:nil]; | ||
| 1772 | - [self setHaveBuiltRequestHeaders:NO]; | ||
| 1773 | - } else { | ||
| 1774 | - | ||
| 1775 | - // Force rebuild the cookie header incase we got some new cookies from this request | ||
| 1776 | - // All other request headers will remain as they are for 301 / 302 redirects | ||
| 1777 | - [self applyCookieHeader]; | ||
| 1778 | - } | ||
| 1779 | 1785 | ||
| 1780 | - // Force the redirected request to rebuild the request headers (if not a 303, it will re-use old ones, and add any new ones) | 1786 | + // Force the redirected request to rebuild the request headers (if not a 303, it will re-use old ones, and add any new ones) |
| 1781 | - | ||
| 1782 | - [self setURL:[[NSURL URLWithString:[responseHeaders valueForKey:@"Location"] relativeToURL:[self url]] absoluteURL]]; | ||
| 1783 | - [self setNeedsRedirect:YES]; | ||
| 1784 | - | ||
| 1785 | - // Clear the request cookies | ||
| 1786 | - // This means manually added cookies will not be added to the redirect request - only those stored in the global persistent store | ||
| 1787 | - // But, this is probably the safest option - we might be redirecting to a different domain | ||
| 1788 | - [self setRequestCookies:[NSMutableArray array]]; | ||
| 1789 | - | ||
| 1790 | - #if DEBUG_REQUEST_STATUS | ||
| 1791 | - NSLog(@"Request will redirect (code: %hi): %@",[self responseStatusCode],self); | ||
| 1792 | - #endif | ||
| 1793 | - | ||
| 1794 | - } | ||
| 1795 | - } | ||
| 1796 | 1787 | ||
| 1797 | - } | 1788 | + [self setURL:[[NSURL URLWithString:[responseHeaders valueForKey:@"Location"] relativeToURL:[self url]] absoluteURL]]; |
| 1798 | - | 1789 | + [self setNeedsRedirect:YES]; |
| 1799 | - // Handle connection persistence | 1790 | + |
| 1800 | - if ([self shouldAttemptPersistentConnection]) { | 1791 | + // Clear the request cookies |
| 1792 | + // This means manually added cookies will not be added to the redirect request - only those stored in the global persistent store | ||
| 1793 | + // But, this is probably the safest option - we might be redirecting to a different domain | ||
| 1794 | + [self setRequestCookies:[NSMutableArray array]]; | ||
| 1801 | 1795 | ||
| 1802 | - NSString *connectionHeader = [[[self responseHeaders] objectForKey:@"Connection"] lowercaseString]; | 1796 | + #if DEBUG_REQUEST_STATUS |
| 1803 | - NSString *httpVersion = [(NSString *)CFHTTPMessageCopyVersion(message) autorelease]; | 1797 | + NSLog(@"Request will redirect (code: %hi): %@",[self responseStatusCode],self); |
| 1798 | + #endif | ||
| 1804 | 1799 | ||
| 1805 | - // Don't re-use the connection if the server is HTTP 1.0 and didn't send Connection: Keep-Alive | 1800 | + } |
| 1806 | - if (![httpVersion isEqualToString:(NSString *)kCFHTTPVersion1_0] || [connectionHeader isEqualToString:@"keep-alive"]) { | 1801 | + } |
| 1802 | + // Handle connection persistence | ||
| 1803 | + if ([self shouldAttemptPersistentConnection]) { | ||
| 1804 | + | ||
| 1805 | + NSString *connectionHeader = [[[self responseHeaders] objectForKey:@"Connection"] lowercaseString]; | ||
| 1806 | + NSString *httpVersion = [(NSString *)CFHTTPMessageCopyVersion(message) autorelease]; | ||
| 1807 | + | ||
| 1808 | + // Don't re-use the connection if the server is HTTP 1.0 and didn't send Connection: Keep-Alive | ||
| 1809 | + if (![httpVersion isEqualToString:(NSString *)kCFHTTPVersion1_0] || [connectionHeader isEqualToString:@"keep-alive"]) { | ||
| 1807 | 1810 | ||
| 1808 | - // See if server explicitly told us to close the connection | 1811 | + // See if server explicitly told us to close the connection |
| 1809 | - if (![connectionHeader isEqualToString:@"close"]) { | 1812 | + if (![connectionHeader isEqualToString:@"close"]) { |
| 1810 | - | 1813 | + |
| 1811 | - NSString *keepAliveHeader = [[self responseHeaders] objectForKey:@"Keep-Alive"]; | 1814 | + NSString *keepAliveHeader = [[self responseHeaders] objectForKey:@"Keep-Alive"]; |
| 1812 | - | 1815 | + |
| 1813 | - // If we got a keep alive header, we'll reuse the connection for as long as the server tells us | 1816 | + // If we got a keep alive header, we'll reuse the connection for as long as the server tells us |
| 1814 | - if (keepAliveHeader) { | 1817 | + if (keepAliveHeader) { |
| 1815 | - int timeout = 0; | 1818 | + int timeout = 0; |
| 1816 | - int max = 0; | 1819 | + int max = 0; |
| 1817 | - NSScanner *scanner = [NSScanner scannerWithString:keepAliveHeader]; | 1820 | + NSScanner *scanner = [NSScanner scannerWithString:keepAliveHeader]; |
| 1818 | - [scanner scanString:@"timeout=" intoString:NULL]; | 1821 | + [scanner scanString:@"timeout=" intoString:NULL]; |
| 1819 | - [scanner scanInt:&timeout]; | 1822 | + [scanner scanInt:&timeout]; |
| 1820 | - [scanner scanUpToString:@"max=" intoString:NULL]; | 1823 | + [scanner scanUpToString:@"max=" intoString:NULL]; |
| 1821 | - [scanner scanString:@"max=" intoString:NULL]; | 1824 | + [scanner scanString:@"max=" intoString:NULL]; |
| 1822 | - [scanner scanInt:&max]; | 1825 | + [scanner scanInt:&max]; |
| 1823 | - if (max > 5) { | 1826 | + if (max > 5) { |
| 1824 | - [self setConnectionCanBeReused:YES]; | ||
| 1825 | - [self setPersistentConnectionTimeoutSeconds:timeout]; | ||
| 1826 | - #if DEBUG_PERSISTENT_CONNECTIONS | ||
| 1827 | - NSLog(@"Got a keep-alive header, will keep this connection open for %f seconds", [self persistentConnectionTimeoutSeconds]); | ||
| 1828 | - #endif | ||
| 1829 | - } | ||
| 1830 | - | ||
| 1831 | - // Otherwise, we'll assume we can keep this connection open | ||
| 1832 | - } else { | ||
| 1833 | [self setConnectionCanBeReused:YES]; | 1827 | [self setConnectionCanBeReused:YES]; |
| 1828 | + [self setPersistentConnectionTimeoutSeconds:timeout]; | ||
| 1834 | #if DEBUG_PERSISTENT_CONNECTIONS | 1829 | #if DEBUG_PERSISTENT_CONNECTIONS |
| 1835 | - NSLog(@"Got no keep-alive header, will keep this connection open for %f seconds", [self persistentConnectionTimeoutSeconds]); | 1830 | + NSLog(@"Got a keep-alive header, will keep this connection open for %f seconds", [self persistentConnectionTimeoutSeconds]); |
| 1836 | - #endif | 1831 | + #endif |
| 1837 | } | 1832 | } |
| 1833 | + | ||
| 1834 | + // Otherwise, we'll assume we can keep this connection open | ||
| 1835 | + } else { | ||
| 1836 | + [self setConnectionCanBeReused:YES]; | ||
| 1837 | + #if DEBUG_PERSISTENT_CONNECTIONS | ||
| 1838 | + NSLog(@"Got no keep-alive header, will keep this connection open for %f seconds", [self persistentConnectionTimeoutSeconds]); | ||
| 1839 | + #endif | ||
| 1838 | } | 1840 | } |
| 1839 | } | 1841 | } |
| 1840 | } | 1842 | } |
| @@ -2687,15 +2689,13 @@ static BOOL isiPhoneOS2; | @@ -2687,15 +2689,13 @@ static BOOL isiPhoneOS2; | ||
| 2687 | 2689 | ||
| 2688 | if (![self error]) { // We may already have handled this error | 2690 | if (![self error]) { // We may already have handled this error |
| 2689 | 2691 | ||
| 2690 | - // First, check for a socket not connected error | 2692 | + // First, check for a 'socket not connected' or 'connection lost' error |
| 2691 | // This may occur when we've attempted to reuse a connection that should have been closed | 2693 | // This may occur when we've attempted to reuse a connection that should have been closed |
| 2692 | // If we get this, we need to retry the request | 2694 | // If we get this, we need to retry the request |
| 2693 | // We'll only do this once - if it happens again on retry, we'll give up | 2695 | // We'll only do this once - if it happens again on retry, we'll give up |
| 2694 | - if ([[underlyingError domain] isEqualToString:NSPOSIXErrorDomain]) { | 2696 | + if (([[underlyingError domain] isEqualToString:NSPOSIXErrorDomain] && [underlyingError code] == ENOTCONN) || ([[underlyingError domain] isEqualToString:(NSString *)kCFErrorDomainCFNetwork] && [underlyingError code] == kCFURLErrorNetworkConnectionLost)) { |
| 2695 | - if ([underlyingError code] == ENOTCONN) { | 2697 | + if ([self retryUsingNewConnection]) { |
| 2696 | - if ([self retryUsingNewConnection]) { | 2698 | + return; |
| 2697 | - return; | ||
| 2698 | - } | ||
| 2699 | } | 2699 | } |
| 2700 | } | 2700 | } |
| 2701 | 2701 | ||
| @@ -2706,7 +2706,7 @@ static BOOL isiPhoneOS2; | @@ -2706,7 +2706,7 @@ static BOOL isiPhoneOS2; | ||
| 2706 | // Also, iPhone seems to handle errors differently from Mac OS X - a self-signed certificate returns a different error code on each platform, so we'll just provide a general error | 2706 | // Also, iPhone seems to handle errors differently from Mac OS X - a self-signed certificate returns a different error code on each platform, so we'll just provide a general error |
| 2707 | if ([[underlyingError domain] isEqualToString:NSOSStatusErrorDomain]) { | 2707 | if ([[underlyingError domain] isEqualToString:NSOSStatusErrorDomain]) { |
| 2708 | if ([underlyingError code] <= -9800 && [underlyingError code] >= -9818) { | 2708 | if ([underlyingError code] <= -9800 && [underlyingError code] >= -9818) { |
| 2709 | - reason = [NSString stringWithFormat:@"%@: SSL problem (possibily a bad/expired/self-signed certificate)",reason]; | 2709 | + reason = [NSString stringWithFormat:@"%@: SSL problem (possibly a bad/expired/self-signed certificate)",reason]; |
| 2710 | } | 2710 | } |
| 2711 | } | 2711 | } |
| 2712 | 2712 |
| @@ -1464,6 +1464,13 @@ | @@ -1464,6 +1464,13 @@ | ||
| 1464 | BOOL success = ![request connectionCanBeReused]; | 1464 | BOOL success = ![request connectionCanBeReused]; |
| 1465 | GHAssertTrue(success,@"Should not be able to re-use a request sent with Connection:close"); | 1465 | GHAssertTrue(success,@"Should not be able to re-use a request sent with Connection:close"); |
| 1466 | 1466 | ||
| 1467 | + // Ensure we close the connection when authentication is needed | ||
| 1468 | + request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/close-connection-auth-needed"]]; | ||
| 1469 | + [request startSynchronous]; | ||
| 1470 | + | ||
| 1471 | + success = ![request connectionCanBeReused]; | ||
| 1472 | + GHAssertTrue(success,@"Should not be able to re-use a request sent with Connection:close"); | ||
| 1473 | + | ||
| 1467 | } | 1474 | } |
| 1468 | 1475 | ||
| 1469 | - (void)testPersistentConnectionTimeout | 1476 | - (void)testPersistentConnectionTimeout |
-
Please register or login to post a comment