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

Side by Side Diff: chrome_frame/npapi_url_request.cc

Issue 7276037: Remove NPAPI support from Chrome Frame. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "chrome_frame/npapi_url_request.h"
6
7 #include "base/string_number_conversions.h"
8 #include "base/threading/platform_thread.h"
9 #include "chrome/common/automation_messages.h"
10 #include "chrome_frame/chrome_frame_npapi.h"
11 #include "chrome_frame/np_browser_functions.h"
12 #include "chrome_frame/np_utils.h"
13 #include "net/base/net_errors.h"
14
15 class NPAPIUrlRequest : public PluginUrlRequest {
16 public:
17 explicit NPAPIUrlRequest(NPP instance);
18 ~NPAPIUrlRequest();
19
20 virtual bool Start();
21 virtual void Stop();
22 virtual bool Read(int bytes_to_read);
23
24 // Called from NPAPI
25 NPError OnStreamCreated(const char* mime_type, NPStream* stream);
26 NPError OnStreamDestroyed(NPReason reason);
27 int OnWriteReady();
28 int OnWrite(void* buffer, int len);
29
30 // Thread unsafe implementation of ref counting, since
31 // this will be called on the plugin UI thread only.
32 virtual unsigned long API_CALL AddRef();
33 virtual unsigned long API_CALL Release();
34
35 const net::URLRequestStatus& status() const {
36 return status_;
37 }
38
39 NPP instance() const {
40 return instance_;
41 }
42
43 private:
44 unsigned long ref_count_;
45 NPP instance_;
46 NPStream* stream_;
47 size_t pending_read_size_;
48 net::URLRequestStatus status_;
49
50 base::PlatformThreadId thread_;
51 static int instance_count_;
52 DISALLOW_COPY_AND_ASSIGN(NPAPIUrlRequest);
53 };
54
55 int NPAPIUrlRequest::instance_count_ = 0;
56
57 NPAPIUrlRequest::NPAPIUrlRequest(NPP instance)
58 : ref_count_(0), instance_(instance), stream_(NULL),
59 pending_read_size_(0),
60 status_(net::URLRequestStatus::FAILED, net::ERR_FAILED),
61 thread_(base::PlatformThread::CurrentId()) {
62 DVLOG(1) << "Created request. Count: " << ++instance_count_;
63 }
64
65 NPAPIUrlRequest::~NPAPIUrlRequest() {
66 DVLOG(1) << "Deleted request. Count: " << --instance_count_;
67 }
68
69 // NPAPIUrlRequest member defines.
70 bool NPAPIUrlRequest::Start() {
71 NPError result = NPERR_GENERIC_ERROR;
72 DVLOG(1) << "Starting URL request: " << url();
73 // Initialize the net::HostPortPair structure from the url
74 socket_address_ = net::HostPortPair::FromURL(GURL(url()));
75
76 if (LowerCaseEqualsASCII(method(), "get")) {
77 // TODO(joshia): if we have extra headers for HTTP GET, then implement
78 // it using XHR
79 result = npapi::GetURLNotify(instance_, url().c_str(), NULL, this);
80 } else if (LowerCaseEqualsASCII(method(), "post")) {
81 uint32 data_len = static_cast<uint32>(post_data_len());
82
83 std::string buffer;
84 if (extra_headers().length() > 0) {
85 buffer += extra_headers();
86 TrimWhitespace(buffer, TRIM_ALL, &buffer);
87
88 // Firefox looks specifically for "Content-length: \d+\r\n\r\n"
89 // to detect if extra headers are added to the message buffer.
90 buffer += "\r\nContent-length: ";
91 buffer += base::IntToString(data_len);
92 buffer += "\r\n\r\n";
93 }
94
95 std::string data;
96 data.resize(data_len);
97 uint32 bytes_read;
98 upload_data_->Read(&data[0], data_len,
99 reinterpret_cast<ULONG*>(&bytes_read));
100 DCHECK_EQ(data_len, bytes_read);
101 buffer += data;
102
103 result = npapi::PostURLNotify(instance_, url().c_str(), NULL,
104 buffer.length(), buffer.c_str(), false, this);
105 } else {
106 NOTREACHED() << "PluginUrlRequest only supports 'GET'/'POST'";
107 }
108
109 if (NPERR_NO_ERROR != result) {
110 int os_error = net::ERR_FAILED;
111 switch (result) {
112 case NPERR_INVALID_URL:
113 os_error = net::ERR_INVALID_URL;
114 break;
115 default:
116 break;
117 }
118
119 delegate_->OnResponseEnd(id(),
120 net::URLRequestStatus(net::URLRequestStatus::FAILED, os_error));
121 return false;
122 }
123
124 return true;
125 }
126
127 void NPAPIUrlRequest::Stop() {
128 DVLOG(1) << "Finished request: Url - " << url()
129 << " result: " << static_cast<int>(status_.status());
130
131 status_.set_status(net::URLRequestStatus::CANCELED);
132 if (stream_) {
133 npapi::DestroyStream(instance_, stream_, NPRES_USER_BREAK);
134 stream_ = NULL;
135 }
136 }
137
138 bool NPAPIUrlRequest::Read(int bytes_to_read) {
139 pending_read_size_ = bytes_to_read;
140 return true;
141 }
142
143 NPError NPAPIUrlRequest::OnStreamCreated(const char* mime_type,
144 NPStream* stream) {
145 stream_ = stream;
146 status_.set_status(net::URLRequestStatus::IO_PENDING);
147 // TODO(iyengar)
148 // Add support for passing persistent cookies and information about any URL
149 // redirects to Chrome.
150 delegate_->OnResponseStarted(id(), mime_type, stream->headers, stream->end,
151 base::Time::FromTimeT(stream->lastmodified), std::string(), 0,
152 socket_address_);
153 return NPERR_NO_ERROR;
154 }
155
156 NPError NPAPIUrlRequest::OnStreamDestroyed(NPReason reason) {
157 // If the request has been aborted, then ignore the |reason| argument.
158 // Normally the execution flow is such than NPRES_USER_BREAK will be passed
159 // when the stream is aborted, but sometimes NPRES_NETWORK_ERROR is passed
160 // instead. To prevent Chrome from receiving a notification of a failed
161 // network connection, when Chrome actually canceled the request, we ignore
162 // the status here.
163 if (net::URLRequestStatus::CANCELED != status_.status()) {
164 switch (reason) {
165 case NPRES_DONE:
166 status_.set_status(net::URLRequestStatus::SUCCESS);
167 status_.set_os_error(0);
168 break;
169 case NPRES_USER_BREAK:
170 status_.set_status(net::URLRequestStatus::CANCELED);
171 status_.set_os_error(net::ERR_ABORTED);
172 break;
173 case NPRES_NETWORK_ERR:
174 default:
175 status_.set_status(net::URLRequestStatus::FAILED);
176 status_.set_os_error(net::ERR_CONNECTION_CLOSED);
177 break;
178 }
179 }
180
181 delegate_->OnResponseEnd(id(), status_);
182 return NPERR_NO_ERROR;
183 }
184
185 int NPAPIUrlRequest::OnWriteReady() {
186 return pending_read_size_;
187 }
188
189 int NPAPIUrlRequest::OnWrite(void* buffer, int len) {
190 pending_read_size_ = 0;
191 std::string data(reinterpret_cast<char*>(buffer), len);
192 delegate_->OnReadComplete(id(), data);
193 return len;
194 }
195
196 STDMETHODIMP_(ULONG) NPAPIUrlRequest::AddRef() {
197 DCHECK_EQ(base::PlatformThread::CurrentId(), thread_);
198 ++ref_count_;
199 return ref_count_;
200 }
201
202 STDMETHODIMP_(ULONG) NPAPIUrlRequest::Release() {
203 DCHECK_EQ(base::PlatformThread::CurrentId(), thread_);
204 unsigned long ret = --ref_count_;
205 if (!ret)
206 delete this;
207
208 return ret;
209 }
210
211 NPAPIUrlRequestManager::NPAPIUrlRequestManager() : instance_(NULL) {
212 }
213
214 NPAPIUrlRequestManager::~NPAPIUrlRequestManager() {
215 StopAll();
216 }
217
218 // PluginUrlRequestManager implementation
219 PluginUrlRequestManager::ThreadSafeFlags
220 NPAPIUrlRequestManager::GetThreadSafeFlags() {
221 return PluginUrlRequestManager::NOT_THREADSAFE;
222 }
223
224 void NPAPIUrlRequestManager::StartRequest(int request_id,
225 const AutomationURLRequest& request_info) {
226 scoped_refptr<NPAPIUrlRequest> new_request(new NPAPIUrlRequest(instance_));
227 DCHECK(new_request);
228 if (new_request->Initialize(this, request_id, request_info.url,
229 request_info.method, request_info.referrer,
230 request_info.extra_request_headers,
231 request_info.upload_data,
232 static_cast<ResourceType::Type>(request_info.resource_type),
233 enable_frame_busting_,
234 request_info.load_flags)) {
235 DCHECK(request_map_.find(request_id) == request_map_.end());
236 if (new_request->Start()) {
237 request_map_[request_id] = new_request;
238 // Keep additional reference on request for NPSTREAM
239 // This will be released in NPP_UrlNotify
240 new_request->AddRef();
241 }
242 }
243 }
244
245 void NPAPIUrlRequestManager::ReadRequest(int request_id, int bytes_to_read) {
246 scoped_refptr<NPAPIUrlRequest> request = LookupRequest(request_id);
247 if (request)
248 request->Read(bytes_to_read);
249 }
250
251 void NPAPIUrlRequestManager::EndRequest(int request_id) {
252 scoped_refptr<NPAPIUrlRequest> request = LookupRequest(request_id);
253 if (request)
254 request->Stop();
255 }
256
257 void NPAPIUrlRequestManager::StopAll() {
258 std::vector<scoped_refptr<NPAPIUrlRequest> > request_list;
259 // We copy the pending requests into a temporary vector as the Stop
260 // function in the request could also try to delete the request from
261 // the request map and the iterator could end up being invalid.
262 for (RequestMap::iterator it = request_map_.begin();
263 it != request_map_.end(); ++it) {
264 DCHECK(it->second != NULL);
265 request_list.push_back(it->second);
266 }
267
268 for (std::vector<scoped_refptr<NPAPIUrlRequest> >::size_type index = 0;
269 index < request_list.size(); ++index) {
270 request_list[index]->Stop();
271 }
272 }
273
274 void NPAPIUrlRequestManager::SetCookiesForUrl(const GURL& url,
275 const std::string& cookie) {
276 if (npapi::VersionMinor() >= NPVERS_HAS_URL_AND_AUTH_INFO) {
277 npapi::SetValueForURL(instance_, NPNURLVCookie, url.spec().c_str(),
278 cookie.c_str(), cookie.length());
279 } else {
280 NOTREACHED() << "Unsupported version";
281 }
282 }
283
284 void NPAPIUrlRequestManager::GetCookiesForUrl(const GURL& url, int cookie_id) {
285 std::string cookie_string;
286 bool success = false;
287
288 if (npapi::VersionMinor() >= NPVERS_HAS_URL_AND_AUTH_INFO) {
289 char* cookies = NULL;
290 unsigned int cookie_length = 0;
291 NPError ret = npapi::GetValueForURL(instance_, NPNURLVCookie,
292 url.spec().c_str(), &cookies,
293 &cookie_length);
294 if (ret == NPERR_NO_ERROR) {
295 DVLOG(1) << "Obtained cookies:" << cookies << " from host";
296 cookie_string.append(cookies, cookie_length);
297 npapi::MemFree(cookies);
298 success = true;
299 }
300 } else {
301 NOTREACHED() << "Unsupported version";
302 }
303
304 if (!success)
305 DVLOG(1) << "Failed to return cookies for url:" << url.spec();
306
307 OnCookiesRetrieved(success, url, cookie_string, cookie_id);
308 }
309
310 // PluginRequestDelegate implementation.
311 // Callbacks from NPAPIUrlRequest. Simply forward to the delegate.
312 void NPAPIUrlRequestManager::OnResponseStarted(int request_id,
313 const char* mime_type, const char* headers, int size,
314 base::Time last_modified, const std::string& redirect_url,
315 int redirect_status, const net::HostPortPair& socket_address) {
316 delegate_->OnResponseStarted(request_id, mime_type, headers, size,
317 last_modified, redirect_url, redirect_status, socket_address);
318 }
319
320 void NPAPIUrlRequestManager::OnReadComplete(int request_id,
321 const std::string& data) {
322 delegate_->OnReadComplete(request_id, data);
323 }
324
325 void NPAPIUrlRequestManager::OnResponseEnd(
326 int request_id,
327 const net::URLRequestStatus& status) {
328 // Delete from map.
329 RequestMap::iterator it = request_map_.find(request_id);
330 DCHECK(request_map_.end() != it);
331 scoped_refptr<NPAPIUrlRequest> request = (*it).second;
332 request_map_.erase(it);
333
334 // Inform delegate unless canceled.
335 if (status.status() != net::URLRequestStatus::CANCELED)
336 delegate_->OnResponseEnd(request_id, status);
337 }
338
339 void NPAPIUrlRequestManager::OnCookiesRetrieved(bool success, const GURL& url,
340 const std::string& cookie_string, int cookie_id) {
341 delegate_->OnCookiesRetrieved(success, url, cookie_string, cookie_id);
342 }
343
344 // Notifications from browser. Find the NPAPIUrlRequest and forward to it.
345 NPError NPAPIUrlRequestManager::NewStream(NPMIMEType type,
346 NPStream* stream,
347 NPBool seekable,
348 uint16* stream_type) {
349 NPAPIUrlRequest* request = RequestFromNotifyData(stream->notifyData);
350 if (!request)
351 return NPERR_NO_ERROR;
352
353 // This stream is being constructed for a request that has already been
354 // canceled. Signal its immediate termination.
355 if (net::URLRequestStatus::CANCELED == request->status().status()) {
356 return npapi::DestroyStream(request->instance(),
357 stream, NPRES_USER_BREAK);
358 }
359
360 DCHECK(request_map_.find(request->id()) != request_map_.end());
361
362 // If the host browser does not support the NPAPI redirect notification
363 // spec, and if the request URL is implicitly redirected, we need to
364 // inform Chrome about the redirect and allow it to follow the redirect.
365 // We achieve this by comparing the URL requested with the URL received in
366 // the response and if they don't match we assume a redirect. This would have
367 // a sideffect that two GET requests would be sent out in this case.
368 if (!BrowserSupportsRedirectNotification()) {
369 if (GURL(request->url().c_str()) != GURL(stream->url)) {
370 DVLOG(1) << "Request URL:"
371 << request->url()
372 << " was redirected to:"
373 << stream->url;
374 delegate_->OnResponseStarted(
375 request->id(), "", "", 0, base::Time(), stream->url, 302,
376 net::HostPortPair(net::HostPortPair::FromURL(GURL(stream->url))));
377 return NPERR_GENERIC_ERROR;
378 }
379 }
380 // We need to return the requested stream mode if we are returning a success
381 // code. If we don't do this it causes Opera to blow up.
382 *stream_type = NP_NORMAL;
383 return request->OnStreamCreated(type, stream);
384 }
385
386 int32 NPAPIUrlRequestManager::WriteReady(NPStream* stream) {
387 NPAPIUrlRequest* request = RequestFromNotifyData(stream->notifyData);
388 if (!request)
389 return 0x7FFFFFFF;
390 DCHECK(request_map_.find(request->id()) != request_map_.end());
391 return request->OnWriteReady();
392 }
393
394 int32 NPAPIUrlRequestManager::Write(NPStream* stream, int32 offset,
395 int32 len, void* buffer) {
396 NPAPIUrlRequest* request = RequestFromNotifyData(stream->notifyData);
397 if (!request)
398 return len;
399 DCHECK(request_map_.find(request->id()) != request_map_.end());
400 return request->OnWrite(buffer, len);
401 }
402
403 NPError NPAPIUrlRequestManager::DestroyStream(NPStream* stream,
404 NPReason reason) {
405 NPAPIUrlRequest* request = RequestFromNotifyData(stream->notifyData);
406 if (!request)
407 return NPERR_NO_ERROR;
408
409 // It is possible to receive notification of a destroyed stream for a
410 // unregistered request: EndRequest will unregister a request in response
411 // to an AutomationMsg_RequestEnd message. EndRequest will also invoke
412 // npapi::DestroyStream, which will call back to this function.
413 if (request_map_.find(request->id()) != request_map_.end())
414 return request->OnStreamDestroyed(reason);
415
416 return NPERR_NO_ERROR;
417 }
418
419 void NPAPIUrlRequestManager::UrlNotify(const char* url, NPReason reason,
420 void* notify_data) {
421 NPAPIUrlRequest* request = RequestFromNotifyData(notify_data);
422 DCHECK(request != NULL);
423 if (request) {
424 request->Stop();
425 request->Release();
426 }
427 }
428
429 void NPAPIUrlRequestManager::UrlRedirectNotify(const char* url, int status,
430 void* notify_data) {
431 NPAPIUrlRequest* request = RequestFromNotifyData(notify_data);
432 if (request) {
433 delegate_->OnResponseStarted(
434 request->id(), "", "", 0, base::Time(), url, status,
435 net::HostPortPair(net::HostPortPair::FromURL(GURL(url))));
436 } else {
437 NOTREACHED() << "Received unexpected redirect notification for url:"
438 << url;
439 }
440 }
441
442 scoped_refptr<NPAPIUrlRequest> NPAPIUrlRequestManager::LookupRequest(
443 int request_id) {
444 RequestMap::iterator index = request_map_.find(request_id);
445 if (index != request_map_.end())
446 return index->second;
447 return NULL;
448 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698