crn_http_protocol_handler.mm 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  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
  3. // found in the LICENSE file.
  4. #import "ios/net/crn_http_protocol_handler.h"
  5. #include <stdint.h>
  6. #include <memory>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/bind.h"
  10. #include "base/callback_helpers.h"
  11. #include "base/command_line.h"
  12. #include "base/logging.h"
  13. #include "base/mac/foundation_util.h"
  14. #include "base/memory/ref_counted.h"
  15. #include "base/strings/string_util.h"
  16. #include "base/strings/sys_string_conversions.h"
  17. #include "base/strings/utf_string_conversions.h"
  18. #include "base/task/single_thread_task_runner.h"
  19. #include "ios/net/chunked_data_stream_uploader.h"
  20. #import "ios/net/clients/crn_network_client_protocol.h"
  21. #import "ios/net/crn_http_protocol_handler_proxy_with_client_thread.h"
  22. #import "ios/net/http_protocol_logging.h"
  23. #include "ios/net/nsurlrequest_util.h"
  24. #import "ios/net/protocol_handler_util.h"
  25. #include "net/base/auth.h"
  26. #include "net/base/elements_upload_data_stream.h"
  27. #include "net/base/io_buffer.h"
  28. #include "net/base/load_flags.h"
  29. #import "net/base/mac/url_conversions.h"
  30. #include "net/base/net_errors.h"
  31. #include "net/base/upload_bytes_element_reader.h"
  32. #include "net/http/http_request_headers.h"
  33. #include "net/url_request/redirect_info.h"
  34. #include "net/url_request/url_request.h"
  35. #include "net/url_request/url_request_context.h"
  36. #include "net/url_request/url_request_context_getter.h"
  37. #if !defined(__has_feature) || !__has_feature(objc_arc)
  38. #error "This file requires ARC support."
  39. #endif
  40. namespace net {
  41. class HttpProtocolHandlerCore;
  42. }
  43. namespace {
  44. // Minimum size of the buffer used to read the net::URLRequest.
  45. const int kIOBufferMinSize = 64 * 1024;
  46. // Maximum size of the buffer used to read the net::URLRequest.
  47. const int kIOBufferMaxSize = 16 * kIOBufferMinSize; // 1MB
  48. // Global instance of the HTTPProtocolHandlerDelegate.
  49. net::HTTPProtocolHandlerDelegate* g_protocol_handler_delegate = nullptr;
  50. // Global instance of the MetricsDelegate.
  51. net::MetricsDelegate* g_metrics_delegate = nullptr;
  52. } // namespace
  53. // Bridge class to forward NSStream events to the HttpProtocolHandlerCore.
  54. // Lives on the IO thread.
  55. @interface CRWHTTPStreamDelegate : NSObject<NSStreamDelegate> {
  56. @private
  57. // The object is owned by |_core| and has a weak reference to it.
  58. net::HttpProtocolHandlerCore* _core; // weak
  59. }
  60. - (instancetype)initWithHttpProtocolHandlerCore:
  61. (net::HttpProtocolHandlerCore*)core;
  62. // NSStreamDelegate method.
  63. - (void)stream:(NSStream*)theStream handleEvent:(NSStreamEvent)streamEvent;
  64. @end
  65. #pragma mark -
  66. #pragma mark HttpProtocolHandlerCore
  67. namespace net {
  68. MetricsDelegate::Metrics::Metrics() = default;
  69. MetricsDelegate::Metrics::~Metrics() = default;
  70. // static
  71. void HTTPProtocolHandlerDelegate::SetInstance(
  72. HTTPProtocolHandlerDelegate* delegate) {
  73. g_protocol_handler_delegate = delegate;
  74. }
  75. // static
  76. void MetricsDelegate::SetInstance(MetricsDelegate* delegate) {
  77. g_metrics_delegate = delegate;
  78. }
  79. // The HttpProtocolHandlerCore class is the bridge between the URLRequest
  80. // and the NSURLProtocolClient.
  81. // Threading and ownership details:
  82. // - The HttpProtocolHandlerCore is owned by the HttpProtocolHandler
  83. // - The HttpProtocolHandler is owned by the system and can be deleted anytime
  84. // - All the methods of HttpProtocolHandlerCore must be called on the IO thread,
  85. // except its constructor that can be called from any thread.
  86. // Implementation notes from Apple's "Read Me About CustomHttpProtocolHandler":
  87. //
  88. // An NSURLProtocol subclass is expected to call the various methods of the
  89. // NSURLProtocolClient from the loading thread, including all of the following:
  90. // -URLProtocol:wasRedirectedToRequest:redirectResponse:
  91. // -URLProtocol:didReceiveResponse:cacheStoragePolicy:
  92. // -URLProtocol:didLoadData:
  93. // -URLProtocol:didFinishLoading:
  94. // -URLProtocol:didFailWithError:
  95. // -URLProtocol:didReceiveAuthenticationChallenge:
  96. // -URLProtocol:didCancelAuthenticationChallenge:
  97. //
  98. // The NSURLProtocol subclass must call the client callbacks in the expected
  99. // order. This breaks down into three phases:
  100. // o pre-response -- In the initial phase the NSURLProtocol can make any number
  101. // of -URLProtocol:wasRedirectedToRequest:redirectResponse: and
  102. // -URLProtocol:didReceiveAuthenticationChallenge: callbacks.
  103. // o response -- It must then call
  104. // -URLProtocol:didReceiveResponse:cacheStoragePolicy: to indicate the
  105. // arrival of a definitive response.
  106. // o post-response -- After receive a response it may then make any number of
  107. // -URLProtocol:didLoadData: callbacks, followed by a
  108. // -URLProtocolDidFinishLoading: callback.
  109. //
  110. // The -URLProtocol:didFailWithError: callback can be made at any time
  111. // (although keep in mind the following point).
  112. //
  113. // The NSProtocol subclass must only send one authentication challenge to the
  114. // client at a time. After calling
  115. // -URLProtocol:didReceiveAuthenticationChallenge:, it must wait for the client
  116. // to resolve the challenge before calling any callbacks other than
  117. // -URLProtocol:didCancelAuthenticationChallenge:. This means that, if the
  118. // connection fails while there is an outstanding authentication challenge, the
  119. // NSURLProtocol subclass must call
  120. // -URLProtocol:didCancelAuthenticationChallenge: before calling
  121. // -URLProtocol:didFailWithError:.
  122. class HttpProtocolHandlerCore
  123. : public base::RefCountedThreadSafe<HttpProtocolHandlerCore,
  124. HttpProtocolHandlerCore>,
  125. public URLRequest::Delegate,
  126. public ChunkedDataStreamUploader::Delegate {
  127. public:
  128. explicit HttpProtocolHandlerCore(NSURLRequest* request);
  129. explicit HttpProtocolHandlerCore(NSURLSessionTask* task);
  130. HttpProtocolHandlerCore(const HttpProtocolHandlerCore&) = delete;
  131. HttpProtocolHandlerCore& operator=(const HttpProtocolHandlerCore&) = delete;
  132. // Starts the network request, and forwards the data downloaded from the
  133. // network to |base_client|.
  134. void Start(id<CRNNetworkClientProtocol> base_client);
  135. // Cancels the request.
  136. void Cancel();
  137. // Called by NSStreamDelegate. Used for POST requests having a HTTPBodyStream.
  138. void HandleStreamEvent(NSStream* stream, NSStreamEvent event);
  139. // URLRequest::Delegate methods:
  140. void OnReceivedRedirect(URLRequest* request,
  141. const RedirectInfo& new_url,
  142. bool* defer_redirect) override;
  143. void OnAuthRequired(URLRequest* request,
  144. const AuthChallengeInfo& auth_info) override;
  145. void OnCertificateRequested(URLRequest* request,
  146. SSLCertRequestInfo* cert_request_info) override;
  147. void OnSSLCertificateError(URLRequest* request,
  148. int net_error,
  149. const SSLInfo& ssl_info,
  150. bool fatal) override;
  151. void OnResponseStarted(URLRequest* request, int net_error) override;
  152. void OnReadCompleted(URLRequest* request, int bytes_read) override;
  153. // ChunkedDataStreamUploader::Delegate method:
  154. int OnRead(char* buffer, int buffer_length) override;
  155. private:
  156. friend class base::RefCountedThreadSafe<HttpProtocolHandlerCore,
  157. HttpProtocolHandlerCore>;
  158. friend class base::DeleteHelper<HttpProtocolHandlerCore>;
  159. ~HttpProtocolHandlerCore() override;
  160. // RefCountedThreadSafe traits implementation:
  161. static void Destruct(const HttpProtocolHandlerCore* x);
  162. void SetLoadFlags();
  163. void StopNetRequest();
  164. // Stop listening the delegate on the IO run loop.
  165. void StopListeningStream(NSStream* stream);
  166. NSInteger IOSErrorCode(int os_error);
  167. void StopRequestWithError(NSInteger ns_error_code, int net_error_code);
  168. void StripPostSpecificHeaders(NSMutableURLRequest* request);
  169. void CancelAfterSSLError();
  170. void StartReading();
  171. void AllocateReadBuffer(int last_read_data_size);
  172. base::ThreadChecker thread_checker_;
  173. // The NSURLProtocol client.
  174. id<CRNNetworkClientProtocol> client_ = nil;
  175. std::unique_ptr<char, base::FreeDeleter> read_buffer_;
  176. int read_buffer_size_ = kIOBufferMinSize;
  177. scoped_refptr<WrappedIOBuffer> read_buffer_wrapper_;
  178. NSMutableURLRequest* request_ = nil;
  179. NSURLSessionTask* task_ = nil;
  180. // The stream has data to upload.
  181. NSInputStream* http_body_stream_ = nil;
  182. // Stream delegate to read the HTTPBodyStream.
  183. CRWHTTPStreamDelegate* http_body_stream_delegate_ = nullptr;
  184. // Vector of readers used to accumulate a POST data stream.
  185. std::vector<std::unique_ptr<UploadElementReader>> post_data_readers_;
  186. // This cannot be a scoped pointer because it must be deleted on the IO
  187. // thread.
  188. URLRequest* net_request_ = nullptr;
  189. // It is a weak pointer because the owner of the uploader is the URLRequest.
  190. base::WeakPtr<ChunkedDataStreamUploader> chunked_uploader_;
  191. };
  192. HttpProtocolHandlerCore::HttpProtocolHandlerCore(NSURLRequest* request) {
  193. // The request will be accessed from another thread. It is safer to make a
  194. // copy to avoid conflicts.
  195. // The copy is mutable, because that request will be given to the client in
  196. // case of a redirect, but with a different URL. The URL must be created
  197. // from the absoluteString of the original URL, because mutableCopy only
  198. // shallowly copies the request, and just retains the non-threadsafe NSURL.
  199. thread_checker_.DetachFromThread();
  200. task_ = nil;
  201. request_ = [request mutableCopy];
  202. // Will allocate read buffer with size |kIOBufferMinSize|.
  203. AllocateReadBuffer(0);
  204. [request_ setURL:request.URL];
  205. }
  206. HttpProtocolHandlerCore::HttpProtocolHandlerCore(NSURLSessionTask* task)
  207. : HttpProtocolHandlerCore([task currentRequest]) {
  208. task_ = task;
  209. }
  210. void HttpProtocolHandlerCore::HandleStreamEvent(NSStream* stream,
  211. NSStreamEvent event) {
  212. DVLOG(2) << "HandleStreamEvent " << stream << " event " << event;
  213. DCHECK(thread_checker_.CalledOnValidThread());
  214. DCHECK(http_body_stream_ == stream);
  215. DCHECK(http_body_stream_delegate_);
  216. switch (event) {
  217. case NSStreamEventErrorOccurred:
  218. DLOG(ERROR)
  219. << "Failed to read POST data: "
  220. << base::SysNSStringToUTF8([[stream streamError] description]);
  221. StopListeningStream(stream);
  222. StopRequestWithError(NSURLErrorUnknown, ERR_UNEXPECTED);
  223. break;
  224. case NSStreamEventEndEncountered:
  225. StopListeningStream(stream);
  226. if (chunked_uploader_) {
  227. chunked_uploader_->UploadWhenReady(true);
  228. break;
  229. }
  230. if (!post_data_readers_.empty()) {
  231. // NOTE: This call will result in |post_data_readers_| being cleared,
  232. // which is the desired behavior.
  233. net_request_->set_upload(std::make_unique<ElementsUploadDataStream>(
  234. std::move(post_data_readers_), 0));
  235. DCHECK(post_data_readers_.empty());
  236. }
  237. net_request_->Start();
  238. break;
  239. case NSStreamEventHasBytesAvailable: {
  240. if (chunked_uploader_) {
  241. chunked_uploader_->UploadWhenReady(false);
  242. break;
  243. }
  244. NSInteger length;
  245. // TODO(crbug.com/738025): Dynamically change the size of the read buffer
  246. // to improve the read (POST) performance, see AllocateReadBuffer(), &
  247. // avoid unnecessary data copy.
  248. length = [base::mac::ObjCCastStrict<NSInputStream>(stream)
  249. read:reinterpret_cast<unsigned char*>(read_buffer_.get())
  250. maxLength:read_buffer_size_];
  251. if (length > 0) {
  252. std::vector<char> owned_data(read_buffer_.get(),
  253. read_buffer_.get() + length);
  254. post_data_readers_.push_back(
  255. std::make_unique<UploadOwnedBytesElementReader>(&owned_data));
  256. } else if (length < 0) { // Error
  257. StopRequestWithError(stream.streamError.code, ERR_FAILED);
  258. }
  259. break;
  260. }
  261. case NSStreamEventNone:
  262. case NSStreamEventOpenCompleted:
  263. case NSStreamEventHasSpaceAvailable:
  264. break;
  265. default:
  266. NOTREACHED() << "Unexpected stream event: " << event;
  267. break;
  268. }
  269. }
  270. #pragma mark URLRequest::Delegate methods
  271. void HttpProtocolHandlerCore::OnReceivedRedirect(
  272. URLRequest* request,
  273. const RedirectInfo& redirect_info,
  274. bool* /* defer_redirect */) {
  275. DCHECK(thread_checker_.CalledOnValidThread());
  276. // Cancel the request and notify UIWebView.
  277. // If we did nothing, the network stack would follow the redirect
  278. // automatically, however we do not want this because we need the UIWebView to
  279. // be notified. The UIWebView will then issue a new request following the
  280. // redirect.
  281. DCHECK(request_);
  282. GURL new_url = redirect_info.new_url;
  283. if (!new_url.is_valid()) {
  284. StopRequestWithError(NSURLErrorBadURL, ERR_INVALID_URL);
  285. return;
  286. }
  287. DCHECK(new_url.is_valid());
  288. NSURL* new_nsurl = NSURLWithGURL(new_url);
  289. // Stash the original URL in case we need to report it in an error.
  290. [request_ setURL:new_nsurl];
  291. if (http_body_stream_)
  292. StopListeningStream(http_body_stream_);
  293. // TODO(droger): See if we can share some code with URLRequest::Redirect() in
  294. // net/net_url_request/url_request.cc.
  295. // For 303 redirects, all request methods except HEAD are converted to GET,
  296. // as per the latest httpbis draft. The draft also allows POST requests to
  297. // be converted to GETs when following 301/302 redirects, for historical
  298. // reasons. Most major browsers do this and so shall we.
  299. // See:
  300. // https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-17#section-7.3
  301. const int http_status_code = request->GetResponseCode();
  302. NSString* method = [request_ HTTPMethod];
  303. const bool was_post = [method isEqualToString:@"POST"];
  304. if ((http_status_code == 303 && ![method isEqualToString:@"HEAD"]) ||
  305. ((http_status_code == 301 || http_status_code == 302) && was_post)) {
  306. [request_ setHTTPMethod:@"GET"];
  307. [request_ setHTTPBody:nil];
  308. [request_ setHTTPBodyStream:nil];
  309. if (was_post) {
  310. // If being switched from POST to GET, must remove headers that were
  311. // specific to the POST and don't have meaning in GET. For example
  312. // the inclusion of a multipart Content-Type header in GET can cause
  313. // problems with some servers:
  314. // http://code.google.com/p/chromium/issues/detail?id=843
  315. StripPostSpecificHeaders(request_);
  316. }
  317. }
  318. NSURLResponse* response = GetNSURLResponseForRequest(request);
  319. #if !defined(NDEBUG)
  320. DVLOG(2) << "Redirect, to client:";
  321. LogNSURLResponse(response);
  322. DVLOG(2) << "Redirect, to client:";
  323. LogNSURLRequest(request_);
  324. #endif // !defined(NDEBUG)
  325. [client_ wasRedirectedToRequest:request_
  326. nativeRequest:request
  327. redirectResponse:response];
  328. // Don't use |request_| or |response| anymore, as the client may be using them
  329. // on another thread and they are not re-entrant. As |request_| is mutable, it
  330. // is also important that it is not modified.
  331. request_ = nil;
  332. request->Cancel();
  333. DCHECK_EQ(net_request_, request);
  334. StopNetRequest();
  335. }
  336. void HttpProtocolHandlerCore::OnAuthRequired(
  337. URLRequest* request,
  338. const AuthChallengeInfo& auth_info) {
  339. DCHECK(thread_checker_.CalledOnValidThread());
  340. if (net_request_ != nullptr) {
  341. net_request_->CancelAuth();
  342. }
  343. }
  344. void HttpProtocolHandlerCore::OnCertificateRequested(
  345. URLRequest* request,
  346. SSLCertRequestInfo* cert_request_info) {
  347. DCHECK(thread_checker_.CalledOnValidThread());
  348. // TODO(ios): The network stack does not support SSL client authentication
  349. // on iOS yet. The request has to be canceled for now.
  350. request->Cancel();
  351. StopRequestWithError(NSURLErrorClientCertificateRequired,
  352. ERR_SSL_PROTOCOL_ERROR);
  353. }
  354. void HttpProtocolHandlerCore::CancelAfterSSLError(void) {
  355. DCHECK(thread_checker_.CalledOnValidThread());
  356. if (net_request_ != nullptr) {
  357. // Cancel the request.
  358. net_request_->Cancel();
  359. // The request is signalled simply cancelled to the consumer, the
  360. // presentation of the SSL error will be done via the tracker.
  361. StopRequestWithError(NSURLErrorCancelled, ERR_BLOCKED_BY_CLIENT);
  362. }
  363. }
  364. void HttpProtocolHandlerCore::OnSSLCertificateError(URLRequest* request,
  365. int net_error,
  366. const SSLInfo& ssl_info,
  367. bool fatal) {
  368. DCHECK(thread_checker_.CalledOnValidThread());
  369. CancelAfterSSLError();
  370. }
  371. void HttpProtocolHandlerCore::OnResponseStarted(URLRequest* request,
  372. int net_error) {
  373. DCHECK(thread_checker_.CalledOnValidThread());
  374. DCHECK_NE(net::ERR_IO_PENDING, net_error);
  375. if (net_request_ == nullptr)
  376. return;
  377. if (net_error != net::OK) {
  378. StopRequestWithError(IOSErrorCode(net_error), net_error);
  379. return;
  380. }
  381. StartReading();
  382. }
  383. void HttpProtocolHandlerCore::StartReading() {
  384. DCHECK(thread_checker_.CalledOnValidThread());
  385. if (net_request_ == nullptr)
  386. return;
  387. NSURLResponse* response = GetNSURLResponseForRequest(net_request_);
  388. #if !defined(NDEBUG)
  389. DVLOG(2) << "To client:";
  390. LogNSURLResponse(response);
  391. #endif // !defined(NDEBUG)
  392. // Don't call any function on the response from now on, as the client may be
  393. // using it and the object is not re-entrant.
  394. [client_ didReceiveResponse:response];
  395. int bytes_read =
  396. net_request_->Read(read_buffer_wrapper_.get(), read_buffer_size_);
  397. if (bytes_read == net::ERR_IO_PENDING)
  398. return;
  399. if (bytes_read >= 0) {
  400. OnReadCompleted(net_request_, bytes_read);
  401. } else {
  402. int error = bytes_read;
  403. StopRequestWithError(IOSErrorCode(error), error);
  404. }
  405. }
  406. void HttpProtocolHandlerCore::OnReadCompleted(URLRequest* request,
  407. int bytes_read) {
  408. DCHECK_NE(net::ERR_IO_PENDING, bytes_read);
  409. DCHECK(thread_checker_.CalledOnValidThread());
  410. if (net_request_ == nullptr)
  411. return;
  412. DCHECK_EQ(net_request_, request);
  413. // Read data from the socket until no bytes left to read.
  414. while (bytes_read > 0) {
  415. // The NSData will take the ownership of |read_buffer_|.
  416. NSData* data =
  417. [NSData dataWithBytesNoCopy:read_buffer_.release() length:bytes_read];
  418. // If the data is not encoded in UTF8, the NSString is nil.
  419. DVLOG(3) << "To client:" << std::endl
  420. << base::SysNSStringToUTF8([[NSString alloc]
  421. initWithData:data
  422. encoding:NSUTF8StringEncoding]);
  423. // Pass the read data to the client.
  424. [client_ didLoadData:data];
  425. // Allocate a new buffer and continue reading from the socket.
  426. AllocateReadBuffer(bytes_read);
  427. bytes_read = request->Read(read_buffer_wrapper_.get(), read_buffer_size_);
  428. }
  429. if (bytes_read == net::OK) {
  430. // If there is nothing more to read.
  431. StopNetRequest();
  432. [client_ didFinishLoading];
  433. } else if (bytes_read != net::ERR_IO_PENDING) {
  434. // If there was an error (not canceled).
  435. int error = bytes_read;
  436. StopRequestWithError(IOSErrorCode(error), error);
  437. }
  438. }
  439. void HttpProtocolHandlerCore::AllocateReadBuffer(int last_read_data_size) {
  440. if (last_read_data_size == read_buffer_size_) {
  441. // If the whole buffer was filled with data then increase the buffer size
  442. // for the next read but don't exceed |kIOBufferMaxSize|.
  443. read_buffer_size_ = std::min(read_buffer_size_ * 2, kIOBufferMaxSize);
  444. } else if (read_buffer_size_ / 2 >= last_read_data_size) {
  445. // If only a half or less of the buffer was filled with data then reduce
  446. // the buffer size for the next read but not make it smaller than
  447. // |kIOBufferMinSize|.
  448. read_buffer_size_ = std::max(read_buffer_size_ / 2, kIOBufferMinSize);
  449. }
  450. read_buffer_.reset(static_cast<char*>(malloc(read_buffer_size_)));
  451. read_buffer_wrapper_ = base::MakeRefCounted<WrappedIOBuffer>(
  452. static_cast<const char*>(read_buffer_.get()));
  453. }
  454. HttpProtocolHandlerCore::~HttpProtocolHandlerCore() {
  455. DCHECK(thread_checker_.CalledOnValidThread());
  456. DCHECK(!net_request_);
  457. DCHECK(!http_body_stream_delegate_);
  458. }
  459. // static
  460. void HttpProtocolHandlerCore::Destruct(const HttpProtocolHandlerCore* x) {
  461. scoped_refptr<base::SingleThreadTaskRunner> task_runner =
  462. g_protocol_handler_delegate->GetDefaultURLRequestContext()
  463. ->GetNetworkTaskRunner();
  464. if (task_runner->BelongsToCurrentThread())
  465. delete x;
  466. else
  467. task_runner->DeleteSoon(FROM_HERE, x);
  468. }
  469. void HttpProtocolHandlerCore::SetLoadFlags() {
  470. DCHECK(thread_checker_.CalledOnValidThread());
  471. int load_flags = LOAD_NORMAL;
  472. switch ([request_ cachePolicy]) {
  473. case NSURLRequestReloadIgnoringLocalAndRemoteCacheData:
  474. load_flags |= LOAD_BYPASS_CACHE;
  475. [[fallthrough]];
  476. case NSURLRequestReloadIgnoringLocalCacheData:
  477. load_flags |= LOAD_DISABLE_CACHE;
  478. break;
  479. case NSURLRequestReturnCacheDataElseLoad:
  480. load_flags |= LOAD_SKIP_CACHE_VALIDATION;
  481. break;
  482. case NSURLRequestReturnCacheDataDontLoad:
  483. load_flags |= LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
  484. break;
  485. case NSURLRequestReloadRevalidatingCacheData:
  486. load_flags |= LOAD_VALIDATE_CACHE;
  487. break;
  488. case NSURLRequestUseProtocolCachePolicy:
  489. // Do nothing, normal load.
  490. break;
  491. }
  492. net_request_->SetLoadFlags(load_flags);
  493. }
  494. void HttpProtocolHandlerCore::Start(id<CRNNetworkClientProtocol> base_client) {
  495. DCHECK(thread_checker_.CalledOnValidThread());
  496. DCHECK(!client_);
  497. DCHECK(base_client);
  498. client_ = base_client;
  499. GURL url = GURLWithNSURL([request_ URL]);
  500. // Now that all of the network clients are set up, if there was an error with
  501. // the URL, it can be raised and all of the clients will have a chance to
  502. // handle it.
  503. if (!url.is_valid()) {
  504. DLOG(ERROR) << "Trying to load an invalid URL: "
  505. << base::SysNSStringToUTF8([[request_ URL] absoluteString]);
  506. [client_ didFailWithNSErrorCode:NSURLErrorBadURL
  507. netErrorCode:ERR_INVALID_URL];
  508. return;
  509. }
  510. const URLRequestContext* context =
  511. g_protocol_handler_delegate->GetDefaultURLRequestContext()
  512. ->GetURLRequestContext();
  513. DCHECK(context);
  514. net_request_ =
  515. context->CreateRequest(url, DEFAULT_PRIORITY, this).release();
  516. net_request_->set_method(base::SysNSStringToUTF8([request_ HTTPMethod]));
  517. net_request_->set_site_for_cookies(
  518. net::SiteForCookies::FromUrl(GURLWithNSURL([request_ mainDocumentURL])));
  519. #if !defined(NDEBUG)
  520. DVLOG(2) << "From client:";
  521. LogNSURLRequest(request_);
  522. #endif // !defined(NDEBUG)
  523. CopyHttpHeaders(request_, net_request_);
  524. [client_ didCreateNativeRequest:net_request_];
  525. SetLoadFlags();
  526. net_request_->set_allow_credentials([request_ HTTPShouldHandleCookies]);
  527. // https://crbug.com/979324 If the application app sets HTTPBody, then system
  528. // creates new NSInputStream every time HTTPBodyStream is called. Get the
  529. // stream here and hold on to it.
  530. http_body_stream_ = [request_ HTTPBodyStream];
  531. if (http_body_stream_) {
  532. DCHECK(![request_ HTTPBody]);
  533. http_body_stream_delegate_ =
  534. [[CRWHTTPStreamDelegate alloc] initWithHttpProtocolHandlerCore:this];
  535. [http_body_stream_ setDelegate:http_body_stream_delegate_];
  536. DVLOG(1) << "input_stream " << http_body_stream_ << " delegate "
  537. << [http_body_stream_ delegate];
  538. [http_body_stream_ scheduleInRunLoop:[NSRunLoop currentRunLoop]
  539. forMode:NSDefaultRunLoopMode];
  540. [http_body_stream_ open];
  541. if (net_request_->extra_request_headers().HasHeader(
  542. HttpRequestHeaders::kContentLength)) {
  543. // The request will be started when the stream is fully read.
  544. return;
  545. }
  546. std::unique_ptr<ChunkedDataStreamUploader> uploader =
  547. std::make_unique<ChunkedDataStreamUploader>(this);
  548. chunked_uploader_ = uploader->GetWeakPtr();
  549. net_request_->set_upload(std::move(uploader));
  550. } else if ([request_ HTTPBody]) {
  551. DVLOG(1) << "HTTPBody " << [request_ HTTPBody];
  552. NSData* body = [request_ HTTPBody];
  553. const NSUInteger body_length = [body length];
  554. if (body_length > 0) {
  555. const char* source_bytes = reinterpret_cast<const char*>([body bytes]);
  556. std::vector<char> owned_data(source_bytes, source_bytes + body_length);
  557. std::unique_ptr<UploadElementReader> reader(
  558. new UploadOwnedBytesElementReader(&owned_data));
  559. net_request_->set_upload(
  560. ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
  561. }
  562. }
  563. net_request_->Start();
  564. }
  565. void HttpProtocolHandlerCore::Cancel() {
  566. DCHECK(thread_checker_.CalledOnValidThread());
  567. if (net_request_ == nullptr)
  568. return;
  569. DVLOG(2) << "Client canceling request: " << net_request_->url().spec();
  570. net_request_->Cancel();
  571. StopNetRequest();
  572. }
  573. void HttpProtocolHandlerCore::StopNetRequest() {
  574. DCHECK(thread_checker_.CalledOnValidThread());
  575. if (g_metrics_delegate) {
  576. auto metrics = std::make_unique<net::MetricsDelegate::Metrics>();
  577. metrics->response_end_time = base::Time::Now();
  578. metrics->task = task_;
  579. metrics->response_info = net_request_->response_info();
  580. net_request_->GetLoadTimingInfo(&metrics->load_timing_info);
  581. g_metrics_delegate->OnStopNetRequest(std::move(metrics));
  582. }
  583. delete net_request_;
  584. net_request_ = nullptr;
  585. if (http_body_stream_)
  586. StopListeningStream(http_body_stream_);
  587. }
  588. void HttpProtocolHandlerCore::StopListeningStream(NSStream* stream) {
  589. DVLOG(1) << "StopListeningStream " << stream << " delegate "
  590. << [stream delegate];
  591. DCHECK(thread_checker_.CalledOnValidThread());
  592. DCHECK(stream);
  593. DCHECK(http_body_stream_delegate_);
  594. DCHECK([stream delegate] == http_body_stream_delegate_);
  595. if (stream != http_body_stream_)
  596. return;
  597. [stream setDelegate:nil];
  598. [stream removeFromRunLoop:[NSRunLoop currentRunLoop]
  599. forMode:NSDefaultRunLoopMode];
  600. http_body_stream_delegate_ = nil;
  601. http_body_stream_ = nil;
  602. // Close the stream if needed.
  603. switch ([stream streamStatus]) {
  604. case NSStreamStatusOpening:
  605. case NSStreamStatusOpen:
  606. case NSStreamStatusReading:
  607. case NSStreamStatusWriting:
  608. case NSStreamStatusAtEnd:
  609. [stream close];
  610. break;
  611. case NSStreamStatusNotOpen:
  612. case NSStreamStatusClosed:
  613. case NSStreamStatusError:
  614. break;
  615. default:
  616. NOTREACHED() << "Unexpected stream status: " << [stream streamStatus];
  617. break;
  618. }
  619. }
  620. NSInteger HttpProtocolHandlerCore::IOSErrorCode(int os_error) {
  621. DCHECK(thread_checker_.CalledOnValidThread());
  622. switch (os_error) {
  623. case ERR_SSL_PROTOCOL_ERROR:
  624. return NSURLErrorClientCertificateRequired;
  625. case ERR_CONNECTION_RESET:
  626. case ERR_NETWORK_CHANGED:
  627. return NSURLErrorNetworkConnectionLost;
  628. case ERR_UNEXPECTED:
  629. return NSURLErrorUnknown;
  630. default:
  631. return NSURLErrorCannotConnectToHost;
  632. }
  633. }
  634. void HttpProtocolHandlerCore::StopRequestWithError(NSInteger ns_error_code,
  635. int net_error_code) {
  636. DCHECK(net_request_ != nullptr);
  637. DCHECK(thread_checker_.CalledOnValidThread());
  638. // Don't show an error message on ERR_ABORTED because this is error is often
  639. // fired when switching profiles.
  640. DLOG_IF(ERROR, net_error_code != ERR_ABORTED)
  641. << "HttpProtocolHandlerCore - Network error: "
  642. << ErrorToString(net_error_code) << " (" << net_error_code << ")";
  643. [client_ didFailWithNSErrorCode:ns_error_code netErrorCode:net_error_code];
  644. StopNetRequest();
  645. }
  646. void HttpProtocolHandlerCore::StripPostSpecificHeaders(
  647. NSMutableURLRequest* request) {
  648. DCHECK(thread_checker_.CalledOnValidThread());
  649. DCHECK(request);
  650. [request setValue:nil forHTTPHeaderField:base::SysUTF8ToNSString(
  651. HttpRequestHeaders::kContentLength)];
  652. [request setValue:nil forHTTPHeaderField:base::SysUTF8ToNSString(
  653. HttpRequestHeaders::kContentType)];
  654. [request setValue:nil forHTTPHeaderField:base::SysUTF8ToNSString(
  655. HttpRequestHeaders::kOrigin)];
  656. }
  657. int HttpProtocolHandlerCore::OnRead(char* buffer, int buffer_length) {
  658. int bytes_read = 0;
  659. if (http_body_stream_) {
  660. // NSInputStream read() blocks the thread until there is at least one byte
  661. // available, so check the status before call read().
  662. if (![http_body_stream_ hasBytesAvailable])
  663. return ERR_IO_PENDING;
  664. bytes_read =
  665. [http_body_stream_ read:reinterpret_cast<unsigned char*>(buffer)
  666. maxLength:buffer_length];
  667. // NSInputStream can read 0 byte when hasBytesAvailable is true, so do not
  668. // treat it as a failure.
  669. if (bytes_read < 0) {
  670. // If NSInputStream meets an error on read(), fail the request
  671. // immediately.
  672. DLOG(ERROR) << "Failed to read POST data: "
  673. << base::SysNSStringToUTF8(
  674. [[http_body_stream_ streamError] description]);
  675. StopListeningStream(http_body_stream_);
  676. StopRequestWithError(NSURLErrorUnknown, ERR_UNEXPECTED);
  677. return ERR_UNEXPECTED;
  678. }
  679. }
  680. return bytes_read;
  681. }
  682. } // namespace net
  683. #pragma mark -
  684. #pragma mark CRWHTTPStreamDelegate
  685. @implementation CRWHTTPStreamDelegate
  686. - (instancetype)initWithHttpProtocolHandlerCore:
  687. (net::HttpProtocolHandlerCore*)core {
  688. DCHECK(core);
  689. self = [super init];
  690. if (self)
  691. _core = core;
  692. return self;
  693. }
  694. - (void)stream:(NSStream*)theStream handleEvent:(NSStreamEvent)streamEvent {
  695. _core->HandleStreamEvent(theStream, streamEvent);
  696. }
  697. @end
  698. #pragma mark -
  699. #pragma mark DeferredCancellation
  700. // An object of class |DeferredCancellation| represents a deferred cancellation
  701. // of a request. In principle this is a block posted to a thread's runloop, but
  702. // since there is no performBlock:onThread:, this class wraps the desired
  703. // behavior in an object.
  704. @interface DeferredCancellation : NSObject
  705. - (instancetype)initWithCore:(scoped_refptr<net::HttpProtocolHandlerCore>)core;
  706. - (void)cancel;
  707. @end
  708. @implementation DeferredCancellation {
  709. scoped_refptr<net::HttpProtocolHandlerCore> _core;
  710. }
  711. - (instancetype)initWithCore:(scoped_refptr<net::HttpProtocolHandlerCore>)core {
  712. if ((self = [super init])) {
  713. _core = core;
  714. }
  715. return self;
  716. }
  717. - (void)cancel {
  718. g_protocol_handler_delegate->GetDefaultURLRequestContext()
  719. ->GetNetworkTaskRunner()
  720. ->PostTask(FROM_HERE,
  721. base::BindOnce(&net::HttpProtocolHandlerCore::Cancel, _core));
  722. }
  723. @end
  724. #pragma mark -
  725. #pragma mark HttpProtocolHandler
  726. @interface CRNHTTPProtocolHandler (Private)
  727. - (void)ensureProtocolHandlerProxyCreated;
  728. - (void)cancelRequest;
  729. @end
  730. // The HttpProtocolHandler is called by the iOS system to handle the
  731. // NSURLRequest.
  732. @implementation CRNHTTPProtocolHandler {
  733. scoped_refptr<net::HttpProtocolHandlerCore> _core;
  734. id<CRNHTTPProtocolHandlerProxy> _protocolProxy;
  735. __weak NSThread* _clientThread;
  736. BOOL _supportedURL;
  737. NSURLSessionTask* _task;
  738. }
  739. #pragma mark NSURLProtocol methods
  740. + (BOOL)canInitWithRequest:(NSURLRequest*)request {
  741. DVLOG(5) << "canInitWithRequest " << net::FormatUrlRequestForLogging(request);
  742. return g_protocol_handler_delegate->CanHandleRequest(request);
  743. }
  744. + (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)request {
  745. // TODO(droger): Is this used if we disable the cache of UIWebView? If it is,
  746. // then we need a real implementation, even though Chrome network stack does
  747. // not need it (GURLs are automatically canonized).
  748. return request;
  749. }
  750. - (instancetype)initWithRequest:(NSURLRequest*)request
  751. cachedResponse:(NSCachedURLResponse*)cachedResponse
  752. client:(id<NSURLProtocolClient>)client {
  753. DCHECK(!cachedResponse);
  754. self = [super initWithRequest:request
  755. cachedResponse:cachedResponse
  756. client:client];
  757. if (self) {
  758. _supportedURL = g_protocol_handler_delegate->IsRequestSupported(request);
  759. _core = new net::HttpProtocolHandlerCore(request);
  760. }
  761. return self;
  762. }
  763. - (instancetype)initWithTask:(NSURLSessionTask*)task
  764. cachedResponse:(NSCachedURLResponse*)cachedResponse
  765. client:(id<NSURLProtocolClient>)client {
  766. DCHECK(!cachedResponse);
  767. self = [super initWithTask:task cachedResponse:cachedResponse client:client];
  768. if (self) {
  769. _supportedURL =
  770. g_protocol_handler_delegate->IsRequestSupported(task.currentRequest);
  771. _core = new net::HttpProtocolHandlerCore(task);
  772. _task = task;
  773. }
  774. return self;
  775. }
  776. #pragma mark NSURLProtocol overrides.
  777. - (NSCachedURLResponse*)cachedResponse {
  778. // We do not use the UIWebView cache.
  779. // TODO(droger): Disable the UIWebView cache.
  780. return nil;
  781. }
  782. - (void)startLoading {
  783. // If the scheme is not valid, just return an error right away.
  784. if (!_supportedURL) {
  785. NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
  786. // It is possible for URL to be nil, so check for that
  787. // before creating the error object. See http://crbug/349051
  788. NSURL* url = [[self request] URL];
  789. if (url)
  790. [dictionary setObject:url forKey:NSURLErrorKey];
  791. NSError* error = [NSError errorWithDomain:NSURLErrorDomain
  792. code:NSURLErrorUnsupportedURL
  793. userInfo:dictionary];
  794. [[self client] URLProtocol:self didFailWithError:error];
  795. return;
  796. }
  797. _clientThread = [NSThread currentThread];
  798. if (g_metrics_delegate) {
  799. g_metrics_delegate->OnStartNetRequest(_task);
  800. }
  801. // The closure passed to PostTask must to retain the _protocolProxy
  802. // scoped_nsobject. A call to ensureProtocolHandlerProxyCreated before passing
  803. // _protocolProxy ensure that _protocolProxy is instanciated before passing
  804. // it.
  805. [self ensureProtocolHandlerProxyCreated];
  806. DCHECK(_protocolProxy);
  807. g_protocol_handler_delegate->GetDefaultURLRequestContext()
  808. ->GetNetworkTaskRunner()
  809. ->PostTask(FROM_HERE, base::BindOnce(&net::HttpProtocolHandlerCore::Start,
  810. _core, _protocolProxy));
  811. }
  812. - (void)ensureProtocolHandlerProxyCreated {
  813. DCHECK_EQ([NSThread currentThread], _clientThread);
  814. if (!_protocolProxy) {
  815. _protocolProxy = [[CRNHTTPProtocolHandlerProxyWithClientThread alloc]
  816. initWithProtocol:self
  817. clientThread:_clientThread
  818. runLoopMode:[[NSRunLoop currentRunLoop] currentMode]];
  819. }
  820. }
  821. - (void)cancelRequest {
  822. g_protocol_handler_delegate->GetDefaultURLRequestContext()
  823. ->GetNetworkTaskRunner()
  824. ->PostTask(FROM_HERE,
  825. base::BindOnce(&net::HttpProtocolHandlerCore::Cancel, _core));
  826. [_protocolProxy invalidate];
  827. }
  828. - (void)stopLoading {
  829. [self cancelRequest];
  830. _protocolProxy = nil;
  831. }
  832. @end