24 |
24 |
#import "ASIDataCompressor.h"
|
25 |
25 |
|
26 |
26 |
// Automatically set on build
|
27 |
|
NSString *ASIHTTPRequestVersion = @"v1.8.1-8 2011-06-05";
|
|
27 |
NSString *ASIHTTPRequestVersion = @"v1.8.1-61 2011-09-19";
|
28 |
28 |
|
29 |
29 |
static NSString *defaultUserAgent = nil;
|
30 |
30 |
|
... | ... | |
105 |
105 |
|
106 |
106 |
// When YES, bandwidth will be automatically throttled when using WWAN (3G/Edge/GPRS)
|
107 |
107 |
// Wifi will not be throttled
|
108 |
|
static BOOL shouldThrottleBandwithForWWANOnly = NO;
|
|
108 |
static BOOL shouldThrottleBandwidthForWWANOnly = NO;
|
109 |
109 |
#endif
|
110 |
110 |
|
111 |
111 |
// Mediates access to the session cookies so requests
|
... | ... | |
392 |
392 |
[connectionInfo release];
|
393 |
393 |
[requestID release];
|
394 |
394 |
[dataDecompressor release];
|
395 |
|
[userAgent release];
|
|
395 |
[userAgentString release];
|
396 |
396 |
|
397 |
397 |
#if NS_BLOCKS_AVAILABLE
|
398 |
398 |
[self releaseBlocksOnMainThread];
|
... | ... | |
460 |
460 |
[authenticationNeededBlock release];
|
461 |
461 |
authenticationNeededBlock = nil;
|
462 |
462 |
}
|
|
463 |
if (requestRedirectedBlock) {
|
|
464 |
[blocks addObject:requestRedirectedBlock];
|
|
465 |
[requestRedirectedBlock release];
|
|
466 |
requestRedirectedBlock = nil;
|
|
467 |
}
|
463 |
468 |
[[self class] performSelectorOnMainThread:@selector(releaseBlocks:) withObject:blocks waitUntilDone:[NSThread isMainThread]];
|
464 |
469 |
}
|
465 |
470 |
// Always called on main thread
|
... | ... | |
696 |
701 |
- (void)cancelOnRequestThread
|
697 |
702 |
{
|
698 |
703 |
#if DEBUG_REQUEST_STATUS
|
699 |
|
NSLog(@"[STATUS] Request cancelled: %@",self);
|
|
704 |
ASI_DEBUG_LOG(@"[STATUS] Request cancelled: %@",self);
|
700 |
705 |
#endif
|
701 |
706 |
|
702 |
707 |
[[self cancelledLock] lock];
|
... | ... | |
786 |
791 |
- (void)startSynchronous
|
787 |
792 |
{
|
788 |
793 |
#if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
|
789 |
|
NSLog(@"[STATUS] Starting synchronous request %@",self);
|
|
794 |
ASI_DEBUG_LOG(@"[STATUS] Starting synchronous request %@",self);
|
790 |
795 |
#endif
|
791 |
796 |
[self setSynchronous:YES];
|
792 |
797 |
[self setRunLoopMode:ASIHTTPRequestRunLoopMode];
|
... | ... | |
811 |
816 |
- (void)startAsynchronous
|
812 |
817 |
{
|
813 |
818 |
#if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
|
814 |
|
NSLog(@"[STATUS] Starting asynchronous request %@",self);
|
|
819 |
ASI_DEBUG_LOG(@"[STATUS] Starting asynchronous request %@",self);
|
815 |
820 |
#endif
|
816 |
821 |
[sharedQueue addOperation:self];
|
817 |
822 |
}
|
... | ... | |
843 |
848 |
|
844 |
849 |
#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
|
845 |
850 |
if ([ASIHTTPRequest isMultitaskingSupported] && [self shouldContinueWhenAppEntersBackground]) {
|
846 |
|
backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
|
847 |
|
// Synchronize the cleanup call on the main thread in case
|
848 |
|
// the task actually finishes at around the same time.
|
849 |
|
dispatch_async(dispatch_get_main_queue(), ^{
|
850 |
|
if (backgroundTask != UIBackgroundTaskInvalid)
|
851 |
|
{
|
852 |
|
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
|
853 |
|
backgroundTask = UIBackgroundTaskInvalid;
|
854 |
|
[self cancel];
|
855 |
|
}
|
856 |
|
});
|
857 |
|
}];
|
|
851 |
if (!backgroundTask || backgroundTask == UIBackgroundTaskInvalid) {
|
|
852 |
backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
|
|
853 |
// Synchronize the cleanup call on the main thread in case
|
|
854 |
// the task actually finishes at around the same time.
|
|
855 |
dispatch_async(dispatch_get_main_queue(), ^{
|
|
856 |
if (backgroundTask != UIBackgroundTaskInvalid)
|
|
857 |
{
|
|
858 |
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
|
|
859 |
backgroundTask = UIBackgroundTaskInvalid;
|
|
860 |
[self cancel];
|
|
861 |
}
|
|
862 |
});
|
|
863 |
}];
|
|
864 |
}
|
858 |
865 |
}
|
859 |
866 |
#endif
|
860 |
867 |
|
... | ... | |
962 |
969 |
// Do we want to send credentials before we are asked for them?
|
963 |
970 |
if (![self shouldPresentCredentialsBeforeChallenge]) {
|
964 |
971 |
#if DEBUG_HTTP_AUTHENTICATION
|
965 |
|
NSLog(@"[AUTH] Request %@ will not send credentials to the server until it asks for them",self);
|
|
972 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will not send credentials to the server until it asks for them",self);
|
966 |
973 |
#endif
|
967 |
974 |
return;
|
968 |
975 |
}
|
... | ... | |
977 |
984 |
[self addBasicAuthenticationHeaderWithUsername:[self username] andPassword:[self password]];
|
978 |
985 |
|
979 |
986 |
#if DEBUG_HTTP_AUTHENTICATION
|
980 |
|
NSLog(@"[AUTH] Request %@ has a username and password set, and was manually configured to use BASIC. Will send credentials without waiting for an authentication challenge",self);
|
|
987 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ has a username and password set, and was manually configured to use BASIC. Will send credentials without waiting for an authentication challenge",self);
|
981 |
988 |
#endif
|
982 |
989 |
|
983 |
990 |
} else {
|
... | ... | |
996 |
1003 |
if (CFHTTPMessageApplyCredentialDictionary(request, (CFHTTPAuthenticationRef)[credentials objectForKey:@"Authentication"], (CFDictionaryRef)[credentials objectForKey:@"Credentials"], NULL)) {
|
997 |
1004 |
[self setAuthenticationScheme:[credentials objectForKey:@"AuthenticationScheme"]];
|
998 |
1005 |
#if DEBUG_HTTP_AUTHENTICATION
|
999 |
|
NSLog(@"[AUTH] Request %@ found cached credentials (%@), will reuse without waiting for an authentication challenge",self,[credentials objectForKey:@"AuthenticationScheme"]);
|
|
1006 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ found cached credentials (%@), will reuse without waiting for an authentication challenge",self,[credentials objectForKey:@"AuthenticationScheme"]);
|
1000 |
1007 |
#endif
|
1001 |
1008 |
} else {
|
1002 |
1009 |
[[self class] removeAuthenticationCredentialsFromSessionStore:[credentials objectForKey:@"Credentials"]];
|
1003 |
1010 |
#if DEBUG_HTTP_AUTHENTICATION
|
1004 |
|
NSLog(@"[AUTH] Failed to apply cached credentials to request %@. These will be removed from the session store, and this request will wait for an authentication challenge",self);
|
|
1011 |
ASI_DEBUG_LOG(@"[AUTH] Failed to apply cached credentials to request %@. These will be removed from the session store, and this request will wait for an authentication challenge",self);
|
1005 |
1012 |
#endif
|
1006 |
1013 |
}
|
1007 |
1014 |
|
... | ... | |
1011 |
1018 |
NSDictionary *usernameAndPassword = [credentials objectForKey:@"Credentials"];
|
1012 |
1019 |
[self addBasicAuthenticationHeaderWithUsername:[usernameAndPassword objectForKey:(NSString *)kCFHTTPAuthenticationUsername] andPassword:[usernameAndPassword objectForKey:(NSString *)kCFHTTPAuthenticationPassword]];
|
1013 |
1020 |
#if DEBUG_HTTP_AUTHENTICATION
|
1014 |
|
NSLog(@"[AUTH] Request %@ found cached BASIC credentials from a previous request. Will send credentials without waiting for an authentication challenge",self);
|
|
1021 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ found cached BASIC credentials from a previous request. Will send credentials without waiting for an authentication challenge",self);
|
1015 |
1022 |
#endif
|
1016 |
1023 |
}
|
1017 |
1024 |
}
|
... | ... | |
1081 |
1088 |
|
1082 |
1089 |
// Build and set the user agent string if the request does not already have a custom user agent specified
|
1083 |
1090 |
if (![[self requestHeaders] objectForKey:@"User-Agent"]) {
|
1084 |
|
NSString *userAgentString = [self userAgent];
|
1085 |
|
if (!userAgentString) {
|
1086 |
|
userAgentString = [ASIHTTPRequest defaultUserAgentString];
|
|
1091 |
NSString *tempUserAgentString = [self userAgentString];
|
|
1092 |
if (!tempUserAgentString) {
|
|
1093 |
tempUserAgentString = [ASIHTTPRequest defaultUserAgentString];
|
1087 |
1094 |
}
|
1088 |
|
if (userAgentString) {
|
1089 |
|
[self addRequestHeader:@"User-Agent" value:userAgentString];
|
|
1095 |
if (tempUserAgentString) {
|
|
1096 |
[self addRequestHeader:@"User-Agent" value:tempUserAgentString];
|
1090 |
1097 |
}
|
1091 |
1098 |
}
|
1092 |
1099 |
|
... | ... | |
1169 |
1176 |
} else {
|
1170 |
1177 |
[self setPostBodyReadStream:[ASIInputStream inputStreamWithFileAtPath:[self postBodyFilePath] request:self]];
|
1171 |
1178 |
}
|
1172 |
|
[self setReadStream:[(NSInputStream *)CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream]) autorelease]];
|
|
1179 |
[self setReadStream:[NSMakeCollectable(CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream])) autorelease]];
|
1173 |
1180 |
} else {
|
1174 |
1181 |
|
1175 |
1182 |
// If we have a request body, we'll stream it from memory using our custom stream, so that we can measure bandwidth use and it can be bandwidth-throttled if necessary
|
... | ... | |
1179 |
1186 |
} else if ([self postBody]) {
|
1180 |
1187 |
[self setPostBodyReadStream:[ASIInputStream inputStreamWithData:[self postBody] request:self]];
|
1181 |
1188 |
}
|
1182 |
|
[self setReadStream:[(NSInputStream *)CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream]) autorelease]];
|
|
1189 |
[self setReadStream:[NSMakeCollectable(CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream])) autorelease]];
|
1183 |
1190 |
|
1184 |
1191 |
} else {
|
1185 |
|
[self setReadStream:[(NSInputStream *)CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request) autorelease]];
|
|
1192 |
[self setReadStream:[NSMakeCollectable(CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request)) autorelease]];
|
1186 |
1193 |
}
|
1187 |
1194 |
}
|
1188 |
1195 |
|
... | ... | |
1198 |
1205 |
// Handle SSL certificate settings
|
1199 |
1206 |
//
|
1200 |
1207 |
|
1201 |
|
if([[[[self url] scheme] lowercaseString] isEqualToString:@"https"]) {
|
1202 |
|
|
1203 |
|
NSMutableDictionary *sslProperties = [NSMutableDictionary dictionaryWithCapacity:1];
|
1204 |
|
|
|
1208 |
if([[[[self url] scheme] lowercaseString] isEqualToString:@"https"]) {
|
|
1209 |
|
1205 |
1210 |
// Tell CFNetwork not to validate SSL certificates
|
1206 |
1211 |
if (![self validatesSecureCertificate]) {
|
1207 |
|
[sslProperties setObject:(NSString *)kCFBooleanFalse forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];
|
1208 |
|
}
|
1209 |
|
|
|
1212 |
// see: http://iphonedevelopment.blogspot.com/2010/05/nsstream-tcp-and-ssl.html
|
|
1213 |
|
|
1214 |
NSDictionary *sslProperties = [[NSDictionary alloc] initWithObjectsAndKeys:
|
|
1215 |
[NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
|
|
1216 |
[NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
|
|
1217 |
[NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
|
|
1218 |
kCFNull,kCFStreamSSLPeerName,
|
|
1219 |
nil];
|
|
1220 |
|
|
1221 |
CFReadStreamSetProperty((CFReadStreamRef)[self readStream],
|
|
1222 |
kCFStreamPropertySSLSettings,
|
|
1223 |
(CFTypeRef)sslProperties);
|
|
1224 |
[sslProperties release];
|
|
1225 |
}
|
|
1226 |
|
1210 |
1227 |
// Tell CFNetwork to use a client certificate
|
1211 |
1228 |
if (clientCertificateIdentity) {
|
1212 |
|
|
|
1229 |
NSMutableDictionary *sslProperties = [NSMutableDictionary dictionaryWithCapacity:1];
|
|
1230 |
|
1213 |
1231 |
NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[clientCertificates count]+1];
|
1214 |
1232 |
|
1215 |
1233 |
// The first object in the array is our SecIdentityRef
|
... | ... | |
1219 |
1237 |
for (id cert in clientCertificates) {
|
1220 |
1238 |
[certificates addObject:cert];
|
1221 |
1239 |
}
|
|
1240 |
|
1222 |
1241 |
[sslProperties setObject:certificates forKey:(NSString *)kCFStreamSSLCertificates];
|
|
1242 |
|
|
1243 |
CFReadStreamSetProperty((CFReadStreamRef)[self readStream], kCFStreamPropertySSLSettings, sslProperties);
|
1223 |
1244 |
}
|
1224 |
|
|
1225 |
|
CFReadStreamSetProperty((CFReadStreamRef)[self readStream], kCFStreamPropertySSLSettings, sslProperties);
|
|
1245 |
|
1226 |
1246 |
}
|
1227 |
1247 |
|
1228 |
1248 |
//
|
... | ... | |
1288 |
1308 |
// Check if we should have expired this connection
|
1289 |
1309 |
} else if ([[[self connectionInfo] objectForKey:@"expires"] timeIntervalSinceNow] < 0) {
|
1290 |
1310 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
1291 |
|
NSLog(@"[CONNECTION] Not re-using connection #%i because it has expired",[[[self connectionInfo] objectForKey:@"id"] intValue]);
|
|
1311 |
ASI_DEBUG_LOG(@"[CONNECTION] Not re-using connection #%i because it has expired",[[[self connectionInfo] objectForKey:@"id"] intValue]);
|
1292 |
1312 |
#endif
|
1293 |
1313 |
[persistentConnectionsPool removeObject:[self connectionInfo]];
|
1294 |
1314 |
[self setConnectionInfo:nil];
|
... | ... | |
1296 |
1316 |
} else if ([[self connectionInfo] objectForKey:@"request"] != nil) {
|
1297 |
1317 |
//Some other request reused this connection already - we'll have to create a new one
|
1298 |
1318 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
1299 |
|
NSLog(@"%@ - Not re-using connection #%i for request #%i because it is already used by request #%i",self,[[[self connectionInfo] objectForKey:@"id"] intValue],[[self requestID] intValue],[[[self connectionInfo] objectForKey:@"request"] intValue]);
|
|
1319 |
ASI_DEBUG_LOG(@"%@ - Not re-using connection #%i for request #%i because it is already used by request #%i",self,[[[self connectionInfo] objectForKey:@"id"] intValue],[[self requestID] intValue],[[[self connectionInfo] objectForKey:@"request"] intValue]);
|
1300 |
1320 |
#endif
|
1301 |
1321 |
[self setConnectionInfo:nil];
|
1302 |
1322 |
}
|
... | ... | |
1340 |
1360 |
CFReadStreamSetProperty((CFReadStreamRef)[self readStream], kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue);
|
1341 |
1361 |
|
1342 |
1362 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
1343 |
|
NSLog(@"[CONNECTION] Request #%@ will use connection #%i",[self requestID],[[[self connectionInfo] objectForKey:@"id"] intValue]);
|
|
1363 |
ASI_DEBUG_LOG(@"[CONNECTION] Request #%@ will use connection #%i",[self requestID],[[[self connectionInfo] objectForKey:@"id"] intValue]);
|
1344 |
1364 |
#endif
|
1345 |
1365 |
|
1346 |
1366 |
|
... | ... | |
1351 |
1371 |
|
1352 |
1372 |
} else {
|
1353 |
1373 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
1354 |
|
NSLog(@"[CONNECTION] Request %@ will not use a persistent connection",self);
|
|
1374 |
ASI_DEBUG_LOG(@"[CONNECTION] Request %@ will not use a persistent connection",self);
|
1355 |
1375 |
#endif
|
1356 |
1376 |
}
|
1357 |
1377 |
|
... | ... | |
1519 |
1539 |
[self setLastBytesSent:totalBytesSent];
|
1520 |
1540 |
|
1521 |
1541 |
// Find out how much data we've uploaded so far
|
1522 |
|
[self setTotalBytesSent:[NSMakeCollectable([(NSNumber *)CFReadStreamCopyProperty((CFReadStreamRef)[self readStream], kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease]) unsignedLongLongValue]];
|
|
1542 |
[self setTotalBytesSent:[[NSMakeCollectable(CFReadStreamCopyProperty((CFReadStreamRef)[self readStream], kCFStreamPropertyHTTPRequestBytesWrittenCount)) autorelease] unsignedLongLongValue]];
|
1523 |
1543 |
if (totalBytesSent > lastBytesSent) {
|
1524 |
1544 |
|
1525 |
1545 |
// We've uploaded more data, reset the timeout
|
... | ... | |
1528 |
1548 |
|
1529 |
1549 |
#if DEBUG_REQUEST_STATUS
|
1530 |
1550 |
if ([self totalBytesSent] == [self postLength]) {
|
1531 |
|
NSLog(@"[STATUS] Request %@ finished uploading data",self);
|
|
1551 |
ASI_DEBUG_LOG(@"[STATUS] Request %@ finished uploading data",self);
|
1532 |
1552 |
}
|
1533 |
1553 |
#endif
|
1534 |
1554 |
}
|
... | ... | |
1985 |
2005 |
- (void)requestFinished
|
1986 |
2006 |
{
|
1987 |
2007 |
#if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
|
1988 |
|
NSLog(@"[STATUS] Request finished: %@",self);
|
|
2008 |
ASI_DEBUG_LOG(@"[STATUS] Request finished: %@",self);
|
1989 |
2009 |
#endif
|
1990 |
2010 |
if ([self error] || [self mainRequest]) {
|
1991 |
2011 |
return;
|
... | ... | |
2052 |
2072 |
- (void)failWithError:(NSError *)theError
|
2053 |
2073 |
{
|
2054 |
2074 |
#if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
|
2055 |
|
NSLog(@"[STATUS] Request %@: %@",self,(theError == ASIRequestCancelledError ? @"Cancelled" : @"Failed"));
|
|
2075 |
ASI_DEBUG_LOG(@"[STATUS] Request %@: %@",self,(theError == ASIRequestCancelledError ? @"Cancelled" : @"Failed"));
|
2056 |
2076 |
#endif
|
2057 |
2077 |
[self setComplete:YES];
|
2058 |
2078 |
|
... | ... | |
2060 |
2080 |
if (theError && [theError code] != ASIAuthenticationErrorType && [theError code] != ASITooMuchRedirectionErrorType) {
|
2061 |
2081 |
[connectionsLock lock];
|
2062 |
2082 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
2063 |
|
NSLog(@"[CONNECTION] Request #%@ failed and will invalidate connection #%@",[self requestID],[[self connectionInfo] objectForKey:@"id"]);
|
|
2083 |
ASI_DEBUG_LOG(@"[CONNECTION] Request #%@ failed and will invalidate connection #%@",[self requestID],[[self connectionInfo] objectForKey:@"id"]);
|
2064 |
2084 |
#endif
|
2065 |
2085 |
[[self connectionInfo] removeObjectForKey:@"request"];
|
2066 |
2086 |
[persistentConnectionsPool removeObject:[self connectionInfo]];
|
... | ... | |
2128 |
2148 |
|
2129 |
2149 |
#if DEBUG_REQUEST_STATUS
|
2130 |
2150 |
if ([self totalBytesSent] == [self postLength]) {
|
2131 |
|
NSLog(@"[STATUS] Request %@ received response headers",self);
|
|
2151 |
ASI_DEBUG_LOG(@"[STATUS] Request %@ received response headers",self);
|
2132 |
2152 |
}
|
2133 |
2153 |
#endif
|
2134 |
2154 |
|
2135 |
|
[self setResponseHeaders:[(NSDictionary *)CFHTTPMessageCopyAllHeaderFields(message) autorelease]];
|
|
2155 |
[self setResponseHeaders:[NSMakeCollectable(CFHTTPMessageCopyAllHeaderFields(message)) autorelease]];
|
2136 |
2156 |
[self setResponseStatusCode:(int)CFHTTPMessageGetResponseStatusCode(message)];
|
2137 |
|
[self setResponseStatusMessage:[(NSString *)CFHTTPMessageCopyResponseStatusLine(message) autorelease]];
|
|
2157 |
[self setResponseStatusMessage:[NSMakeCollectable(CFHTTPMessageCopyResponseStatusLine(message)) autorelease]];
|
2138 |
2158 |
|
2139 |
2159 |
if ([self downloadCache] && ([[self downloadCache] canUseCachedDataForRequest:self])) {
|
2140 |
2160 |
|
... | ... | |
2156 |
2176 |
} else {
|
2157 |
2177 |
#if DEBUG_HTTP_AUTHENTICATION
|
2158 |
2178 |
if ([self authenticationScheme]) {
|
2159 |
|
NSLog(@"[AUTH] Request %@ has passed %@ authentication",self,[self authenticationScheme]);
|
|
2179 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ has passed %@ authentication",self,[self authenticationScheme]);
|
2160 |
2180 |
}
|
2161 |
2181 |
#endif
|
2162 |
2182 |
}
|
... | ... | |
2168 |
2188 |
if (!requestAuthentication && [[self authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && [self username] && [self password] && [self useSessionPersistence]) {
|
2169 |
2189 |
|
2170 |
2190 |
#if DEBUG_HTTP_AUTHENTICATION
|
2171 |
|
NSLog(@"[AUTH] Request %@ passed BASIC authentication, and will save credentials in the session store for future use",self);
|
|
2191 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ passed BASIC authentication, and will save credentials in the session store for future use",self);
|
2172 |
2192 |
#endif
|
2173 |
2193 |
|
2174 |
2194 |
NSMutableDictionary *newCredentials = [NSMutableDictionary dictionaryWithCapacity:2];
|
... | ... | |
2238 |
2258 |
|
2239 |
2259 |
NSString *connectionHeader = [[[self responseHeaders] objectForKey:@"Connection"] lowercaseString];
|
2240 |
2260 |
|
2241 |
|
NSString *httpVersion = NSMakeCollectable([(NSString *)CFHTTPMessageCopyVersion(message) autorelease]);
|
|
2261 |
NSString *httpVersion = [NSMakeCollectable(CFHTTPMessageCopyVersion(message)) autorelease];
|
2242 |
2262 |
|
2243 |
2263 |
// Don't re-use the connection if the server is HTTP 1.0 and didn't send Connection: Keep-Alive
|
2244 |
2264 |
if (![httpVersion isEqualToString:(NSString *)kCFHTTPVersion1_0] || [connectionHeader isEqualToString:@"keep-alive"]) {
|
... | ... | |
2262 |
2282 |
[self setConnectionCanBeReused:YES];
|
2263 |
2283 |
[self setPersistentConnectionTimeoutSeconds:timeout];
|
2264 |
2284 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
2265 |
|
NSLog(@"[CONNECTION] Got a keep-alive header, will keep this connection open for %f seconds", [self persistentConnectionTimeoutSeconds]);
|
|
2285 |
ASI_DEBUG_LOG(@"[CONNECTION] Got a keep-alive header, will keep this connection open for %f seconds", [self persistentConnectionTimeoutSeconds]);
|
2266 |
2286 |
#endif
|
2267 |
2287 |
}
|
2268 |
2288 |
|
... | ... | |
2270 |
2290 |
} else {
|
2271 |
2291 |
[self setConnectionCanBeReused:YES];
|
2272 |
2292 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
2273 |
|
NSLog(@"[CONNECTION] Got no keep-alive header, will keep this connection open for %f seconds", [self persistentConnectionTimeoutSeconds]);
|
|
2293 |
ASI_DEBUG_LOG(@"[CONNECTION] Got no keep-alive header, will keep this connection open for %f seconds", [self persistentConnectionTimeoutSeconds]);
|
2274 |
2294 |
#endif
|
2275 |
2295 |
}
|
2276 |
2296 |
}
|
... | ... | |
2334 |
2354 |
[self setRequestCookies:[NSMutableArray array]];
|
2335 |
2355 |
|
2336 |
2356 |
#if DEBUG_REQUEST_STATUS
|
2337 |
|
NSLog(@"[STATUS] Request will redirect (code: %i): %@",responseCode,self);
|
|
2357 |
ASI_DEBUG_LOG(@"[STATUS] Request will redirect (code: %i): %@",responseCode,self);
|
2338 |
2358 |
#endif
|
2339 |
2359 |
|
2340 |
2360 |
return YES;
|
... | ... | |
2523 |
2543 |
if (user && pass) {
|
2524 |
2544 |
|
2525 |
2545 |
#if DEBUG_HTTP_AUTHENTICATION
|
2526 |
|
NSLog(@"[AUTH] Request %@ will use credentials set on its url",self);
|
|
2546 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will use credentials set on its url",self);
|
2527 |
2547 |
#endif
|
2528 |
2548 |
|
2529 |
2549 |
} else {
|
... | ... | |
2534 |
2554 |
pass = [[self mainRequest] password];
|
2535 |
2555 |
|
2536 |
2556 |
#if DEBUG_HTTP_AUTHENTICATION
|
2537 |
|
NSLog(@"[AUTH] Request %@ will use credentials from its parent request",self);
|
|
2557 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will use credentials from its parent request",self);
|
2538 |
2558 |
#endif
|
2539 |
2559 |
|
2540 |
2560 |
// Let's try to use the ones set in this object
|
... | ... | |
2543 |
2563 |
pass = [self password];
|
2544 |
2564 |
|
2545 |
2565 |
#if DEBUG_HTTP_AUTHENTICATION
|
2546 |
|
NSLog(@"[AUTH] Request %@ will use username and password properties as credentials",self);
|
|
2566 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will use username and password properties as credentials",self);
|
2547 |
2567 |
#endif
|
2548 |
2568 |
}
|
2549 |
2569 |
}
|
... | ... | |
2556 |
2576 |
pass = [authenticationCredentials password];
|
2557 |
2577 |
#if DEBUG_HTTP_AUTHENTICATION
|
2558 |
2578 |
if (user && pass) {
|
2559 |
|
NSLog(@"[AUTH] Request %@ will use credentials from the keychain",self);
|
|
2579 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will use credentials from the keychain",self);
|
2560 |
2580 |
}
|
2561 |
2581 |
#endif
|
2562 |
2582 |
}
|
... | ... | |
2592 |
2612 |
- (void)retryUsingSuppliedCredentials
|
2593 |
2613 |
{
|
2594 |
2614 |
#if DEBUG_HTTP_AUTHENTICATION
|
2595 |
|
NSLog(@"[AUTH] Request %@ received credentials from its delegate or an ASIAuthenticationDialog, will retry",self);
|
|
2615 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ received credentials from its delegate or an ASIAuthenticationDialog, will retry",self);
|
2596 |
2616 |
#endif
|
2597 |
2617 |
//If the url was changed by the delegate, our CFHTTPMessageRef will be NULL and we'll go back to the start
|
2598 |
2618 |
if (!request) {
|
... | ... | |
2606 |
2626 |
- (void)cancelAuthentication
|
2607 |
2627 |
{
|
2608 |
2628 |
#if DEBUG_HTTP_AUTHENTICATION
|
2609 |
|
NSLog(@"[AUTH] Request %@ had authentication cancelled by its delegate or an ASIAuthenticationDialog",self);
|
|
2629 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ had authentication cancelled by its delegate or an ASIAuthenticationDialog",self);
|
2610 |
2630 |
#endif
|
2611 |
2631 |
[self performSelector:@selector(failAuthentication) onThread:[[self class] threadForRequest:self] withObject:nil waitUntilDone:NO];
|
2612 |
2632 |
}
|
... | ... | |
2749 |
2769 |
CFHTTPMessageRef responseHeader = (CFHTTPMessageRef) CFReadStreamCopyProperty((CFReadStreamRef)[self readStream],kCFStreamPropertyHTTPResponseHeader);
|
2750 |
2770 |
proxyAuthentication = CFHTTPAuthenticationCreateFromResponse(NULL, responseHeader);
|
2751 |
2771 |
CFRelease(responseHeader);
|
2752 |
|
[self setProxyAuthenticationScheme:[(NSString *)CFHTTPAuthenticationCopyMethod(proxyAuthentication) autorelease]];
|
|
2772 |
[self setProxyAuthenticationScheme:[NSMakeCollectable(CFHTTPAuthenticationCopyMethod(proxyAuthentication)) autorelease]];
|
2753 |
2773 |
}
|
2754 |
2774 |
|
2755 |
2775 |
// If we haven't got a CFHTTPAuthenticationRef by now, something is badly wrong, so we'll have to give up
|
... | ... | |
2762 |
2782 |
// Get the authentication realm
|
2763 |
2783 |
[self setProxyAuthenticationRealm:nil];
|
2764 |
2784 |
if (!CFHTTPAuthenticationRequiresAccountDomain(proxyAuthentication)) {
|
2765 |
|
[self setProxyAuthenticationRealm:[(NSString *)CFHTTPAuthenticationCopyRealm(proxyAuthentication) autorelease]];
|
|
2785 |
[self setProxyAuthenticationRealm:[NSMakeCollectable(CFHTTPAuthenticationCopyRealm(proxyAuthentication)) autorelease]];
|
2766 |
2786 |
}
|
2767 |
2787 |
|
2768 |
2788 |
// See if authentication is valid
|
... | ... | |
2926 |
2946 |
CFHTTPMessageRef responseHeader = (CFHTTPMessageRef) CFReadStreamCopyProperty((CFReadStreamRef)[self readStream],kCFStreamPropertyHTTPResponseHeader);
|
2927 |
2947 |
requestAuthentication = CFHTTPAuthenticationCreateFromResponse(NULL, responseHeader);
|
2928 |
2948 |
CFRelease(responseHeader);
|
2929 |
|
[self setAuthenticationScheme:[(NSString *)CFHTTPAuthenticationCopyMethod(requestAuthentication) autorelease]];
|
|
2949 |
[self setAuthenticationScheme:[NSMakeCollectable(CFHTTPAuthenticationCopyMethod(requestAuthentication)) autorelease]];
|
2930 |
2950 |
}
|
2931 |
2951 |
|
2932 |
2952 |
if (!requestAuthentication) {
|
2933 |
2953 |
#if DEBUG_HTTP_AUTHENTICATION
|
2934 |
|
NSLog(@"[AUTH] Request %@ failed to read authentication information from response headers",self);
|
|
2954 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ failed to read authentication information from response headers",self);
|
2935 |
2955 |
#endif
|
2936 |
2956 |
|
2937 |
2957 |
[self cancelLoad];
|
... | ... | |
2942 |
2962 |
// Get the authentication realm
|
2943 |
2963 |
[self setAuthenticationRealm:nil];
|
2944 |
2964 |
if (!CFHTTPAuthenticationRequiresAccountDomain(requestAuthentication)) {
|
2945 |
|
[self setAuthenticationRealm:[(NSString *)CFHTTPAuthenticationCopyRealm(requestAuthentication) autorelease]];
|
|
2965 |
[self setAuthenticationRealm:[NSMakeCollectable(CFHTTPAuthenticationCopyRealm(requestAuthentication)) autorelease]];
|
2946 |
2966 |
}
|
2947 |
2967 |
|
2948 |
2968 |
#if DEBUG_HTTP_AUTHENTICATION
|
... | ... | |
2953 |
2973 |
realm = @"";
|
2954 |
2974 |
}
|
2955 |
2975 |
if ([self authenticationScheme] != (NSString *)kCFHTTPAuthenticationSchemeNTLM || [self authenticationRetryCount] == 0) {
|
2956 |
|
NSLog(@"[AUTH] Request %@ received 401 challenge and must authenticate using %@%@",self,[self authenticationScheme],realm);
|
|
2976 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ received 401 challenge and must authenticate using %@%@",self,[self authenticationScheme],realm);
|
2957 |
2977 |
} else {
|
2958 |
|
NSLog(@"[AUTH] Request %@ NTLM handshake step %i",self,[self authenticationRetryCount]+1);
|
|
2978 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ NTLM handshake step %i",self,[self authenticationRetryCount]+1);
|
2959 |
2979 |
}
|
2960 |
2980 |
#endif
|
2961 |
2981 |
|
... | ... | |
2970 |
2990 |
if (err.domain == kCFStreamErrorDomainHTTP && (err.error == kCFStreamErrorHTTPAuthenticationBadUserName || err.error == kCFStreamErrorHTTPAuthenticationBadPassword)) {
|
2971 |
2991 |
|
2972 |
2992 |
#if DEBUG_HTTP_AUTHENTICATION
|
2973 |
|
NSLog(@"[AUTH] Request %@ had bad credentials, will remove them from the session store if they are cached",self);
|
|
2993 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ had bad credentials, will remove them from the session store if they are cached",self);
|
2974 |
2994 |
#endif
|
2975 |
2995 |
|
2976 |
2996 |
// Prevent more than one request from asking for credentials at once
|
... | ... | |
2984 |
3004 |
if ([self error] || [self isCancelled]) {
|
2985 |
3005 |
|
2986 |
3006 |
#if DEBUG_HTTP_AUTHENTICATION
|
2987 |
|
NSLog(@"[AUTH] Request %@ failed or was cancelled while waiting to access credentials",self);
|
|
3007 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ failed or was cancelled while waiting to access credentials",self);
|
2988 |
3008 |
#endif
|
2989 |
3009 |
|
2990 |
3010 |
[delegateAuthenticationLock unlock];
|
... | ... | |
2997 |
3017 |
if (credentials && [self applyCredentials:[credentials objectForKey:@"Credentials"]]) {
|
2998 |
3018 |
|
2999 |
3019 |
#if DEBUG_HTTP_AUTHENTICATION
|
3000 |
|
NSLog(@"[AUTH] Request %@ will reuse cached credentials from the session (%@)",self,[credentials objectForKey:@"AuthenticationScheme"]);
|
|
3020 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will reuse cached credentials from the session (%@)",self,[credentials objectForKey:@"AuthenticationScheme"]);
|
3001 |
3021 |
#endif
|
3002 |
3022 |
|
3003 |
3023 |
[delegateAuthenticationLock unlock];
|
... | ... | |
3011 |
3031 |
if ([self willAskDelegateForCredentials]) {
|
3012 |
3032 |
|
3013 |
3033 |
#if DEBUG_HTTP_AUTHENTICATION
|
3014 |
|
NSLog(@"[AUTH] Request %@ will ask its delegate for credentials to use",self);
|
|
3034 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will ask its delegate for credentials to use",self);
|
3015 |
3035 |
#endif
|
3016 |
3036 |
|
3017 |
3037 |
[delegateAuthenticationLock unlock];
|
... | ... | |
3020 |
3040 |
if ([self showAuthenticationDialog]) {
|
3021 |
3041 |
|
3022 |
3042 |
#if DEBUG_HTTP_AUTHENTICATION
|
3023 |
|
NSLog(@"[AUTH] Request %@ will ask ASIAuthenticationDialog for credentials",self);
|
|
3043 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will ask ASIAuthenticationDialog for credentials",self);
|
3024 |
3044 |
#endif
|
3025 |
3045 |
|
3026 |
3046 |
[delegateAuthenticationLock unlock];
|
... | ... | |
3030 |
3050 |
}
|
3031 |
3051 |
|
3032 |
3052 |
#if DEBUG_HTTP_AUTHENTICATION
|
3033 |
|
NSLog(@"[AUTH] Request %@ has no credentials to present and must give up",self);
|
|
3053 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ has no credentials to present and must give up",self);
|
3034 |
3054 |
#endif
|
3035 |
3055 |
|
3036 |
3056 |
[self cancelLoad];
|
... | ... | |
3048 |
3068 |
// We've failed NTLM authentication twice, we should assume our credentials are wrong
|
3049 |
3069 |
} else if ([self authenticationScheme] == (NSString *)kCFHTTPAuthenticationSchemeNTLM && [self authenticationRetryCount ] == 2) {
|
3050 |
3070 |
#if DEBUG_HTTP_AUTHENTICATION
|
3051 |
|
NSLog(@"[AUTH] Request %@ has failed NTLM authentication",self);
|
|
3071 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ has failed NTLM authentication",self);
|
3052 |
3072 |
#endif
|
3053 |
3073 |
|
3054 |
3074 |
[self failWithError:ASIAuthenticationError];
|
... | ... | |
3056 |
3076 |
} else {
|
3057 |
3077 |
|
3058 |
3078 |
#if DEBUG_HTTP_AUTHENTICATION
|
3059 |
|
NSLog(@"[AUTH] Request %@ had credentials and they were not marked as bad, but we got a 401 all the same.",self);
|
|
3079 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ had credentials and they were not marked as bad, but we got a 401 all the same.",self);
|
3060 |
3080 |
#endif
|
3061 |
3081 |
|
3062 |
3082 |
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Failed to apply credentials to request",NSLocalizedDescriptionKey,nil]]];
|
... | ... | |
3072 |
3092 |
if ([self error] || [self isCancelled]) {
|
3073 |
3093 |
|
3074 |
3094 |
#if DEBUG_HTTP_AUTHENTICATION
|
3075 |
|
NSLog(@"[AUTH] Request %@ failed or was cancelled while waiting to access credentials",self);
|
|
3095 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ failed or was cancelled while waiting to access credentials",self);
|
3076 |
3096 |
#endif
|
3077 |
3097 |
|
3078 |
3098 |
[delegateAuthenticationLock unlock];
|
... | ... | |
3085 |
3105 |
if (credentials && [self applyCredentials:[credentials objectForKey:@"Credentials"]]) {
|
3086 |
3106 |
|
3087 |
3107 |
#if DEBUG_HTTP_AUTHENTICATION
|
3088 |
|
NSLog(@"[AUTH] Request %@ will reuse cached credentials from the session (%@)",self,[credentials objectForKey:@"AuthenticationScheme"]);
|
|
3108 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will reuse cached credentials from the session (%@)",self,[credentials objectForKey:@"AuthenticationScheme"]);
|
3089 |
3109 |
#endif
|
3090 |
3110 |
|
3091 |
3111 |
[delegateAuthenticationLock unlock];
|
... | ... | |
3105 |
3125 |
[self startRequest];
|
3106 |
3126 |
} else {
|
3107 |
3127 |
#if DEBUG_HTTP_AUTHENTICATION
|
3108 |
|
NSLog(@"[AUTH] Request %@ failed to apply credentials",self);
|
|
3128 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ failed to apply credentials",self);
|
3109 |
3129 |
#endif
|
3110 |
3130 |
[delegateAuthenticationLock unlock];
|
3111 |
3131 |
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Failed to apply credentials to request",NSLocalizedDescriptionKey,nil]]];
|
... | ... | |
3115 |
3135 |
if ([self willAskDelegateForCredentials]) {
|
3116 |
3136 |
|
3117 |
3137 |
#if DEBUG_HTTP_AUTHENTICATION
|
3118 |
|
NSLog(@"[AUTH] Request %@ will ask its delegate for credentials to use",self);
|
|
3138 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will ask its delegate for credentials to use",self);
|
3119 |
3139 |
#endif
|
3120 |
3140 |
|
3121 |
3141 |
[delegateAuthenticationLock unlock];
|
... | ... | |
3124 |
3144 |
if ([self showAuthenticationDialog]) {
|
3125 |
3145 |
|
3126 |
3146 |
#if DEBUG_HTTP_AUTHENTICATION
|
3127 |
|
NSLog(@"[AUTH] Request %@ will ask ASIAuthenticationDialog for credentials",self);
|
|
3147 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ will ask ASIAuthenticationDialog for credentials",self);
|
3128 |
3148 |
#endif
|
3129 |
3149 |
|
3130 |
3150 |
[delegateAuthenticationLock unlock];
|
... | ... | |
3132 |
3152 |
}
|
3133 |
3153 |
|
3134 |
3154 |
#if DEBUG_HTTP_AUTHENTICATION
|
3135 |
|
NSLog(@"[AUTH] Request %@ has no credentials to present and must give up",self);
|
|
3155 |
ASI_DEBUG_LOG(@"[AUTH] Request %@ has no credentials to present and must give up",self);
|
3136 |
3156 |
#endif
|
3137 |
3157 |
[delegateAuthenticationLock unlock];
|
3138 |
3158 |
[self failWithError:ASIAuthenticationError];
|
... | ... | |
3159 |
3179 |
|
3160 |
3180 |
if ([self complete] || [self isCancelled]) {
|
3161 |
3181 |
[[self cancelledLock] unlock];
|
3162 |
|
[pool release];
|
|
3182 |
[pool drain];
|
3163 |
3183 |
return;
|
3164 |
3184 |
}
|
3165 |
3185 |
|
... | ... | |
3196 |
3216 |
}
|
3197 |
3217 |
|
3198 |
3218 |
CFRelease(self);
|
3199 |
|
[pool release];
|
|
3219 |
[pool drain];
|
3200 |
3220 |
}
|
3201 |
3221 |
|
3202 |
3222 |
- (BOOL)willAskDelegateToConfirmRedirect
|
... | ... | |
3373 |
3393 |
{
|
3374 |
3394 |
|
3375 |
3395 |
#if DEBUG_REQUEST_STATUS
|
3376 |
|
NSLog(@"[STATUS] Request %@ finished downloading data (%qu bytes)",self, [self totalBytesRead]);
|
|
3396 |
ASI_DEBUG_LOG(@"[STATUS] Request %@ finished downloading data (%qu bytes)",self, [self totalBytesRead]);
|
3377 |
3397 |
#endif
|
3378 |
3398 |
[self setStatusTimer:nil];
|
3379 |
3399 |
[self setDownloadComplete:YES];
|
... | ... | |
3385 |
3405 |
[progressLock lock];
|
3386 |
3406 |
// Find out how much data we've uploaded so far
|
3387 |
3407 |
[self setLastBytesSent:totalBytesSent];
|
3388 |
|
[self setTotalBytesSent:[NSMakeCollectable([(NSNumber *)CFReadStreamCopyProperty((CFReadStreamRef)[self readStream], kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease]) unsignedLongLongValue]];
|
|
3408 |
[self setTotalBytesSent:[[NSMakeCollectable(CFReadStreamCopyProperty((CFReadStreamRef)[self readStream], kCFStreamPropertyHTTPRequestBytesWrittenCount)) autorelease] unsignedLongLongValue]];
|
3389 |
3409 |
[self setComplete:YES];
|
3390 |
3410 |
if (![self contentLength]) {
|
3391 |
3411 |
[self setContentLength:[self totalBytesRead]];
|
... | ... | |
3471 |
3491 |
}
|
3472 |
3492 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
3473 |
3493 |
if ([self requestID]) {
|
3474 |
|
NSLog(@"[CONNECTION] Request #%@ finished using connection #%@",[self requestID], [[self connectionInfo] objectForKey:@"id"]);
|
|
3494 |
ASI_DEBUG_LOG(@"[CONNECTION] Request #%@ finished using connection #%@",[self requestID], [[self connectionInfo] objectForKey:@"id"]);
|
3475 |
3495 |
}
|
3476 |
3496 |
#endif
|
3477 |
3497 |
[[self connectionInfo] removeObjectForKey:@"request"];
|
... | ... | |
3495 |
3515 |
|
3496 |
3516 |
// If request has asked delegate or ASIAuthenticationDialog for credentials
|
3497 |
3517 |
} else if ([self authenticationNeeded]) {
|
3498 |
|
CFRunLoopStop(CFRunLoopGetCurrent());
|
|
3518 |
// Do nothing.
|
3499 |
3519 |
}
|
3500 |
3520 |
|
3501 |
3521 |
}
|
... | ... | |
3507 |
3527 |
|
3508 |
3528 |
// dealloc won't be called when running with GC, so we'll clean these up now
|
3509 |
3529 |
if (request) {
|
3510 |
|
CFMakeCollectable(request);
|
|
3530 |
CFRelease(request);
|
|
3531 |
request = nil;
|
3511 |
3532 |
}
|
3512 |
3533 |
if (requestAuthentication) {
|
3513 |
|
CFMakeCollectable(requestAuthentication);
|
|
3534 |
CFRelease(requestAuthentication);
|
|
3535 |
requestAuthentication = nil;
|
3514 |
3536 |
}
|
3515 |
3537 |
if (proxyAuthentication) {
|
3516 |
|
CFMakeCollectable(proxyAuthentication);
|
|
3538 |
CFRelease(proxyAuthentication);
|
|
3539 |
proxyAuthentication = nil;
|
3517 |
3540 |
}
|
3518 |
3541 |
|
3519 |
3542 |
BOOL wasInProgress = inProgress;
|
... | ... | |
3532 |
3555 |
if (!wasFinished)
|
3533 |
3556 |
[self didChangeValueForKey:@"isFinished"];
|
3534 |
3557 |
|
3535 |
|
CFRunLoopStop(CFRunLoopGetCurrent());
|
3536 |
|
|
3537 |
3558 |
#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
|
3538 |
3559 |
if ([ASIHTTPRequest isMultitaskingSupported] && [self shouldContinueWhenAppEntersBackground]) {
|
3539 |
3560 |
dispatch_async(dispatch_get_main_queue(), ^{
|
... | ... | |
3609 |
3630 |
[self setWillRetryRequest:NO];
|
3610 |
3631 |
|
3611 |
3632 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
3612 |
|
NSLog(@"[CONNECTION] Request attempted to use connection #%@, but it has been closed - will retry with a new connection", [[self connectionInfo] objectForKey:@"id"]);
|
|
3633 |
ASI_DEBUG_LOG(@"[CONNECTION] Request attempted to use connection #%@, but it has been closed - will retry with a new connection", [[self connectionInfo] objectForKey:@"id"]);
|
3613 |
3634 |
#endif
|
3614 |
3635 |
[connectionsLock lock];
|
3615 |
3636 |
[[self connectionInfo] removeObjectForKey:@"request"];
|
... | ... | |
3621 |
3642 |
return YES;
|
3622 |
3643 |
}
|
3623 |
3644 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
3624 |
|
NSLog(@"[CONNECTION] Request attempted to use connection #%@, but it has been closed - we have already retried with a new connection, so we must give up", [[self connectionInfo] objectForKey:@"id"]);
|
|
3645 |
ASI_DEBUG_LOG(@"[CONNECTION] Request attempted to use connection #%@, but it has been closed - we have already retried with a new connection, so we must give up", [[self connectionInfo] objectForKey:@"id"]);
|
3625 |
3646 |
#endif
|
3626 |
3647 |
return NO;
|
3627 |
3648 |
}
|
... | ... | |
3629 |
3650 |
- (void)handleStreamError
|
3630 |
3651 |
|
3631 |
3652 |
{
|
3632 |
|
NSError *underlyingError = NSMakeCollectable([(NSError *)CFReadStreamCopyError((CFReadStreamRef)[self readStream]) autorelease]);
|
|
3653 |
NSError *underlyingError = [NSMakeCollectable(CFReadStreamCopyError((CFReadStreamRef)[self readStream])) autorelease];
|
3633 |
3654 |
|
3634 |
3655 |
if (![self error]) { // We may already have handled this error
|
3635 |
3656 |
|
... | ... | |
3807 |
3828 |
} else {
|
3808 |
3829 |
|
3809 |
3830 |
#if TARGET_OS_IPHONE
|
3810 |
|
NSDictionary *proxySettings = NSMakeCollectable([(NSDictionary *)CFNetworkCopySystemProxySettings() autorelease]);
|
|
3831 |
NSDictionary *proxySettings = [NSMakeCollectable(CFNetworkCopySystemProxySettings()) autorelease];
|
3811 |
3832 |
#else
|
3812 |
|
NSDictionary *proxySettings = NSMakeCollectable([(NSDictionary *)SCDynamicStoreCopyProxies(NULL) autorelease]);
|
|
3833 |
NSDictionary *proxySettings = [NSMakeCollectable(SCDynamicStoreCopyProxies(NULL)) autorelease];
|
3813 |
3834 |
#endif
|
3814 |
3835 |
|
3815 |
|
proxies = NSMakeCollectable([(NSArray *)CFNetworkCopyProxiesForURL((CFURLRef)[self url], (CFDictionaryRef)proxySettings) autorelease]);
|
|
3836 |
proxies = [NSMakeCollectable(CFNetworkCopyProxiesForURL((CFURLRef)[self url], (CFDictionaryRef)proxySettings)) autorelease];
|
3816 |
3837 |
|
3817 |
3838 |
// Now check to see if the proxy settings contained a PAC url, we need to run the script to get the real list of proxies if so
|
3818 |
3839 |
NSDictionary *settings = [proxies objectAtIndex:0];
|
... | ... | |
3964 |
3985 |
|
3965 |
3986 |
// Obtain the list of proxies by running the autoconfiguration script
|
3966 |
3987 |
CFErrorRef err = NULL;
|
3967 |
|
NSArray *proxies = NSMakeCollectable([(NSArray *)CFNetworkCopyProxiesForAutoConfigurationScript((CFStringRef)script,(CFURLRef)[self url], &err) autorelease]);
|
|
3988 |
NSArray *proxies = [NSMakeCollectable(CFNetworkCopyProxiesForAutoConfigurationScript((CFStringRef)script,(CFURLRef)[self url], &err)) autorelease];
|
3968 |
3989 |
if (!err && [proxies count] > 0) {
|
3969 |
3990 |
NSDictionary *settings = [proxies objectAtIndex:0];
|
3970 |
3991 |
[self setProxyHost:[settings objectForKey:(NSString *)kCFProxyHostNameKey]];
|
... | ... | |
4009 |
4030 |
NSDictionary *existingConnection = [persistentConnectionsPool objectAtIndex:i];
|
4010 |
4031 |
if (![existingConnection objectForKey:@"request"] && [[existingConnection objectForKey:@"expires"] timeIntervalSinceNow] <= 0) {
|
4011 |
4032 |
#if DEBUG_PERSISTENT_CONNECTIONS
|
4012 |
|
NSLog(@"[CONNECTION] Closing connection #%i because it has expired",[[existingConnection objectForKey:@"id"] intValue]);
|
|
4033 |
ASI_DEBUG_LOG(@"[CONNECTION] Closing connection #%i because it has expired",[[existingConnection objectForKey:@"id"] intValue]);
|
4013 |
4034 |
#endif
|
4014 |
4035 |
NSInputStream *stream = [existingConnection objectForKey:@"stream"];
|
4015 |
4036 |
if (stream) {
|
... | ... | |
4023 |
4044 |
}
|
4024 |
4045 |
|
4025 |
4046 |
#pragma mark NSCopying
|
4026 |
|
|
4027 |
4047 |
- (id)copyWithZone:(NSZone *)zone
|
4028 |
4048 |
{
|
4029 |
4049 |
// Don't forget - this will return a retained copy!
|
... | ... | |
4078 |
4098 |
[newRequest setShouldUseRFC2616RedirectBehaviour:[self shouldUseRFC2616RedirectBehaviour]];
|
4079 |
4099 |
[newRequest setShouldAttemptPersistentConnection:[self shouldAttemptPersistentConnection]];
|
4080 |
4100 |
[newRequest setPersistentConnectionTimeoutSeconds:[self persistentConnectionTimeoutSeconds]];
|
|
4101 |
[newRequest setAuthenticationScheme:[self authenticationScheme]];
|
4081 |
4102 |
return newRequest;
|
4082 |
4103 |
}
|
4083 |
4104 |
|
... | ... | |
4232 |
4253 |
if ([self username] && [self password]) {
|
4233 |
4254 |
NSDictionary *usernameAndPassword = [theCredentials objectForKey:@"Credentials"];
|
4234 |
4255 |
NSString *storedUsername = [usernameAndPassword objectForKey:(NSString *)kCFHTTPAuthenticationUsername];
|
4235 |
|
NSString *storedPassword = [usernameAndPassword objectForKey:(NSString *)kCFHTTPAuthenticationUsername];
|
|
4256 |
NSString *storedPassword = [usernameAndPassword objectForKey:(NSString *)kCFHTTPAuthenticationPassword];
|
4236 |
4257 |
if (![storedUsername isEqualToString:[self username]] || ![storedPassword isEqualToString:[self password]]) {
|
4237 |
4258 |
continue;
|
4238 |
4259 |
}
|
... | ... | |
4417 |
4438 |
}
|
4418 |
4439 |
return [[defaultUserAgent retain] autorelease];
|
4419 |
4440 |
}
|
|
4441 |
return nil;
|
4420 |
4442 |
}
|
4421 |
4443 |
|
4422 |
4444 |
+ (void)setDefaultUserAgentString:(NSString *)agent
|
... | ... | |
4445 |
4467 |
if (!MIMEType) {
|
4446 |
4468 |
return @"application/octet-stream";
|
4447 |
4469 |
}
|
4448 |
|
return NSMakeCollectable([(NSString *)MIMEType autorelease]);
|
|
4470 |
return [NSMakeCollectable(MIMEType) autorelease];
|
4449 |
4471 |
}
|
4450 |
4472 |
|
4451 |
4473 |
#pragma mark bandwidth measurement / throttling
|
... | ... | |
4464 |
4486 |
if ([self readStreamIsScheduled]) {
|
4465 |
4487 |
[self unscheduleReadStream];
|
4466 |
4488 |
#if DEBUG_THROTTLING
|
4467 |
|
NSLog(@"[THROTTLING] Sleeping request %@ until after %@",self,throttleWakeUpTime);
|
|
4489 |
ASI_DEBUG_LOG(@"[THROTTLING] Sleeping request %@ until after %@",self,throttleWakeUpTime);
|
4468 |
4490 |
#endif
|
4469 |
4491 |
}
|
4470 |
4492 |
} else {
|
4471 |
4493 |
if (![self readStreamIsScheduled]) {
|
4472 |
4494 |
[self scheduleReadStream];
|
4473 |
4495 |
#if DEBUG_THROTTLING
|
4474 |
|
NSLog(@"[THROTTLING] Waking up request %@",self);
|
|
4496 |
ASI_DEBUG_LOG(@"[THROTTLING] Waking up request %@",self);
|
4475 |
4497 |
#endif
|
4476 |
4498 |
}
|
4477 |
4499 |
}
|
... | ... | |
4489 |
4511 |
#if TARGET_OS_IPHONE
|
4490 |
4512 |
[bandwidthThrottlingLock lock];
|
4491 |
4513 |
|
4492 |
|
BOOL throttle = isBandwidthThrottled || (!shouldThrottleBandwithForWWANOnly && (maxBandwidthPerSecond > 0));
|
|
4514 |
BOOL throttle = isBandwidthThrottled || (!shouldThrottleBandwidthForWWANOnly && (maxBandwidthPerSecond > 0));
|
4493 |
4515 |
[bandwidthThrottlingLock unlock];
|
4494 |
4516 |
return throttle;
|
4495 |
4517 |
#else
|
... | ... | |
4534 |
4556 |
}
|
4535 |
4557 |
}
|
4536 |
4558 |
#if DEBUG_THROTTLING
|
4537 |
|
NSLog(@"[THROTTLING] ===Used: %u bytes of bandwidth in last measurement period===",bandwidthUsedInLastSecond);
|
|
4559 |
ASI_DEBUG_LOG(@"[THROTTLING] ===Used: %u bytes of bandwidth in last measurement period===",bandwidthUsedInLastSecond);
|
4538 |
4560 |
#endif
|
4539 |
4561 |
[bandwidthUsageTracker addObject:[NSNumber numberWithUnsignedLong:bandwidthUsedInLastSecond]];
|
4540 |
4562 |
[bandwidthMeasurementDate release];
|
... | ... | |
4569 |
4591 |
// Are we performing bandwidth throttling?
|
4570 |
4592 |
if (
|
4571 |
4593 |
#if TARGET_OS_IPHONE
|
4572 |
|
isBandwidthThrottled || (!shouldThrottleBandwithForWWANOnly && (maxBandwidthPerSecond))
|
|
4594 |
isBandwidthThrottled || (!shouldThrottleBandwidthForWWANOnly && (maxBandwidthPerSecond))
|
4573 |
4595 |
#else
|
4574 |
4596 |
maxBandwidthPerSecond
|
4575 |
4597 |
#endif
|
... | ... | |
4621 |
4643 |
[ASIHTTPRequest setMaxBandwidthPerSecond:0];
|
4622 |
4644 |
[bandwidthThrottlingLock lock];
|
4623 |
4645 |
isBandwidthThrottled = NO;
|
4624 |
|
shouldThrottleBandwithForWWANOnly = NO;
|
|
4646 |
shouldThrottleBandwidthForWWANOnly = NO;
|
4625 |
4647 |
[bandwidthThrottlingLock unlock];
|
4626 |
4648 |
}
|
4627 |
4649 |
}
|
... | ... | |
4629 |
4651 |
+ (void)throttleBandwidthForWWANUsingLimit:(unsigned long)limit
|
4630 |
4652 |
{
|
4631 |
4653 |
[bandwidthThrottlingLock lock];
|
4632 |
|
shouldThrottleBandwithForWWANOnly = YES;
|
|
4654 |
shouldThrottleBandwidthForWWANOnly = YES;
|
4633 |
4655 |
maxBandwidthPerSecond = limit;
|
4634 |
4656 |
[ASIHTTPRequest registerForNetworkReachabilityNotifications];
|
4635 |
4657 |
[bandwidthThrottlingLock unlock];
|
... | ... | |
4687 |
4709 |
@synchronized(self) {
|
4688 |
4710 |
return [[defaultCache retain] autorelease];
|
4689 |
4711 |
}
|
|
4712 |
return nil;
|
4690 |
4713 |
}
|
4691 |
4714 |
|
4692 |
4715 |
|
... | ... | |
4770 |
4793 |
BOOL runAlways = YES; // Introduced to cheat Static Analyzer
|
4771 |
4794 |
while (runAlways) {
|
4772 |
4795 |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
4773 |
|
CFRunLoopRun();
|
4774 |
|
[pool release];
|
|
4796 |
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
|
|
4797 |
[pool drain];
|
4775 |
4798 |
}
|
4776 |
4799 |
|
4777 |
4800 |
// Should never be called, but anyway
|
... | ... | |
4824 |
4847 |
return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
4825 |
4848 |
}
|
4826 |
4849 |
|
|
4850 |
+ (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
|
4851 |
{
|
|
4852 |
NSDictionary *responseHeaders = [request responseHeaders];
|
|
4853 |
|
|
4854 |
// If we weren't given a custom max-age, lets look for one in the response headers
|
|
4855 |
if (!maxAge) {
|
|
4856 |
NSString *cacheControl = [[responseHeaders objectForKey:@"Cache-Control"] lowercaseString];
|
|
4857 |
if (cacheControl) {
|
|
4858 |
NSScanner *scanner = [NSScanner scannerWithString:cacheControl];
|
|
4859 |
[scanner scanUpToString:@"max-age" intoString:NULL];
|
|
4860 |
if ([scanner scanString:@"max-age" intoString:NULL]) {
|
|
4861 |
[scanner scanString:@"=" intoString:NULL];
|
|
4862 |
[scanner scanDouble:&maxAge];
|
|
4863 |
}
|
|
4864 |
}
|
|
4865 |
}
|
|
4866 |
|
|
4867 |
// RFC 2612 says max-age must override any Expires header
|
|
4868 |
if (maxAge) {
|
|
4869 |
return [[NSDate date] addTimeInterval:maxAge];
|
|
4870 |
} else {
|
|
4871 |
NSString *expires = [responseHeaders objectForKey:@"Expires"];
|
|
4872 |
if (expires) {
|
|
4873 |
return [ASIHTTPRequest dateFromRFC1123String:expires];
|
|
4874 |
}
|
|
4875 |
}
|
|
4876 |
return nil;
|
|
4877 |
}
|
|
4878 |
|
4827 |
4879 |
// Based on hints from http://stackoverflow.com/questions/1850824/parsing-a-rfc-822-date-with-nsdateformatter
|
4828 |
4880 |
+ (NSDate *)dateFromRFC1123String:(NSString *)string
|
4829 |
4881 |
{
|
... | ... | |
4947 |
4999 |
|
4948 |
5000 |
@synthesize username;
|
4949 |
5001 |
@synthesize password;
|
4950 |
|
@synthesize userAgent;
|
|
5002 |
@synthesize userAgentString;
|
4951 |
5003 |
@synthesize domain;
|
4952 |
5004 |
@synthesize proxyUsername;
|
4953 |
5005 |
@synthesize proxyPassword;
|