1 // Copyright 2013 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 5 #include "content/renderer/media/android/media_info_loader.h" 6 7 #include "base/bits.h" 8 #include "base/callback_helpers.h" 9 #include "base/metrics/histogram.h" 10 #include "third_party/WebKit/public/platform/WebURLError.h" 11 #include "third_party/WebKit/public/platform/WebURLLoader.h" 12 #include "third_party/WebKit/public/platform/WebURLResponse.h" 13 #include "third_party/WebKit/public/web/WebFrame.h" 14 15 using blink::WebFrame; 16 using blink::WebURLError; 17 using blink::WebURLLoader; 18 using blink::WebURLLoaderOptions; 19 using blink::WebURLRequest; 20 using blink::WebURLResponse; 21 22 namespace content { 23 24 static const int kHttpOK = 200; 25 26 MediaInfoLoader::MediaInfoLoader( 27 const GURL& url, 28 blink::WebMediaPlayer::CORSMode cors_mode, 29 const ReadyCB& ready_cb) 30 : loader_failed_(false), 31 url_(url), 32 cors_mode_(cors_mode), 33 single_origin_(true), 34 ready_cb_(ready_cb) {} 35 36 MediaInfoLoader::~MediaInfoLoader() {} 37 38 void MediaInfoLoader::Start(blink::WebFrame* frame) { 39 // Make sure we have not started. 40 DCHECK(!ready_cb_.is_null()); 41 CHECK(frame); 42 43 start_time_ = base::TimeTicks::Now(); 44 45 // Prepare the request. 46 WebURLRequest request(url_); 47 request.setTargetType(WebURLRequest::TargetIsMedia); 48 frame->setReferrerForRequest(request, blink::WebURL()); 49 50 scoped_ptr<WebURLLoader> loader; 51 if (test_loader_) { 52 loader = test_loader_.Pass(); 53 } else { 54 WebURLLoaderOptions options; 55 if (cors_mode_ == blink::WebMediaPlayer::CORSModeUnspecified) { 56 options.allowCredentials = true; 57 options.crossOriginRequestPolicy = 58 WebURLLoaderOptions::CrossOriginRequestPolicyAllow; 59 } else { 60 options.exposeAllResponseHeaders = true; 61 // The author header set is empty, no preflight should go ahead. 62 options.preflightPolicy = WebURLLoaderOptions::PreventPreflight; 63 options.crossOriginRequestPolicy = 64 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; 65 if (cors_mode_ == blink::WebMediaPlayer::CORSModeUseCredentials) 66 options.allowCredentials = true; 67 } 68 loader.reset(frame->createAssociatedURLLoader(options)); 69 } 70 71 // Start the resource loading. 72 loader->loadAsynchronously(request, this); 73 active_loader_.reset(new ActiveLoader(loader.Pass())); 74 } 75 76 ///////////////////////////////////////////////////////////////////////////// 77 // blink::WebURLLoaderClient implementation. 78 void MediaInfoLoader::willSendRequest( 79 WebURLLoader* loader, 80 WebURLRequest& newRequest, 81 const WebURLResponse& redirectResponse) { 82 // The load may have been stopped and |ready_cb| is destroyed. 83 // In this case we shouldn't do anything. 84 if (ready_cb_.is_null()) { 85 // Set the url in the request to an invalid value (empty url). 86 newRequest.setURL(blink::WebURL()); 87 return; 88 } 89 90 // Only allow |single_origin_| if we haven't seen a different origin yet. 91 if (single_origin_) 92 single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin(); 93 94 url_ = newRequest.url(); 95 } 96 97 void MediaInfoLoader::didSendData( 98 WebURLLoader* loader, 99 unsigned long long bytes_sent, 100 unsigned long long total_bytes_to_be_sent) { 101 NOTIMPLEMENTED(); 102 } 103 104 void MediaInfoLoader::didReceiveResponse( 105 WebURLLoader* loader, 106 const WebURLResponse& response) { 107 DVLOG(1) << "didReceiveResponse: HTTP/" 108 << (response.httpVersion() == WebURLResponse::HTTP_0_9 ? "0.9" : 109 response.httpVersion() == WebURLResponse::HTTP_1_0 ? "1.0" : 110 response.httpVersion() == WebURLResponse::HTTP_1_1 ? "1.1" : 111 "Unknown") 112 << " " << response.httpStatusCode(); 113 DCHECK(active_loader_.get()); 114 if (!url_.SchemeIs("http") && !url_.SchemeIs("https")) { 115 DidBecomeReady(kOk); 116 return; 117 } 118 if (response.httpStatusCode() == kHttpOK) { 119 DidBecomeReady(kOk); 120 return; 121 } 122 loader_failed_ = true; 123 DidBecomeReady(kFailed); 124 } 125 126 void MediaInfoLoader::didReceiveData( 127 WebURLLoader* loader, 128 const char* data, 129 int data_length, 130 int encoded_data_length) { 131 // Ignored. 132 } 133 134 void MediaInfoLoader::didDownloadData( 135 blink::WebURLLoader* loader, 136 int dataLength, 137 int encodedDataLength) { 138 NOTIMPLEMENTED(); 139 } 140 141 void MediaInfoLoader::didReceiveCachedMetadata( 142 WebURLLoader* loader, 143 const char* data, 144 int data_length) { 145 NOTIMPLEMENTED(); 146 } 147 148 void MediaInfoLoader::didFinishLoading( 149 WebURLLoader* loader, 150 double finishTime) { 151 DCHECK(active_loader_.get()); 152 DidBecomeReady(kOk); 153 } 154 155 void MediaInfoLoader::didFail( 156 WebURLLoader* loader, 157 const WebURLError& error) { 158 DVLOG(1) << "didFail: reason=" << error.reason 159 << ", isCancellation=" << error.isCancellation 160 << ", domain=" << error.domain.utf8().data() 161 << ", localizedDescription=" 162 << error.localizedDescription.utf8().data(); 163 DCHECK(active_loader_.get()); 164 loader_failed_ = true; 165 DidBecomeReady(kFailed); 166 } 167 168 bool MediaInfoLoader::HasSingleOrigin() const { 169 DCHECK(ready_cb_.is_null()) 170 << "Must become ready before calling HasSingleOrigin()"; 171 return single_origin_; 172 } 173 174 bool MediaInfoLoader::DidPassCORSAccessCheck() const { 175 DCHECK(ready_cb_.is_null()) 176 << "Must become ready before calling DidPassCORSAccessCheck()"; 177 return !loader_failed_ && 178 cors_mode_ != blink::WebMediaPlayer::CORSModeUnspecified; 179 } 180 181 ///////////////////////////////////////////////////////////////////////////// 182 // Helper methods. 183 184 void MediaInfoLoader::DidBecomeReady(Status status) { 185 UMA_HISTOGRAM_TIMES("Media.InfoLoadDelay", 186 base::TimeTicks::Now() - start_time_); 187 active_loader_.reset(); 188 if (!ready_cb_.is_null()) 189 base::ResetAndReturn(&ready_cb_).Run(status); 190 } 191 192 } // namespace content 193