Showing
2 changed files
with
95 additions
and
4 deletions
@@ -31,8 +31,14 @@ typedef enum _ASINetworkErrorType { | @@ -31,8 +31,14 @@ typedef enum _ASINetworkErrorType { | ||
31 | 31 | ||
32 | } ASINetworkErrorType; | 32 | } ASINetworkErrorType; |
33 | 33 | ||
34 | +// The error domain that all errors generated by ASIHTTPRequest use | ||
34 | extern NSString* const NetworkRequestErrorDomain; | 35 | extern NSString* const NetworkRequestErrorDomain; |
35 | 36 | ||
37 | +// You can use this number to throttle upload and download bandwidth in iPhone OS apps send or receive a large amount of data | ||
38 | +// This may help apps that might otherwise be rejected for inclusion into the app store for using excessive bandwidth | ||
39 | +// This number is not official, as far as I know there is no officially documented bandwidth limit | ||
40 | +extern unsigned long const ASIWWANBandwidthThrottleAmount; | ||
41 | + | ||
36 | @interface ASIHTTPRequest : NSOperation { | 42 | @interface ASIHTTPRequest : NSOperation { |
37 | 43 | ||
38 | // The url for this operation, should include GET params in the query string where appropriate | 44 | // The url for this operation, should include GET params in the query string where appropriate |
@@ -449,6 +455,15 @@ extern NSString* const NetworkRequestErrorDomain; | @@ -449,6 +455,15 @@ extern NSString* const NetworkRequestErrorDomain; | ||
449 | // Only works on Mac OS, will always return 'application/octet-stream' on iPhone | 455 | // Only works on Mac OS, will always return 'application/octet-stream' on iPhone |
450 | + (NSString *)mimeTypeForFileAtPath:(NSString *)path; | 456 | + (NSString *)mimeTypeForFileAtPath:(NSString *)path; |
451 | 457 | ||
458 | +#pragma mark bandwidth throttling | ||
459 | + | ||
460 | +// The maximum number of bytes ALL requests can send / receive in a second | ||
461 | +// This is a rough figure. The actual amount used may be slightly more | ||
462 | ++ (unsigned long)maxBandwidthPerSecond; | ||
463 | ++ (void)setMaxBandwidthPerSecond:(unsigned long)bytes; | ||
464 | + | ||
465 | + | ||
466 | + | ||
452 | @property (retain) NSString *username; | 467 | @property (retain) NSString *username; |
453 | @property (retain) NSString *password; | 468 | @property (retain) NSString *password; |
454 | @property (retain) NSString *domain; | 469 | @property (retain) NSString *domain; |
@@ -48,12 +48,29 @@ static NSError *ASIAuthenticationError; | @@ -48,12 +48,29 @@ static NSError *ASIAuthenticationError; | ||
48 | static NSError *ASIUnableToCreateRequestError; | 48 | static NSError *ASIUnableToCreateRequestError; |
49 | static NSError *ASITooMuchRedirectionError; | 49 | static NSError *ASITooMuchRedirectionError; |
50 | 50 | ||
51 | +// Used for throttling bandwidth | ||
52 | +// I am assuming you don't have a connection capable of more than 4GB/second? If so, why are you reading this? Aren't you supposed to be backing up the Internet?! | ||
53 | +static unsigned long bandwidthUsedInLastSecond = 0; | ||
54 | + | ||
55 | +// A date one second in the future from the time it was created | ||
56 | +static NSDate *bandwidthThrottlingMeasurementDate = nil; | ||
57 | + | ||
58 | +// Since throttling variables are shared among all requests, we'll use a lock to mediate access | ||
59 | +static NSLock *bandwidthThrottlingLock = nil; | ||
60 | + | ||
61 | +// the maximum number of bytes that can be transmitted in one second | ||
62 | +static unsigned long maxBandwidthPerSecond = 0; | ||
63 | + | ||
64 | +// A default figure for throttling bandwidth on mobile devices | ||
65 | +unsigned long const ASIWWANBandwidthThrottleAmount = 14800; | ||
51 | 66 | ||
52 | // Private stuff | 67 | // Private stuff |
53 | @interface ASIHTTPRequest () | 68 | @interface ASIHTTPRequest () |
54 | 69 | ||
55 | - (BOOL)askDelegateForCredentials; | 70 | - (BOOL)askDelegateForCredentials; |
56 | - (BOOL)askDelegateForProxyCredentials; | 71 | - (BOOL)askDelegateForProxyCredentials; |
72 | ++ (void)incrementBandwidthUsedInLastSecond:(unsigned long)bytes; | ||
73 | ++ (void)throttleBandwidth; | ||
57 | 74 | ||
58 | @property (assign) BOOL complete; | 75 | @property (assign) BOOL complete; |
59 | @property (retain) NSDictionary *responseHeaders; | 76 | @property (retain) NSDictionary *responseHeaders; |
@@ -97,6 +114,7 @@ static NSError *ASITooMuchRedirectionError; | @@ -97,6 +114,7 @@ static NSError *ASITooMuchRedirectionError; | ||
97 | { | 114 | { |
98 | if (self == [ASIHTTPRequest class]) { | 115 | if (self == [ASIHTTPRequest class]) { |
99 | progressLock = [[NSRecursiveLock alloc] init]; | 116 | progressLock = [[NSRecursiveLock alloc] init]; |
117 | + bandwidthThrottlingLock = [[NSLock alloc] init]; | ||
100 | ASIRequestTimedOutError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIRequestTimedOutErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request timed out",NSLocalizedDescriptionKey,nil]] retain]; | 118 | ASIRequestTimedOutError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIRequestTimedOutErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request timed out",NSLocalizedDescriptionKey,nil]] retain]; |
101 | ASIAuthenticationError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIAuthenticationErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Authentication needed",NSLocalizedDescriptionKey,nil]] retain]; | 119 | ASIAuthenticationError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIAuthenticationErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Authentication needed",NSLocalizedDescriptionKey,nil]] retain]; |
102 | ASIRequestCancelledError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIRequestCancelledErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request was cancelled",NSLocalizedDescriptionKey,nil]] retain]; | 120 | ASIRequestCancelledError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIRequestCancelledErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request was cancelled",NSLocalizedDescriptionKey,nil]] retain]; |
@@ -618,7 +636,6 @@ static NSError *ASITooMuchRedirectionError; | @@ -618,7 +636,6 @@ static NSError *ASITooMuchRedirectionError; | ||
618 | [self startRequest]; | 636 | [self startRequest]; |
619 | 637 | ||
620 | 638 | ||
621 | - | ||
622 | // Wait for the request to finish | 639 | // Wait for the request to finish |
623 | while (!complete) { | 640 | while (!complete) { |
624 | 641 | ||
@@ -665,6 +682,11 @@ static NSError *ASITooMuchRedirectionError; | @@ -665,6 +682,11 @@ static NSError *ASITooMuchRedirectionError; | ||
665 | 682 | ||
666 | // Find out if we've sent any more data than last time, and reset the timeout if so | 683 | // Find out if we've sent any more data than last time, and reset the timeout if so |
667 | if (totalBytesSent > lastBytesSent) { | 684 | if (totalBytesSent > lastBytesSent) { |
685 | + | ||
686 | + // For bandwidth throttling | ||
687 | + if ([ASIHTTPRequest maxBandwidthPerSecond] > 0) { | ||
688 | + [ASIHTTPRequest incrementBandwidthUsedInLastSecond:totalBytesSent-maxBandwidthPerSecond]; | ||
689 | + } | ||
668 | [self setLastActivityTime:[NSDate date]]; | 690 | [self setLastActivityTime:[NSDate date]]; |
669 | [self setLastBytesSent:totalBytesSent]; | 691 | [self setLastBytesSent:totalBytesSent]; |
670 | } | 692 | } |
@@ -676,7 +698,8 @@ static NSError *ASITooMuchRedirectionError; | @@ -676,7 +698,8 @@ static NSError *ASITooMuchRedirectionError; | ||
676 | 698 | ||
677 | [self updateProgressIndicators]; | 699 | [self updateProgressIndicators]; |
678 | 700 | ||
679 | - | 701 | + // Throttle bandwidth if nescessary |
702 | + [ASIHTTPRequest throttleBandwidth]; | ||
680 | 703 | ||
681 | // This thread should wait for 1/4 second for the stream to do something. We'll stop early if it does. | 704 | // This thread should wait for 1/4 second for the stream to do something. We'll stop early if it does. |
682 | CFRunLoopRunInMode(ASIHTTPRequestRunMode,0.25,YES); | 705 | CFRunLoopRunInMode(ASIHTTPRequestRunMode,0.25,YES); |
@@ -1630,6 +1653,11 @@ static NSError *ASITooMuchRedirectionError; | @@ -1630,6 +1653,11 @@ static NSError *ASITooMuchRedirectionError; | ||
1630 | [self setTotalBytesRead:[self totalBytesRead]+bytesRead]; | 1653 | [self setTotalBytesRead:[self totalBytesRead]+bytesRead]; |
1631 | [self setLastActivityTime:[NSDate date]]; | 1654 | [self setLastActivityTime:[NSDate date]]; |
1632 | 1655 | ||
1656 | + // For bandwidth throttling | ||
1657 | + if ([ASIHTTPRequest maxBandwidthPerSecond] > 0) { | ||
1658 | + [ASIHTTPRequest incrementBandwidthUsedInLastSecond:bytesRead]; | ||
1659 | + } | ||
1660 | + | ||
1633 | // Are we downloading to a file? | 1661 | // Are we downloading to a file? |
1634 | if ([self downloadDestinationPath]) { | 1662 | if ([self downloadDestinationPath]) { |
1635 | if (![self fileDownloadOutputStream]) { | 1663 | if (![self fileDownloadOutputStream]) { |
@@ -2219,7 +2247,7 @@ static NSError *ASITooMuchRedirectionError; | @@ -2219,7 +2247,7 @@ static NSError *ASITooMuchRedirectionError; | ||
2219 | return proxies; | 2247 | return proxies; |
2220 | } | 2248 | } |
2221 | 2249 | ||
2222 | -#pragma mark Helper functions | 2250 | +#pragma mark mime-type detection |
2223 | 2251 | ||
2224 | + (NSString *)mimeTypeForFileAtPath:(NSString *)path | 2252 | + (NSString *)mimeTypeForFileAtPath:(NSString *)path |
2225 | { | 2253 | { |
@@ -2251,6 +2279,55 @@ static NSError *ASITooMuchRedirectionError; | @@ -2251,6 +2279,55 @@ static NSError *ASITooMuchRedirectionError; | ||
2251 | #endif | 2279 | #endif |
2252 | } | 2280 | } |
2253 | 2281 | ||
2282 | +#pragma mark bandwidth throttling | ||
2283 | + | ||
2284 | ++ (unsigned long)maxBandwidthPerSecond | ||
2285 | +{ | ||
2286 | + [bandwidthThrottlingLock lock]; | ||
2287 | + unsigned long amount = maxBandwidthPerSecond; | ||
2288 | + [bandwidthThrottlingLock unlock]; | ||
2289 | + return amount; | ||
2290 | +} | ||
2291 | + | ||
2292 | ++ (void)setMaxBandwidthPerSecond:(unsigned long)bytes | ||
2293 | +{ | ||
2294 | + [bandwidthThrottlingLock lock]; | ||
2295 | + maxBandwidthPerSecond = bytes; | ||
2296 | + [bandwidthThrottlingLock unlock]; | ||
2297 | +} | ||
2298 | + | ||
2299 | ++ (void)incrementBandwidthUsedInLastSecond:(unsigned long)bytes | ||
2300 | +{ | ||
2301 | + [bandwidthThrottlingLock lock]; | ||
2302 | + bandwidthUsedInLastSecond += bytes; | ||
2303 | + [bandwidthThrottlingLock unlock]; | ||
2304 | +} | ||
2305 | + | ||
2306 | ++ (void)throttleBandwidth | ||
2307 | +{ | ||
2308 | + // Other requests may have to wait for this lock if we're sleeping, but this is fine, since we already know they shouldn't be sending or receiving data | ||
2309 | + [bandwidthThrottlingLock lock]; | ||
2310 | + | ||
2311 | + // Are we performing bandwidth throttling? | ||
2312 | + if (maxBandwidthPerSecond > 0) { | ||
2313 | + if (!bandwidthThrottlingMeasurementDate) { | ||
2314 | + bandwidthThrottlingMeasurementDate = [NSDate dateWithTimeIntervalSinceNow:1]; | ||
2315 | + } | ||
2316 | + | ||
2317 | + // How much data can we still send or receive this second? | ||
2318 | + long long bytesRemaining = maxBandwidthPerSecond - bandwidthUsedInLastSecond; | ||
2319 | + | ||
2320 | + // Have we used up our allowance? | ||
2321 | + if (bytesRemaining < 0) { | ||
2322 | + | ||
2323 | + // Yes, put this request to sleep until a second is up | ||
2324 | + [NSThread sleepUntilDate:bandwidthThrottlingMeasurementDate]; | ||
2325 | + bandwidthThrottlingMeasurementDate = [NSDate dateWithTimeIntervalSinceNow:1]; | ||
2326 | + } | ||
2327 | + } | ||
2328 | + [bandwidthThrottlingLock unlock]; | ||
2329 | +} | ||
2330 | + | ||
2254 | 2331 | ||
2255 | 2332 | ||
2256 | @synthesize username; | 2333 | @synthesize username; |
@@ -2324,7 +2401,6 @@ static NSError *ASITooMuchRedirectionError; | @@ -2324,7 +2401,6 @@ static NSError *ASITooMuchRedirectionError; | ||
2324 | @synthesize authenticationLock; | 2401 | @synthesize authenticationLock; |
2325 | @synthesize needsProxyAuthentication; | 2402 | @synthesize needsProxyAuthentication; |
2326 | @synthesize proxyCredentials; | 2403 | @synthesize proxyCredentials; |
2327 | - | ||
2328 | @synthesize proxyHost; | 2404 | @synthesize proxyHost; |
2329 | @synthesize proxyPort; | 2405 | @synthesize proxyPort; |
2330 | @synthesize PACurl; | 2406 | @synthesize PACurl; |
-
Please register or login to post a comment