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