Showing
5 changed files
with
80 additions
and
57 deletions
| @@ -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.2-33 2009-12-17"; | 24 | +NSString *ASIHTTPRequestVersion = @"v1.2-34 2009-12-17"; |
| 25 | 25 | ||
| 26 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; | 26 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; |
| 27 | 27 | ||
| @@ -731,9 +731,9 @@ static BOOL isiPhoneOS2; | @@ -731,9 +731,9 @@ static BOOL isiPhoneOS2; | ||
| 731 | 731 | ||
| 732 | // Are we gzipping the request body? | 732 | // Are we gzipping the request body? |
| 733 | if ([self compressedPostBodyFilePath] && [[NSFileManager defaultManager] fileExistsAtPath:[self compressedPostBodyFilePath]]) { | 733 | if ([self compressedPostBodyFilePath] && [[NSFileManager defaultManager] fileExistsAtPath:[self compressedPostBodyFilePath]]) { |
| 734 | - [self setPostBodyReadStream:[ASIInputStream inputStreamWithFileAtPath:[self compressedPostBodyFilePath]]]; | 734 | + [self setPostBodyReadStream:[ASIInputStream inputStreamWithFileAtPath:[self compressedPostBodyFilePath] request:self]]; |
| 735 | } else { | 735 | } else { |
| 736 | - [self setPostBodyReadStream:[ASIInputStream inputStreamWithFileAtPath:[self postBodyFilePath]]]; | 736 | + [self setPostBodyReadStream:[ASIInputStream inputStreamWithFileAtPath:[self postBodyFilePath] request:self]]; |
| 737 | } | 737 | } |
| 738 | readStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream]); | 738 | readStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream]); |
| 739 | } else { | 739 | } else { |
| @@ -741,9 +741,9 @@ static BOOL isiPhoneOS2; | @@ -741,9 +741,9 @@ static BOOL isiPhoneOS2; | ||
| 741 | // 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 nescessary | 741 | // 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 nescessary |
| 742 | if ([self postBody] && [[self postBody] length] > 0) { | 742 | if ([self postBody] && [[self postBody] length] > 0) { |
| 743 | if ([self shouldCompressRequestBody] && [self compressedPostBody]) { | 743 | if ([self shouldCompressRequestBody] && [self compressedPostBody]) { |
| 744 | - [self setPostBodyReadStream:[ASIInputStream inputStreamWithData:[self compressedPostBody]]]; | 744 | + [self setPostBodyReadStream:[ASIInputStream inputStreamWithData:[self compressedPostBody] request:self]]; |
| 745 | } else if ([self postBody]) { | 745 | } else if ([self postBody]) { |
| 746 | - [self setPostBodyReadStream:[ASIInputStream inputStreamWithData:[self postBody]]]; | 746 | + [self setPostBodyReadStream:[ASIInputStream inputStreamWithData:[self postBody] request:self]]; |
| 747 | } | 747 | } |
| 748 | readStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream]); | 748 | readStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream]); |
| 749 | 749 | ||
| @@ -917,7 +917,7 @@ static BOOL isiPhoneOS2; | @@ -917,7 +917,7 @@ static BOOL isiPhoneOS2; | ||
| 917 | [self performThrottling]; | 917 | [self performThrottling]; |
| 918 | 918 | ||
| 919 | // See if we need to timeout | 919 | // See if we need to timeout |
| 920 | - if (lastActivityTime && timeOutSeconds > 0 && [now timeIntervalSinceDate:lastActivityTime] > timeOutSeconds) { | 920 | + if (readStreamIsScheduled && lastActivityTime && timeOutSeconds > 0 && [now timeIntervalSinceDate:lastActivityTime] > timeOutSeconds) { |
| 921 | 921 | ||
| 922 | // Prevent timeouts before 128KB* has been sent when the size of data to upload is greater than 128KB* (*32KB on iPhone 3.0 SDK) | 922 | // Prevent timeouts before 128KB* has been sent when the size of data to upload is greater than 128KB* (*32KB on iPhone 3.0 SDK) |
| 923 | // This is to workaround the fact that kCFStreamPropertyHTTPRequestBytesWrittenCount is the amount written to the buffer, not the amount actually sent | 923 | // This is to workaround the fact that kCFStreamPropertyHTTPRequestBytesWrittenCount is the amount written to the buffer, not the amount actually sent |
| @@ -2965,6 +2965,9 @@ static BOOL isiPhoneOS2; | @@ -2965,6 +2965,9 @@ static BOOL isiPhoneOS2; | ||
| 2965 | #if DEBUG_THROTTLING | 2965 | #if DEBUG_THROTTLING |
| 2966 | NSLog(@"Waking up request %@",self); | 2966 | NSLog(@"Waking up request %@",self); |
| 2967 | #endif | 2967 | #endif |
| 2968 | + | ||
| 2969 | + // Reset the timeout | ||
| 2970 | + [self setLastActivityTime:[NSDate date]]; | ||
| 2968 | CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL}; | 2971 | CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL}; |
| 2969 | CFReadStreamSetClient(readStream, kNetworkEvents, ReadStreamClientCallBack, &ctxt); | 2972 | CFReadStreamSetClient(readStream, kNetworkEvents, ReadStreamClientCallBack, &ctxt); |
| 2970 | CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); | 2973 | CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); |
| @@ -2973,6 +2976,13 @@ static BOOL isiPhoneOS2; | @@ -2973,6 +2976,13 @@ static BOOL isiPhoneOS2; | ||
| 2973 | } | 2976 | } |
| 2974 | } | 2977 | } |
| 2975 | [bandwidthThrottlingLock unlock]; | 2978 | [bandwidthThrottlingLock unlock]; |
| 2979 | + } else if (!readStreamIsScheduled) { | ||
| 2980 | + // Reset the timeout | ||
| 2981 | + [self setLastActivityTime:[NSDate date]]; | ||
| 2982 | + CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL}; | ||
| 2983 | + CFReadStreamSetClient(readStream, kNetworkEvents, ReadStreamClientCallBack, &ctxt); | ||
| 2984 | + CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); | ||
| 2985 | + readStreamIsScheduled = YES; | ||
| 2976 | } | 2986 | } |
| 2977 | } | 2987 | } |
| 2978 | 2988 | ||
| @@ -3044,10 +3054,6 @@ static BOOL isiPhoneOS2; | @@ -3044,10 +3054,6 @@ static BOOL isiPhoneOS2; | ||
| 3044 | + (unsigned long)averageBandwidthUsedPerSecond | 3054 | + (unsigned long)averageBandwidthUsedPerSecond |
| 3045 | { | 3055 | { |
| 3046 | [bandwidthThrottlingLock lock]; | 3056 | [bandwidthThrottlingLock lock]; |
| 3047 | - | ||
| 3048 | - if (!bandwidthMeasurementDate || [bandwidthMeasurementDate timeIntervalSinceNow] < 0) { | ||
| 3049 | - [self recordBandwidthUsage]; | ||
| 3050 | - } | ||
| 3051 | unsigned long amount = averageBandwidthUsedPerSecond; | 3057 | unsigned long amount = averageBandwidthUsedPerSecond; |
| 3052 | [bandwidthThrottlingLock unlock]; | 3058 | [bandwidthThrottlingLock unlock]; |
| 3053 | return amount; | 3059 | return amount; |
| @@ -3063,11 +3069,11 @@ static BOOL isiPhoneOS2; | @@ -3063,11 +3069,11 @@ static BOOL isiPhoneOS2; | ||
| 3063 | } | 3069 | } |
| 3064 | 3070 | ||
| 3065 | // Are we performing bandwidth throttling? | 3071 | // Are we performing bandwidth throttling? |
| 3066 | -#if TARGET_OS_IPHONE | 3072 | + #if TARGET_OS_IPHONE |
| 3067 | if (isBandwidthThrottled || (!shouldThrottleBandwithForWWANOnly && (maxBandwidthPerSecond))) { | 3073 | if (isBandwidthThrottled || (!shouldThrottleBandwithForWWANOnly && (maxBandwidthPerSecond))) { |
| 3068 | -#else | 3074 | + #else |
| 3069 | if (maxBandwidthPerSecond) { | 3075 | if (maxBandwidthPerSecond) { |
| 3070 | -#endif | 3076 | + #endif |
| 3071 | // How much data can we still send or receive this second? | 3077 | // How much data can we still send or receive this second? |
| 3072 | long long bytesRemaining = (long long)maxBandwidthPerSecond - (long long)bandwidthUsedInLastSecond; | 3078 | long long bytesRemaining = (long long)maxBandwidthPerSecond - (long long)bandwidthUsedInLastSecond; |
| 3073 | 3079 | ||
| @@ -3083,6 +3089,32 @@ static BOOL isiPhoneOS2; | @@ -3083,6 +3089,32 @@ static BOOL isiPhoneOS2; | ||
| 3083 | [bandwidthThrottlingLock unlock]; | 3089 | [bandwidthThrottlingLock unlock]; |
| 3084 | } | 3090 | } |
| 3085 | 3091 | ||
| 3092 | + | ||
| 3093 | + | ||
| 3094 | ++ (unsigned long)maxUploadReadLength | ||
| 3095 | +{ | ||
| 3096 | + | ||
| 3097 | + [bandwidthThrottlingLock lock]; | ||
| 3098 | + | ||
| 3099 | + // We'll split our bandwidth allowance into 4 (which is the default for an ASINetworkQueue's max concurrent operations count) to give all running requests a fighting chance of reading data this cycle | ||
| 3100 | + long long toRead = maxBandwidthPerSecond/4; | ||
| 3101 | + if (maxBandwidthPerSecond > 0 && (bandwidthUsedInLastSecond + toRead > maxBandwidthPerSecond)) { | ||
| 3102 | + toRead = (long long)maxBandwidthPerSecond-(long long)bandwidthUsedInLastSecond; | ||
| 3103 | + if (toRead < 0) { | ||
| 3104 | + toRead = 0; | ||
| 3105 | + } | ||
| 3106 | + } | ||
| 3107 | + | ||
| 3108 | + if (toRead == 0 || !bandwidthMeasurementDate || [bandwidthMeasurementDate timeIntervalSinceNow] < -0) { | ||
| 3109 | + [throttleWakeUpTime release]; | ||
| 3110 | + throttleWakeUpTime = [bandwidthMeasurementDate retain]; | ||
| 3111 | + } | ||
| 3112 | + [bandwidthThrottlingLock unlock]; | ||
| 3113 | + return (unsigned long)toRead; | ||
| 3114 | +} | ||
| 3115 | + | ||
| 3116 | + | ||
| 3117 | + | ||
| 3086 | #if TARGET_OS_IPHONE | 3118 | #if TARGET_OS_IPHONE |
| 3087 | + (void)setShouldThrottleBandwidthForWWAN:(BOOL)throttle | 3119 | + (void)setShouldThrottleBandwidthForWWAN:(BOOL)throttle |
| 3088 | { | 3120 | { |
| @@ -3145,31 +3177,6 @@ static BOOL isiPhoneOS2; | @@ -3145,31 +3177,6 @@ static BOOL isiPhoneOS2; | ||
| 3145 | #endif | 3177 | #endif |
| 3146 | 3178 | ||
| 3147 | 3179 | ||
| 3148 | - | ||
| 3149 | -+ (unsigned long)maxUploadReadLength | ||
| 3150 | -{ | ||
| 3151 | - | ||
| 3152 | - [bandwidthThrottlingLock lock]; | ||
| 3153 | - | ||
| 3154 | - // We'll split our bandwidth allowance into 4 (which is the default for an ASINetworkQueue's max concurrent operations count) to give all running requests a fighting chance of reading data this cycle | ||
| 3155 | - unsigned long toRead = maxBandwidthPerSecond/4; | ||
| 3156 | - if (maxBandwidthPerSecond > 0 && (bandwidthUsedInLastSecond + toRead > maxBandwidthPerSecond)) { | ||
| 3157 | - toRead = maxBandwidthPerSecond-bandwidthUsedInLastSecond; | ||
| 3158 | - if (toRead < 0) { | ||
| 3159 | - toRead = 0; | ||
| 3160 | - } | ||
| 3161 | - } | ||
| 3162 | - | ||
| 3163 | - if (toRead == 0 || !bandwidthMeasurementDate || [bandwidthMeasurementDate timeIntervalSinceNow] < -0) { | ||
| 3164 | - [throttleWakeUpTime release]; | ||
| 3165 | - throttleWakeUpTime = [bandwidthMeasurementDate retain]; | ||
| 3166 | - [self recordBandwidthUsage]; | ||
| 3167 | - } | ||
| 3168 | - [bandwidthThrottlingLock unlock]; | ||
| 3169 | - return toRead; | ||
| 3170 | -} | ||
| 3171 | - | ||
| 3172 | - | ||
| 3173 | #pragma mark miscellany | 3180 | #pragma mark miscellany |
| 3174 | 3181 | ||
| 3175 | + (BOOL)isiPhoneOS2 | 3182 | + (BOOL)isiPhoneOS2 |
| @@ -7,6 +7,27 @@ | @@ -7,6 +7,27 @@ | ||
| 7 | // | 7 | // |
| 8 | 8 | ||
| 9 | 9 | ||
| 10 | +// ====== | ||
| 11 | +// Debug output configuration options | ||
| 12 | +// ====== | ||
| 13 | + | ||
| 14 | +// When set to 1 ASIHTTPRequests will print information about what a request is doing | ||
| 15 | +#define DEBUG_REQUEST_STATUS 0 | ||
| 16 | + | ||
| 17 | +// When set to 1, ASIFormDataRequests will print information about the request body to the console | ||
| 18 | +#define DEBUG_FORM_DATA_REQUEST 0 | ||
| 19 | + | ||
| 20 | +// When set to 1, ASIHTTPRequests will print information about bandwidth throttling to the console | ||
| 21 | +#define DEBUG_THROTTLING 0 | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +// ====== | ||
| 25 | +// Reachability API (iPhone only) | ||
| 26 | +// ====== | ||
| 27 | + | ||
| 28 | +/* | ||
| 29 | +Turn off any features you don't need for a speed boost | ||
| 30 | +*/ | ||
| 10 | 31 | ||
| 11 | /* | 32 | /* |
| 12 | ASIHTTPRequest uses Apple's Reachability class (http://developer.apple.com/iphone/library/samplecode/Reachability/) to turn bandwidth throttling on and off automatically when shouldThrottleBandwidthForWWAN is set to YES on iPhone OS | 33 | ASIHTTPRequest uses Apple's Reachability class (http://developer.apple.com/iphone/library/samplecode/Reachability/) to turn bandwidth throttling on and off automatically when shouldThrottleBandwidthForWWAN is set to YES on iPhone OS |
| @@ -25,16 +46,3 @@ This config option is not used for apps targeting Mac OS X | @@ -25,16 +46,3 @@ This config option is not used for apps targeting Mac OS X | ||
| 25 | #define REACHABILITY_20_API 0 | 46 | #define REACHABILITY_20_API 0 |
| 26 | 47 | ||
| 27 | 48 | ||
| 28 | -/* | ||
| 29 | -Debug output configuration options | ||
| 30 | -*/ | ||
| 31 | - | ||
| 32 | -// When set to 1 ASIHTTPRequests will print information about what a request is doing | ||
| 33 | -#define DEBUG_REQUEST_STATUS 0 | ||
| 34 | - | ||
| 35 | -// When set to 1, ASIFormDataRequests will print information about the request body to the console | ||
| 36 | -#define DEBUG_FORM_DATA_REQUEST 0 | ||
| 37 | - | ||
| 38 | -// When set to 1, ASIHTTPRequests will print information about bandwidth throttling to the console | ||
| 39 | -#define DEBUG_THROTTLING 0 | ||
| 40 | - |
| @@ -8,15 +8,19 @@ | @@ -8,15 +8,19 @@ | ||
| 8 | 8 | ||
| 9 | #import <Foundation/Foundation.h> | 9 | #import <Foundation/Foundation.h> |
| 10 | 10 | ||
| 11 | +@class ASIHTTPRequest; | ||
| 12 | + | ||
| 11 | // This is a wrapper for NSInputStream that pretends to be an NSInputStream itself | 13 | // This is a wrapper for NSInputStream that pretends to be an NSInputStream itself |
| 12 | // Subclassing NSInputStream seems to be tricky, and may involve overriding undocumented methods, so we'll cheat instead. | 14 | // Subclassing NSInputStream seems to be tricky, and may involve overriding undocumented methods, so we'll cheat instead. |
| 13 | // It is used by ASIHTTPRequest whenever we have a request body, and handles measuring and throttling the bandwidth used for uploading | 15 | // It is used by ASIHTTPRequest whenever we have a request body, and handles measuring and throttling the bandwidth used for uploading |
| 14 | 16 | ||
| 15 | @interface ASIInputStream : NSObject { | 17 | @interface ASIInputStream : NSObject { |
| 16 | NSInputStream *stream; | 18 | NSInputStream *stream; |
| 19 | + ASIHTTPRequest *request; | ||
| 17 | } | 20 | } |
| 18 | -+ (id)inputStreamWithFileAtPath:(NSString *)path; | 21 | ++ (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)request; |
| 19 | -+ (id)inputStreamWithData:(NSData *)data; | 22 | ++ (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)request; |
| 20 | 23 | ||
| 21 | -@property (retain) NSInputStream *stream; | 24 | +@property (retain, nonatomic) NSInputStream *stream; |
| 25 | +@property (assign, nonatomic) ASIHTTPRequest *request; | ||
| 22 | @end | 26 | @end |
| @@ -21,16 +21,18 @@ static NSLock *readLock = nil; | @@ -21,16 +21,18 @@ static NSLock *readLock = nil; | ||
| 21 | } | 21 | } |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | -+ (id)inputStreamWithFileAtPath:(NSString *)path | 24 | ++ (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)request |
| 25 | { | 25 | { |
| 26 | ASIInputStream *stream = [[[self alloc] init] autorelease]; | 26 | ASIInputStream *stream = [[[self alloc] init] autorelease]; |
| 27 | + [stream setRequest:request]; | ||
| 27 | [stream setStream:[NSInputStream inputStreamWithFileAtPath:path]]; | 28 | [stream setStream:[NSInputStream inputStreamWithFileAtPath:path]]; |
| 28 | return stream; | 29 | return stream; |
| 29 | } | 30 | } |
| 30 | 31 | ||
| 31 | -+ (id)inputStreamWithData:(NSData *)data | 32 | ++ (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)request |
| 32 | { | 33 | { |
| 33 | ASIInputStream *stream = [[[self alloc] init] autorelease]; | 34 | ASIInputStream *stream = [[[self alloc] init] autorelease]; |
| 35 | + [stream setRequest:request]; | ||
| 34 | [stream setStream:[NSInputStream inputStreamWithData:data]]; | 36 | [stream setStream:[NSInputStream inputStreamWithData:data]]; |
| 35 | return stream; | 37 | return stream; |
| 36 | } | 38 | } |
| @@ -54,6 +56,7 @@ static NSLock *readLock = nil; | @@ -54,6 +56,7 @@ static NSLock *readLock = nil; | ||
| 54 | } else if (toRead == 0) { | 56 | } else if (toRead == 0) { |
| 55 | toRead = 1; | 57 | toRead = 1; |
| 56 | } | 58 | } |
| 59 | + [request performThrottling]; | ||
| 57 | } | 60 | } |
| 58 | [ASIHTTPRequest incrementBandwidthUsedInLastSecond:toRead]; | 61 | [ASIHTTPRequest incrementBandwidthUsedInLastSecond:toRead]; |
| 59 | [readLock unlock]; | 62 | [readLock unlock]; |
| @@ -73,4 +76,5 @@ static NSLock *readLock = nil; | @@ -73,4 +76,5 @@ static NSLock *readLock = nil; | ||
| 73 | } | 76 | } |
| 74 | 77 | ||
| 75 | @synthesize stream; | 78 | @synthesize stream; |
| 79 | +@synthesize request; | ||
| 76 | @end | 80 | @end |
| @@ -192,7 +192,7 @@ | @@ -192,7 +192,7 @@ | ||
| 192 | [request setDidFinishSelector:@selector(topSecretFetchComplete:)]; | 192 | [request setDidFinishSelector:@selector(topSecretFetchComplete:)]; |
| 193 | [request setDelegate:self]; | 193 | [request setDelegate:self]; |
| 194 | [request setUseKeychainPersistance:[keychainCheckbox state]]; | 194 | [request setUseKeychainPersistance:[keychainCheckbox state]]; |
| 195 | - [request startAsynchronous]; | 195 | + [request start]; |
| 196 | 196 | ||
| 197 | } | 197 | } |
| 198 | 198 |
-
Please register or login to post a comment