Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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 "ios/net/crn_http_protocol_handler.h" | 5 #import "ios/net/crn_http_protocol_handler.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 43 #if !defined(__has_feature) || !__has_feature(objc_arc) | 43 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 44 #error "This file requires ARC support." | 44 #error "This file requires ARC support." |
| 45 #endif | 45 #endif |
| 46 | 46 |
| 47 namespace net { | 47 namespace net { |
| 48 class HttpProtocolHandlerCore; | 48 class HttpProtocolHandlerCore; |
| 49 } | 49 } |
| 50 | 50 |
| 51 namespace { | 51 namespace { |
| 52 | 52 |
| 53 // Size of the buffer used to read the net::URLRequest. | 53 // Minimum size of the buffer used to read the net::URLRequest. |
| 54 const int kIOBufferSize = 64 * 1024; | 54 const int kIOBufferMinSize = 64 * 1024; |
| 55 | 55 |
| 56 // The maximum size of NSData that can be passed to the client 'didReceiveData' | 56 // Maximum size of the buffer used to read the net::URLRequest. |
| 57 // callback. This value must always be greater or equal to |kIOBufferSize|. | 57 const int kIOBufferMaxSize = 16 * kIOBufferMinSize; // 1MB |
| 58 const int kClientMaxBufferSize = 4 * kIOBufferSize; | |
| 59 | 58 |
| 60 // Global instance of the HTTPProtocolHandlerDelegate. | 59 // Global instance of the HTTPProtocolHandlerDelegate. |
| 61 net::HTTPProtocolHandlerDelegate* g_protocol_handler_delegate = nullptr; | 60 net::HTTPProtocolHandlerDelegate* g_protocol_handler_delegate = nullptr; |
| 62 | 61 |
| 63 // Empty callback. | 62 // Empty callback. |
| 64 void DoNothing(bool flag) {} | 63 void DoNothing(bool flag) {} |
| 65 | 64 |
| 66 } // namespace | 65 } // namespace |
| 67 | 66 |
| 68 // Bridge class to forward NSStream events to the HttpProtocolHandlerCore. | 67 // Bridge class to forward NSStream events to the HttpProtocolHandlerCore. |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 // credentials if |auth_ok| is true. | 181 // credentials if |auth_ok| is true. |
| 183 void CompleteAuthentication(bool auth_ok, | 182 void CompleteAuthentication(bool auth_ok, |
| 184 const base::string16& username, | 183 const base::string16& username, |
| 185 const base::string16& password); | 184 const base::string16& password); |
| 186 void StripPostSpecificHeaders(NSMutableURLRequest* request); | 185 void StripPostSpecificHeaders(NSMutableURLRequest* request); |
| 187 void CancelAfterSSLError(); | 186 void CancelAfterSSLError(); |
| 188 void ContinueAfterSSLError(); | 187 void ContinueAfterSSLError(); |
| 189 void SSLErrorCallback(bool carryOn); | 188 void SSLErrorCallback(bool carryOn); |
| 190 void HostStateCallback(bool carryOn); | 189 void HostStateCallback(bool carryOn); |
| 191 void StartReading(); | 190 void StartReading(); |
| 191 void AllocateReadBuffer(int last_read_data_size); | |
| 192 | 192 |
| 193 base::ThreadChecker thread_checker_; | 193 base::ThreadChecker thread_checker_; |
| 194 | 194 |
| 195 // The NSURLProtocol client. | 195 // The NSURLProtocol client. |
| 196 id<CRNNetworkClientProtocol> client_; | 196 id<CRNNetworkClientProtocol> client_; |
| 197 scoped_refptr<IOBuffer> buffer_; | 197 std::unique_ptr<char[]> read_buffer_; |
| 198 int read_buffer_size_; | |
| 199 scoped_refptr<WrappedIOBuffer> read_buffer_wrapper_; | |
| 198 base::scoped_nsobject<NSMutableURLRequest> request_; | 200 base::scoped_nsobject<NSMutableURLRequest> request_; |
| 199 // Stream delegate to read the HTTPBodyStream. | 201 // Stream delegate to read the HTTPBodyStream. |
| 200 base::scoped_nsobject<CRWHTTPStreamDelegate> stream_delegate_; | 202 base::scoped_nsobject<CRWHTTPStreamDelegate> stream_delegate_; |
| 201 // Vector of readers used to accumulate a POST data stream. | 203 // Vector of readers used to accumulate a POST data stream. |
| 202 std::vector<std::unique_ptr<UploadElementReader>> post_data_readers_; | 204 std::vector<std::unique_ptr<UploadElementReader>> post_data_readers_; |
| 203 | 205 |
| 204 // This cannot be a scoped pointer because it must be deleted on the IO | 206 // This cannot be a scoped pointer because it must be deleted on the IO |
| 205 // thread. | 207 // thread. |
| 206 URLRequest* net_request_; | 208 URLRequest* net_request_; |
| 207 | 209 |
| 208 base::WeakPtr<RequestTracker> tracker_; | 210 base::WeakPtr<RequestTracker> tracker_; |
| 209 | 211 |
| 210 DISALLOW_COPY_AND_ASSIGN(HttpProtocolHandlerCore); | 212 DISALLOW_COPY_AND_ASSIGN(HttpProtocolHandlerCore); |
| 211 }; | 213 }; |
| 212 | 214 |
| 213 HttpProtocolHandlerCore::HttpProtocolHandlerCore(NSURLRequest* request) | 215 HttpProtocolHandlerCore::HttpProtocolHandlerCore(NSURLRequest* request) |
| 214 : client_(nil), | 216 : client_(nil), |
| 215 buffer_(new IOBuffer(kIOBufferSize)), | 217 read_buffer_size_(kIOBufferMinSize), |
| 218 read_buffer_wrapper_(nullptr), | |
| 216 net_request_(nullptr) { | 219 net_request_(nullptr) { |
| 217 // The request will be accessed from another thread. It is safer to make a | 220 // The request will be accessed from another thread. It is safer to make a |
| 218 // copy to avoid conflicts. | 221 // copy to avoid conflicts. |
| 219 // The copy is mutable, because that request will be given to the client in | 222 // The copy is mutable, because that request will be given to the client in |
| 220 // case of a redirect, but with a different URL. The URL must be created | 223 // case of a redirect, but with a different URL. The URL must be created |
| 221 // from the absoluteString of the original URL, because mutableCopy only | 224 // from the absoluteString of the original URL, because mutableCopy only |
| 222 // shallowly copies the request, and just retains the non-threadsafe NSURL. | 225 // shallowly copies the request, and just retains the non-threadsafe NSURL. |
| 223 thread_checker_.DetachFromThread(); | 226 thread_checker_.DetachFromThread(); |
| 224 request_.reset([request mutableCopy]); | 227 request_.reset([request mutableCopy]); |
| 228 read_buffer_.reset(new char[kIOBufferMinSize]); | |
| 225 [request_ setURL:[NSURL URLWithString:[[request URL] absoluteString]]]; | 229 [request_ setURL:[NSURL URLWithString:[[request URL] absoluteString]]]; |
| 226 } | 230 } |
| 227 | 231 |
| 228 void HttpProtocolHandlerCore::HandleStreamEvent(NSStream* stream, | 232 void HttpProtocolHandlerCore::HandleStreamEvent(NSStream* stream, |
| 229 NSStreamEvent event) { | 233 NSStreamEvent event) { |
| 230 DCHECK(thread_checker_.CalledOnValidThread()); | 234 DCHECK(thread_checker_.CalledOnValidThread()); |
| 231 DCHECK(stream_delegate_); | 235 DCHECK(stream_delegate_); |
| 232 switch (event) { | 236 switch (event) { |
| 233 case NSStreamEventErrorOccurred: | 237 case NSStreamEventErrorOccurred: |
| 234 DLOG(ERROR) | 238 DLOG(ERROR) |
| 235 << "Failed to read POST data: " | 239 << "Failed to read POST data: " |
| 236 << base::SysNSStringToUTF8([[stream streamError] description]); | 240 << base::SysNSStringToUTF8([[stream streamError] description]); |
| 237 StopListeningStream(stream); | 241 StopListeningStream(stream); |
| 238 StopRequestWithError(NSURLErrorUnknown, ERR_UNEXPECTED); | 242 StopRequestWithError(NSURLErrorUnknown, ERR_UNEXPECTED); |
| 239 break; | 243 break; |
| 240 case NSStreamEventEndEncountered: | 244 case NSStreamEventEndEncountered: |
| 241 StopListeningStream(stream); | 245 StopListeningStream(stream); |
| 242 if (!post_data_readers_.empty()) { | 246 if (!post_data_readers_.empty()) { |
| 243 // NOTE: This call will result in |post_data_readers_| being cleared, | 247 // NOTE: This call will result in |post_data_readers_| being cleared, |
| 244 // which is the desired behavior. | 248 // which is the desired behavior. |
| 245 net_request_->set_upload(base::MakeUnique<ElementsUploadDataStream>( | 249 net_request_->set_upload(base::MakeUnique<ElementsUploadDataStream>( |
| 246 std::move(post_data_readers_), 0)); | 250 std::move(post_data_readers_), 0)); |
| 247 DCHECK(post_data_readers_.empty()); | 251 DCHECK(post_data_readers_.empty()); |
| 248 } | 252 } |
| 249 net_request_->Start(); | 253 net_request_->Start(); |
| 250 if (tracker_) | 254 if (tracker_) |
| 251 tracker_->StartRequest(net_request_); | 255 tracker_->StartRequest(net_request_); |
| 252 break; | 256 break; |
| 253 case NSStreamEventHasBytesAvailable: { | 257 case NSStreamEventHasBytesAvailable: { |
| 254 NSUInteger length; | 258 NSInteger length; |
| 255 DCHECK([stream isKindOfClass:[NSInputStream class]]); | 259 DCHECK([stream isKindOfClass:[NSInputStream class]]); |
| 256 length = [(NSInputStream*)stream read:(unsigned char*)buffer_->data() | 260 // TODO(crbug.com/738025): Dynamically change the size of the read buffer |
| 257 maxLength:kIOBufferSize]; | 261 // to improve the read (POST) performance, see AllocateReadBuffer() & |
| 262 // avoid unnecessary data copy. | |
| 263 length = [(NSInputStream*)stream | |
|
sdefresne
2017/06/29 16:32:53
drive-by: style guide bans casts using C style (ht
kapishnikov
2017/06/29 19:40:11
Done. It is good to know. Thanks!
| |
| 264 read:(unsigned char*)(read_buffer_.get())maxLength:read_buffer_size_]; | |
|
mef
2017/06/29 16:18:38
nit: weird formatting. Maybe try git cl fomat ios/
kapishnikov
2017/06/29 19:40:11
That was the output of "git cl format". Agree that
| |
| 258 if (length) { | 265 if (length) { |
|
mef
2017/06/29 16:18:38
Length could be -1 if error occurred. We should ha
kapishnikov
2017/06/29 19:40:11
Nice catch. Fixed it.
| |
| 259 std::vector<char> owned_data(buffer_->data(), buffer_->data() + length); | 266 std::vector<char> owned_data(read_buffer_.get(), |
| 267 read_buffer_.get() + length); | |
| 260 post_data_readers_.push_back( | 268 post_data_readers_.push_back( |
| 261 base::MakeUnique<UploadOwnedBytesElementReader>(&owned_data)); | 269 base::MakeUnique<UploadOwnedBytesElementReader>(&owned_data)); |
| 262 } | 270 } |
| 263 break; | 271 break; |
| 264 } | 272 } |
| 265 case NSStreamEventNone: | 273 case NSStreamEventNone: |
| 266 case NSStreamEventOpenCompleted: | 274 case NSStreamEventOpenCompleted: |
| 267 case NSStreamEventHasSpaceAvailable: | 275 case NSStreamEventHasSpaceAvailable: |
| 268 break; | 276 break; |
| 269 default: | 277 default: |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 491 tracker_->CaptureHeaders(net_request_); | 499 tracker_->CaptureHeaders(net_request_); |
| 492 long long expectedContentLength = [response expectedContentLength]; | 500 long long expectedContentLength = [response expectedContentLength]; |
| 493 if (expectedContentLength > 0) | 501 if (expectedContentLength > 0) |
| 494 tracker_->CaptureExpectedLength(net_request_, expectedContentLength); | 502 tracker_->CaptureExpectedLength(net_request_, expectedContentLength); |
| 495 } | 503 } |
| 496 | 504 |
| 497 // Don't call any function on the response from now on, as the client may be | 505 // Don't call any function on the response from now on, as the client may be |
| 498 // using it and the object is not re-entrant. | 506 // using it and the object is not re-entrant. |
| 499 [client_ didReceiveResponse:response]; | 507 [client_ didReceiveResponse:response]; |
| 500 | 508 |
| 501 int bytes_read = net_request_->Read(buffer_.get(), kIOBufferSize); | 509 read_buffer_wrapper_ = new WrappedIOBuffer((const char*)(read_buffer_.get())); |
| 510 int bytes_read = | |
| 511 net_request_->Read(read_buffer_wrapper_.get(), read_buffer_size_); | |
| 502 if (bytes_read == net::ERR_IO_PENDING) | 512 if (bytes_read == net::ERR_IO_PENDING) |
| 503 return; | 513 return; |
| 504 | 514 |
| 505 if (bytes_read >= 0) { | 515 if (bytes_read >= 0) { |
| 506 OnReadCompleted(net_request_, bytes_read); | 516 OnReadCompleted(net_request_, bytes_read); |
| 507 } else { | 517 } else { |
| 508 int error = bytes_read; | 518 int error = bytes_read; |
| 509 StopRequestWithError(IOSErrorCode(error), error); | 519 StopRequestWithError(IOSErrorCode(error), error); |
| 510 } | 520 } |
| 511 } | 521 } |
| 512 | 522 |
| 513 void HttpProtocolHandlerCore::OnReadCompleted(URLRequest* request, | 523 void HttpProtocolHandlerCore::OnReadCompleted(URLRequest* request, |
| 514 int bytes_read) { | 524 int bytes_read) { |
| 515 DCHECK_NE(net::ERR_IO_PENDING, bytes_read); | 525 DCHECK_NE(net::ERR_IO_PENDING, bytes_read); |
| 516 DCHECK(thread_checker_.CalledOnValidThread()); | 526 DCHECK(thread_checker_.CalledOnValidThread()); |
| 517 | 527 |
| 518 if (net_request_ == nullptr) | 528 if (net_request_ == nullptr) |
| 519 return; | 529 return; |
| 520 | 530 |
| 521 DCHECK_EQ(net_request_, request); | 531 DCHECK_EQ(net_request_, request); |
| 522 DCHECK_GE(kClientMaxBufferSize, kIOBufferSize); | |
| 523 | 532 |
| 524 // Read all we can from the socket and put it into data. | 533 // Read data from the socket until no bytes left to read. |
| 525 // TODO(droger): It may be possible to avoid some of the copies (using | |
| 526 // WrappedIOBuffer for example). | |
| 527 uint64_t total_bytes_read = 0; | 534 uint64_t total_bytes_read = 0; |
| 528 while (bytes_read > 0) { | 535 while (bytes_read > 0) { |
| 529 base::scoped_nsobject<NSMutableData> data( | 536 total_bytes_read += bytes_read; |
| 530 [[NSMutableData alloc] initWithCapacity:bytes_read]); | 537 // The NSData will take the ownership of |buffer_|. |
| 531 // |bytes_read| should always be less or equal to |kClientMaxBufferSize|. | 538 NSData* data = |
| 532 // This is ensured by the fact that the max read buffer size (i.e. | 539 [NSData dataWithBytesNoCopy:read_buffer_.release() length:bytes_read]; |
| 533 // |kIOBufferSize|) is always smaller or equal to |kClientMaxBufferSize|. | 540 // If the data is not encoded in UTF8, the NSString is nil. |
| 534 while (bytes_read > 0 && | 541 DVLOG(3) << "To client:" << std::endl |
| 535 [data length] + bytes_read <= kClientMaxBufferSize) { | 542 << base::SysNSStringToUTF8([[NSString alloc] |
| 536 total_bytes_read += bytes_read; | 543 initWithData:data |
| 537 [data appendBytes:buffer_->data() length:bytes_read]; | 544 encoding:NSUTF8StringEncoding]); |
| 538 bytes_read = request->Read(buffer_.get(), kIOBufferSize); | 545 // Pass the read data to the client. |
| 539 } | 546 [client_ didLoadData:data]; |
| 540 | 547 |
| 541 if ([data length] > 0) { | 548 // Allocate a new buffer and continue reading from the socket. |
| 542 // If the data is not encoded in UTF8, the NSString is nil. | 549 AllocateReadBuffer(bytes_read); |
| 543 DVLOG(3) << "To client:" << std::endl | 550 read_buffer_wrapper_ = |
| 544 << base::SysNSStringToUTF8([[NSString alloc] | 551 new WrappedIOBuffer((const char*)(read_buffer_.get())); |
| 545 initWithData:data | 552 bytes_read = request->Read(read_buffer_wrapper_.get(), read_buffer_size_); |
| 546 encoding:NSUTF8StringEncoding]); | |
| 547 [client_ didLoadData:data]; | |
| 548 } | |
| 549 } | 553 } |
| 550 | 554 |
| 551 if (tracker_) | 555 if (tracker_) |
| 552 tracker_->CaptureReceivedBytes(request, total_bytes_read); | 556 tracker_->CaptureReceivedBytes(request, total_bytes_read); |
| 553 | 557 |
| 554 if (bytes_read == net::OK) { | 558 if (bytes_read == net::OK) { |
| 555 // If there is nothing more to read. | 559 // If there is nothing more to read. |
| 556 StopNetRequest(); | 560 StopNetRequest(); |
| 557 [client_ didFinishLoading]; | 561 [client_ didFinishLoading]; |
| 558 } else if (bytes_read != net::ERR_IO_PENDING) { | 562 } else if (bytes_read != net::ERR_IO_PENDING) { |
| 559 // If there was an error (not canceled). | 563 // If there was an error (not canceled). |
| 560 int error = bytes_read; | 564 int error = bytes_read; |
| 561 StopRequestWithError(IOSErrorCode(error), error); | 565 StopRequestWithError(IOSErrorCode(error), error); |
| 562 } | 566 } |
| 563 } | 567 } |
| 564 | 568 |
| 569 void HttpProtocolHandlerCore::AllocateReadBuffer(int last_read_data_size) { | |
| 570 if (last_read_data_size == read_buffer_size_) { | |
| 571 // If the whole buffer was filled with data then increase the buffer size | |
| 572 // for the next read but don't exceed |kIOBufferMaxSize|. | |
| 573 read_buffer_size_ = std::min(read_buffer_size_ * 2, kIOBufferMaxSize); | |
| 574 } else if (read_buffer_size_ / 2 >= last_read_data_size) { | |
| 575 // If only a half or less of the buffer was filled with data then reduce | |
| 576 // the buffer size for the next read but not make it smaller than | |
| 577 // |kIOBufferMinSize|. | |
| 578 read_buffer_size_ = std::max(read_buffer_size_ / 2, kIOBufferMinSize); | |
| 579 } | |
| 580 read_buffer_.reset(new char[read_buffer_size_]); | |
| 581 } | |
| 582 | |
| 565 HttpProtocolHandlerCore::~HttpProtocolHandlerCore() { | 583 HttpProtocolHandlerCore::~HttpProtocolHandlerCore() { |
| 566 DCHECK(thread_checker_.CalledOnValidThread()); | 584 DCHECK(thread_checker_.CalledOnValidThread()); |
| 567 [client_ cancelAuthRequest]; | 585 [client_ cancelAuthRequest]; |
| 568 DCHECK(!net_request_); | 586 DCHECK(!net_request_); |
| 569 DCHECK(!stream_delegate_); | 587 DCHECK(!stream_delegate_); |
| 570 } | 588 } |
| 571 | 589 |
| 572 // static | 590 // static |
| 573 void HttpProtocolHandlerCore::Destruct(const HttpProtocolHandlerCore* x) { | 591 void HttpProtocolHandlerCore::Destruct(const HttpProtocolHandlerCore* x) { |
| 574 scoped_refptr<base::SingleThreadTaskRunner> task_runner = | 592 scoped_refptr<base::SingleThreadTaskRunner> task_runner = |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 964 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); | 982 base::Bind(&net::HttpProtocolHandlerCore::Cancel, _core)); |
| 965 [_protocolProxy invalidate]; | 983 [_protocolProxy invalidate]; |
| 966 } | 984 } |
| 967 | 985 |
| 968 - (void)stopLoading { | 986 - (void)stopLoading { |
| 969 [self cancelRequest]; | 987 [self cancelRequest]; |
| 970 _protocolProxy.reset(); | 988 _protocolProxy.reset(); |
| 971 } | 989 } |
| 972 | 990 |
| 973 @end | 991 @end |
| OLD | NEW |