Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: ios/net/crn_http_protocol_handler.mm

Issue 2968453002: Eliminate copying of data in iOS protocol handler to improve performance (Closed)
Patch Set: Changed ERR_UNEXPECTED to ERR_FAILED Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 |buffer_|.
mef 2017/06/29 22:14:08 nit: buffer_ -> read_buffer_
kapishnikov 2017/06/30 01:06:59 Done.
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_]);
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698