| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import <Cronet/Cronet.h> | 5 #import <Cronet/Cronet.h> |
| 6 #import <Foundation/Foundation.h> | 6 #import <Foundation/Foundation.h> |
| 7 | 7 |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 | 21 |
| 22 #include "url/gurl.h" | 22 #include "url/gurl.h" |
| 23 | 23 |
| 24 @interface TestDelegate : NSObject<NSURLSessionDataDelegate, | 24 @interface TestDelegate : NSObject<NSURLSessionDataDelegate, |
| 25 NSURLSessionDelegate, | 25 NSURLSessionDelegate, |
| 26 NSURLSessionTaskDelegate> | 26 NSURLSessionTaskDelegate> |
| 27 | 27 |
| 28 // Completion semaphore for this TestDelegate. When the request this delegate is | 28 // Completion semaphore for this TestDelegate. When the request this delegate is |
| 29 // attached to finishes (either successfully or with an error), this delegate | 29 // attached to finishes (either successfully or with an error), this delegate |
| 30 // signals this semaphore. | 30 // signals this semaphore. |
| 31 @property(assign, nonatomic) dispatch_semaphore_t semaphore; | 31 @property(retain, atomic) dispatch_semaphore_t semaphore; |
| 32 | |
| 33 // Body of response received by the request this delegate is attached to. | |
| 34 @property(retain, nonatomic) NSString* responseBody; | |
| 35 | 32 |
| 36 // Error the request this delegate is attached to failed with, if any. | 33 // Error the request this delegate is attached to failed with, if any. |
| 37 @property(retain, nonatomic) NSError* error; | 34 @property(retain, atomic) NSError* error; |
| 38 | 35 |
| 39 @end | 36 @end |
| 40 | 37 |
| 41 @implementation TestDelegate | 38 @implementation TestDelegate |
| 42 @synthesize semaphore = _semaphore; | 39 @synthesize semaphore = _semaphore; |
| 43 @synthesize responseBody = _responseBody; | |
| 44 @synthesize error = _error; | 40 @synthesize error = _error; |
| 45 | 41 |
| 42 NSMutableArray<NSData*>* _responseData; |
| 43 |
| 46 - (id)init { | 44 - (id)init { |
| 47 if (self = [super init]) { | 45 if (self = [super init]) { |
| 48 _semaphore = dispatch_semaphore_create(0); | 46 _semaphore = dispatch_semaphore_create(0); |
| 49 } | 47 } |
| 50 return self; | 48 return self; |
| 51 } | 49 } |
| 52 | 50 |
| 53 - (void)dealloc { | 51 - (void)dealloc { |
| 54 dispatch_release(_semaphore); | 52 // dispatch_release(_semaphore); |
| 55 [_error release]; | 53 // [_error release]; |
| 54 _semaphore = nil; |
| 56 _error = nil; | 55 _error = nil; |
| 57 [super dealloc]; | 56 // [super dealloc]; |
| 58 } | 57 } |
| 59 | 58 |
| 60 - (void)reset { | 59 - (void)reset { |
| 61 _responseBody = nil; | 60 // [_responseData dealloc]; |
| 61 _responseData = nil; |
| 62 _error = nil; | 62 _error = nil; |
| 63 } | 63 } |
| 64 | 64 |
| 65 - (NSString*)responseBody { |
| 66 if (_responseData == nil) { |
| 67 return nil; |
| 68 } |
| 69 NSMutableString* body = [NSMutableString string]; |
| 70 for (NSData* data in _responseData) { |
| 71 [body appendString:[[NSString alloc] initWithData:data |
| 72 encoding:NSUTF8StringEncoding]]; |
| 73 } |
| 74 VLOG(3) << "responseBody size:" << [body length] |
| 75 << " chunks:" << [_responseData count]; |
| 76 return body; |
| 77 } |
| 78 |
| 65 - (void)URLSession:(NSURLSession*)session | 79 - (void)URLSession:(NSURLSession*)session |
| 66 didBecomeInvalidWithError:(NSError*)error { | 80 didBecomeInvalidWithError:(NSError*)error { |
| 67 } | 81 } |
| 68 | 82 |
| 69 - (void)URLSession:(NSURLSession*)session | 83 - (void)URLSession:(NSURLSession*)session |
| 70 task:(NSURLSessionTask*)task | 84 task:(NSURLSessionTask*)task |
| 71 didCompleteWithError:(NSError*)error { | 85 didCompleteWithError:(NSError*)error { |
| 72 [self setError:error]; | 86 [self setError:error]; |
| 73 dispatch_semaphore_signal(_semaphore); | 87 dispatch_semaphore_signal(_semaphore); |
| 74 } | 88 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 86 dataTask:(NSURLSessionDataTask*)dataTask | 100 dataTask:(NSURLSessionDataTask*)dataTask |
| 87 didReceiveResponse:(NSURLResponse*)response | 101 didReceiveResponse:(NSURLResponse*)response |
| 88 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition)) | 102 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition)) |
| 89 completionHandler { | 103 completionHandler { |
| 90 completionHandler(NSURLSessionResponseAllow); | 104 completionHandler(NSURLSessionResponseAllow); |
| 91 } | 105 } |
| 92 | 106 |
| 93 - (void)URLSession:(NSURLSession*)session | 107 - (void)URLSession:(NSURLSession*)session |
| 94 dataTask:(NSURLSessionDataTask*)dataTask | 108 dataTask:(NSURLSessionDataTask*)dataTask |
| 95 didReceiveData:(NSData*)data { | 109 didReceiveData:(NSData*)data { |
| 96 NSString* stringData = | 110 if (_responseData == nil) { |
| 97 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | 111 _responseData = [[NSMutableArray alloc] init]; |
| 98 if (_responseBody == nil) { | |
| 99 _responseBody = stringData; | |
| 100 } else { | |
| 101 _responseBody = [_responseBody stringByAppendingString:stringData]; | |
| 102 } | 112 } |
| 113 [_responseData addObject:data]; |
| 103 } | 114 } |
| 104 | 115 |
| 105 - (void)URLSession:(NSURLSession*)session | 116 - (void)URLSession:(NSURLSession*)session |
| 106 dataTask:(NSURLSessionDataTask*)dataTask | 117 dataTask:(NSURLSessionDataTask*)dataTask |
| 107 willCacheResponse:(NSCachedURLResponse*)proposedResponse | 118 willCacheResponse:(NSCachedURLResponse*)proposedResponse |
| 108 completionHandler: | 119 completionHandler: |
| 109 (void (^)(NSCachedURLResponse* cachedResponse))completionHandler { | 120 (void (^)(NSCachedURLResponse* cachedResponse))completionHandler { |
| 110 completionHandler(proposedResponse); | 121 completionHandler(proposedResponse); |
| 111 } | 122 } |
| 112 | 123 |
| 113 @end | 124 @end |
| 114 | 125 |
| 115 namespace cronet { | 126 namespace cronet { |
| 116 // base::TimeDelta would normally be ideal for this but it does not support | |
| 117 // nanosecond resolution. | |
| 118 static const int64_t ns_in_second = 1000000000LL; | |
| 119 const char kUserAgent[] = "CronetTest/1.0.0.0"; | 127 const char kUserAgent[] = "CronetTest/1.0.0.0"; |
| 120 | 128 |
| 121 class HttpTest : public ::testing::Test { | 129 class HttpTest : public ::testing::Test { |
| 122 protected: | 130 protected: |
| 123 HttpTest() {} | 131 HttpTest() {} |
| 124 ~HttpTest() override {} | 132 ~HttpTest() override {} |
| 125 | 133 |
| 126 void SetUp() override { | 134 void SetUp() override { |
| 127 grpc_support::StartQuicTestServer(); | 135 grpc_support::StartQuicTestServer(); |
| 128 TestServer::Start(); | 136 TestServer::Start(); |
| 129 | 137 |
| 130 [Cronet setRequestFilterBlock:^(NSURLRequest* request) { | 138 [Cronet setRequestFilterBlock:^(NSURLRequest* request) { |
| 131 return YES; | 139 return YES; |
| 132 }]; | 140 }]; |
| 133 StartCronetIfNecessary(grpc_support::GetQuicTestServerPort()); | 141 StartCronetIfNecessary(grpc_support::GetQuicTestServerPort()); |
| 134 [Cronet registerHttpProtocolHandler]; | 142 [Cronet registerHttpProtocolHandler]; |
| 135 NSURLSessionConfiguration* config = | 143 NSURLSessionConfiguration* config = |
| 136 [NSURLSessionConfiguration ephemeralSessionConfiguration]; | 144 [NSURLSessionConfiguration ephemeralSessionConfiguration]; |
| 137 [Cronet installIntoSessionConfiguration:config]; | 145 [Cronet installIntoSessionConfiguration:config]; |
| 138 delegate_.reset([[TestDelegate alloc] init]); | 146 delegate_.reset([[TestDelegate alloc] init]); |
| 139 NSURLSession* session = [NSURLSession sessionWithConfiguration:config | 147 NSURLSession* session = [NSURLSession sessionWithConfiguration:config |
| 140 delegate:delegate_ | 148 delegate:delegate_ |
| 141 delegateQueue:nil]; | 149 delegateQueue:nil]; |
| 142 // Take a reference to the session and store it so it doesn't get | 150 // Take a reference to the session and store it so it doesn't get |
| 143 // deallocated until this object does. | 151 // deallocated until this object does. |
| 144 session_.reset([session retain]); | 152 //session_.reset([session retain]); |
| 153 session_.reset(session); |
| 145 } | 154 } |
| 146 | 155 |
| 147 void TearDown() override { | 156 void TearDown() override { |
| 148 grpc_support::ShutdownQuicTestServer(); | 157 grpc_support::ShutdownQuicTestServer(); |
| 149 TestServer::Shutdown(); | 158 TestServer::Shutdown(); |
| 150 } | 159 } |
| 151 | 160 |
| 152 // Launches the supplied |task| and blocks until it completes, with a timeout | 161 // Launches the supplied |task| and blocks until it completes, with a timeout |
| 153 // of 1 second. | 162 // of 1 second. |
| 154 void StartDataTaskAndWaitForCompletion(NSURLSessionDataTask* task) { | 163 void StartDataTaskAndWaitForCompletion(NSURLSessionDataTask* task) { |
| 155 [delegate_ reset]; | 164 [delegate_ reset]; |
| 156 [task resume]; | 165 [task resume]; |
| 157 int64_t deadline_ns = 1 * ns_in_second; | 166 dispatch_semaphore_wait([delegate_ semaphore], DISPATCH_TIME_FOREVER); |
| 158 dispatch_semaphore_wait([delegate_ semaphore], | |
| 159 dispatch_time(DISPATCH_TIME_NOW, deadline_ns)); | |
| 160 } | 167 } |
| 161 | 168 |
| 162 base::scoped_nsobject<NSURLSession> session_; | 169 base::scoped_nsobject<NSURLSession> session_; |
| 163 base::scoped_nsobject<TestDelegate> delegate_; | 170 base::scoped_nsobject<TestDelegate> delegate_; |
| 164 }; | 171 }; |
| 165 | 172 |
| 166 TEST_F(HttpTest, NSURLSessionReceivesData) { | 173 TEST_F(HttpTest, NSURLSessionReceivesData) { |
| 167 NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerUrl)); | 174 NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl)); |
| 168 __block BOOL block_used = NO; | 175 __block BOOL block_used = NO; |
| 169 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; | 176 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; |
| 170 [Cronet setRequestFilterBlock:^(NSURLRequest* request) { | 177 [Cronet setRequestFilterBlock:^(NSURLRequest* request) { |
| 171 block_used = YES; | 178 block_used = YES; |
| 172 EXPECT_EQ([request URL], url); | 179 EXPECT_EQ([request URL], url); |
| 173 return YES; | 180 return YES; |
| 174 }]; | 181 }]; |
| 175 StartDataTaskAndWaitForCompletion(task); | 182 StartDataTaskAndWaitForCompletion(task); |
| 176 EXPECT_TRUE(block_used); | 183 EXPECT_TRUE(block_used); |
| 177 EXPECT_EQ(nil, [delegate_ error]); | 184 EXPECT_EQ(nil, [delegate_ error]); |
| 178 EXPECT_STREQ(grpc_support::kHelloBodyValue, | 185 EXPECT_STREQ(grpc_support::kSimpleBodyValue, |
| 179 base::SysNSStringToUTF8([delegate_ responseBody]).c_str()); | 186 base::SysNSStringToUTF8([delegate_ responseBody]).c_str()); |
| 180 } | 187 } |
| 181 | 188 |
| 189 TEST_F(HttpTest, NSURLSessionReceivesBigHttpDataLoop) { |
| 190 int iterations = 50; |
| 191 long size = 10 * 1024 * 1024; |
| 192 LOG(INFO) << "Downloading " << size << " bytes " << iterations << " times."; |
| 193 NSTimeInterval elapsed_avg = 0; |
| 194 NSTimeInterval elapsed_max = 0; |
| 195 NSURL* url = net::NSURLWithGURL(GURL(TestServer::GetBigDataURL(size))); |
| 196 for (int i = 0; i < iterations; ++i) { |
| 197 [delegate_ reset]; |
| 198 __block BOOL block_used = NO; |
| 199 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; |
| 200 [Cronet setRequestFilterBlock:^(NSURLRequest* request) { |
| 201 block_used = YES; |
| 202 EXPECT_EQ([request URL], url); |
| 203 return YES; |
| 204 }]; |
| 205 NSDate* date = [NSDate date]; |
| 206 StartDataTaskAndWaitForCompletion(task); |
| 207 NSTimeInterval elapsed = [date timeIntervalSinceNow] * -1000.0; |
| 208 elapsed_avg += elapsed; |
| 209 if (elapsed > elapsed_max) |
| 210 elapsed_max = elapsed; |
| 211 EXPECT_TRUE(block_used); |
| 212 EXPECT_EQ(nil, [delegate_ error]); |
| 213 } |
| 214 LOG(INFO) << "Elapsed Average:" << elapsed_avg / iterations |
| 215 << "ms Max:" << elapsed_max << "ms"; |
| 216 } |
| 217 |
| 182 TEST_F(HttpTest, GetGlobalMetricsDeltas) { | 218 TEST_F(HttpTest, GetGlobalMetricsDeltas) { |
| 183 NSData* delta1 = [Cronet getGlobalMetricsDeltas]; | 219 NSData* delta1 = [Cronet getGlobalMetricsDeltas]; |
| 184 | 220 |
| 185 NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerUrl)); | 221 NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl)); |
| 186 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; | 222 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; |
| 187 StartDataTaskAndWaitForCompletion(task); | 223 StartDataTaskAndWaitForCompletion(task); |
| 188 EXPECT_EQ(nil, [delegate_ error]); | 224 EXPECT_EQ(nil, [delegate_ error]); |
| 189 EXPECT_STREQ(grpc_support::kHelloBodyValue, | 225 EXPECT_STREQ(grpc_support::kSimpleBodyValue, |
| 190 base::SysNSStringToUTF8([delegate_ responseBody]).c_str()); | 226 base::SysNSStringToUTF8([delegate_ responseBody]).c_str()); |
| 191 | 227 |
| 192 NSData* delta2 = [Cronet getGlobalMetricsDeltas]; | 228 NSData* delta2 = [Cronet getGlobalMetricsDeltas]; |
| 193 EXPECT_FALSE([delta2 isEqualToData:delta1]); | 229 EXPECT_FALSE([delta2 isEqualToData:delta1]); |
| 194 } | 230 } |
| 195 | 231 |
| 196 TEST_F(HttpTest, SdchDisabledByDefault) { | 232 TEST_F(HttpTest, SdchDisabledByDefault) { |
| 197 NSURL* url = | 233 NSURL* url = |
| 198 net::NSURLWithGURL(GURL(TestServer::GetEchoHeaderURL("Accept-Encoding"))); | 234 net::NSURLWithGURL(GURL(TestServer::GetEchoHeaderURL("Accept-Encoding"))); |
| 199 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; | 235 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 [Cronet setRequestFilterBlock:^(NSURLRequest* request) { | 445 [Cronet setRequestFilterBlock:^(NSURLRequest* request) { |
| 410 EXPECT_TRUE(false) << "Block should not be called for unsupported requests"; | 446 EXPECT_TRUE(false) << "Block should not be called for unsupported requests"; |
| 411 return YES; | 447 return YES; |
| 412 }]; | 448 }]; |
| 413 StartDataTaskAndWaitForCompletion(task); | 449 StartDataTaskAndWaitForCompletion(task); |
| 414 EXPECT_EQ(nil, [delegate_ error]); | 450 EXPECT_EQ(nil, [delegate_ error]); |
| 415 EXPECT_TRUE([[delegate_ responseBody] containsString:testString]); | 451 EXPECT_TRUE([[delegate_ responseBody] containsString:testString]); |
| 416 } | 452 } |
| 417 | 453 |
| 418 } // namespace cronet | 454 } // namespace cronet |
| OLD | NEW |