diff options
Diffstat (limited to 'webkit/glue/plugins/webplugin_impl.cc')
-rw-r--r-- | webkit/glue/plugins/webplugin_impl.cc | 1379 |
1 files changed, 0 insertions, 1379 deletions
diff --git a/webkit/glue/plugins/webplugin_impl.cc b/webkit/glue/plugins/webplugin_impl.cc deleted file mode 100644 index cd91744..0000000 --- a/webkit/glue/plugins/webplugin_impl.cc +++ /dev/null @@ -1,1379 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "webkit/glue/plugins/webplugin_impl.h" - -#include "base/linked_ptr.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/string_util.h" -#include "base/stringprintf.h" -#include "base/utf_string_conversions.h" -#include "gfx/rect.h" -#include "googleurl/src/gurl.h" -#include "net/base/escape.h" -#include "net/base/net_errors.h" -#include "net/http/http_response_headers.h" -#include "skia/ext/platform_canvas.h" -#include "third_party/WebKit/WebKit/chromium/public/WebConsoleMessage.h" -#include "third_party/WebKit/WebKit/chromium/public/WebCookieJar.h" -#include "third_party/WebKit/WebKit/chromium/public/WebCString.h" -#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h" -#include "third_party/WebKit/WebKit/chromium/public/WebDevToolsAgent.h" -#include "third_party/WebKit/WebKit/chromium/public/WebData.h" -#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" -#include "third_party/WebKit/WebKit/chromium/public/WebHTTPBody.h" -#include "third_party/WebKit/WebKit/chromium/public/WebHTTPHeaderVisitor.h" -#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" -#include "third_party/WebKit/WebKit/chromium/public/WebKit.h" -#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h" -#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h" -#include "third_party/WebKit/WebKit/chromium/public/WebPluginParams.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURL.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h" -#include "third_party/WebKit/WebKit/chromium/public/WebView.h" -#include "webkit/appcache/web_application_cache_host_impl.h" -#include "webkit/glue/multipart_response_delegate.h" -#include "webkit/glue/plugins/plugin_host.h" -#include "webkit/glue/plugins/plugin_instance.h" -#include "webkit/glue/plugins/webplugin_delegate.h" -#include "webkit/glue/plugins/webplugin_page_delegate.h" - -using appcache::WebApplicationCacheHostImpl; -using WebKit::WebCanvas; -using WebKit::WebConsoleMessage; -using WebKit::WebCookieJar; -using WebKit::WebCString; -using WebKit::WebCursorInfo; -using WebKit::WebData; -using WebKit::WebDataSource; -using WebKit::WebDevToolsAgent; -using WebKit::WebFrame; -using WebKit::WebHTTPBody; -using WebKit::WebHTTPHeaderVisitor; -using WebKit::WebInputEvent; -using WebKit::WebKeyboardEvent; -using WebKit::WebMouseEvent; -using WebKit::WebPluginContainer; -using WebKit::WebPluginParams; -using WebKit::WebRect; -using WebKit::WebString; -using WebKit::WebURL; -using WebKit::WebURLError; -using WebKit::WebURLLoader; -using WebKit::WebURLLoaderClient; -using WebKit::WebURLRequest; -using WebKit::WebURLResponse; -using WebKit::WebVector; -using WebKit::WebView; -using webkit_glue::MultipartResponseDelegate; - -namespace webkit_glue { -namespace { - -// This class handles individual multipart responses. It is instantiated when -// we receive HTTP status code 206 in the HTTP response. This indicates -// that the response could have multiple parts each separated by a boundary -// specified in the response header. -class MultiPartResponseClient : public WebURLLoaderClient { - public: - explicit MultiPartResponseClient(WebPluginResourceClient* resource_client) - : resource_client_(resource_client) { - Clear(); - } - - virtual void willSendRequest( - WebURLLoader*, WebURLRequest&, const WebURLResponse&) {} - virtual void didSendData( - WebURLLoader*, unsigned long long, unsigned long long) {} - - // Called when the multipart parser encounters an embedded multipart - // response. - virtual void didReceiveResponse( - WebURLLoader*, const WebURLResponse& response) { - if (!MultipartResponseDelegate::ReadContentRanges( - response, - &byte_range_lower_bound_, - &byte_range_upper_bound_)) { - NOTREACHED(); - return; - } - - resource_response_ = response; - } - - // Receives individual part data from a multipart response. - virtual void didReceiveData( - WebURLLoader*, const char* data, int data_size) { - // TODO(ananta) - // We should defer further loads on multipart resources on the same lines - // as regular resources requested by plugins to prevent reentrancy. - resource_client_->DidReceiveData( - data, data_size, byte_range_lower_bound_); - byte_range_lower_bound_ += data_size; - } - - virtual void didFinishLoading(WebURLLoader*, double finishTime) {} - virtual void didFail(WebURLLoader*, const WebURLError&) {} - - void Clear() { - resource_response_.reset(); - byte_range_lower_bound_ = 0; - byte_range_upper_bound_ = 0; - } - - private: - WebURLResponse resource_response_; - // The lower bound of the byte range. - int byte_range_lower_bound_; - // The upper bound of the byte range. - int byte_range_upper_bound_; - // The handler for the data. - WebPluginResourceClient* resource_client_; -}; - -class HeaderFlattener : public WebHTTPHeaderVisitor { - public: - HeaderFlattener(std::string* buf) : buf_(buf) { - } - - virtual void visitHeader(const WebString& name, const WebString& value) { - // TODO(darin): Should we really exclude headers with an empty value? - if (!name.isEmpty() && !value.isEmpty()) { - buf_->append(name.utf8()); - buf_->append(": "); - buf_->append(value.utf8()); - buf_->append("\n"); - } - } - - private: - std::string* buf_; -}; - -std::string GetAllHeaders(const WebURLResponse& response) { - // TODO(darin): It is possible for httpStatusText to be empty and still have - // an interesting response, so this check seems wrong. - std::string result; - const WebString& status = response.httpStatusText(); - if (status.isEmpty()) - return result; - - // TODO(darin): Shouldn't we also report HTTP version numbers? - result = base::StringPrintf("HTTP %d ", response.httpStatusCode()); - result.append(status.utf8()); - result.append("\n"); - - HeaderFlattener flattener(&result); - response.visitHTTPHeaderFields(&flattener); - - return result; -} - -struct ResponseInfo { - GURL url; - std::string mime_type; - uint32 last_modified; - uint32 expected_length; -}; - -void GetResponseInfo(const WebURLResponse& response, - ResponseInfo* response_info) { - response_info->url = response.url(); - response_info->mime_type = response.mimeType().utf8(); - - // Measured in seconds since 12:00 midnight GMT, January 1, 1970. - response_info->last_modified = - static_cast<uint32>(response.lastModifiedDate()); - - // If the length comes in as -1, then it indicates that it was not - // read off the HTTP headers. We replicate Safari webkit behavior here, - // which is to set it to 0. - response_info->expected_length = - static_cast<uint32>(std::max(response.expectedContentLength(), 0LL)); - - WebString content_encoding = - response.httpHeaderField(WebString::fromUTF8("Content-Encoding")); - if (!content_encoding.isNull() && - !EqualsASCII(content_encoding, "identity")) { - // Don't send the compressed content length to the plugin, which only - // cares about the decoded length. - response_info->expected_length = 0; - } -} - -} // namespace - -// WebKit::WebPlugin ---------------------------------------------------------- - -struct WebPluginImpl::ClientInfo { - unsigned long id; - WebPluginResourceClient* client; - WebKit::WebURLRequest request; - bool pending_failure_notification; - linked_ptr<WebKit::WebURLLoader> loader; - bool notify_redirects; -}; - -bool WebPluginImpl::initialize(WebPluginContainer* container) { - if (!page_delegate_) - return false; - - WebPluginDelegate* plugin_delegate = page_delegate_->CreatePluginDelegate( - file_path_, mime_type_); - if (!plugin_delegate) - return false; - - // Set the container before Initialize because the plugin may - // synchronously call NPN_GetValue to get its container during its - // initialization. - SetContainer(container); - bool ok = plugin_delegate->Initialize( - plugin_url_, arg_names_, arg_values_, this, load_manually_); - if (!ok) { - plugin_delegate->PluginDestroyed(); - return false; - } - - delegate_ = plugin_delegate; - - return true; -} - -void WebPluginImpl::destroy() { - SetContainer(NULL); - MessageLoop::current()->DeleteSoon(FROM_HERE, this); -} - -NPObject* WebPluginImpl::scriptableObject() { - return delegate_->GetPluginScriptableObject(); -} - -void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) { - if (!delegate_ || !container_) - return; - -#if defined(OS_WIN) - // Force a geometry update if needed to allow plugins like media player - // which defer the initial geometry update to work. - container_->reportGeometry(); -#endif // OS_WIN - - // Note that |canvas| is only used when in windowless mode. - delegate_->Paint(canvas, paint_rect); -} - -void WebPluginImpl::updateGeometry( - const WebRect& window_rect, const WebRect& clip_rect, - const WebVector<WebRect>& cutout_rects, bool is_visible) { - WebPluginGeometry new_geometry; - new_geometry.window = window_; - new_geometry.window_rect = window_rect; - new_geometry.clip_rect = clip_rect; - new_geometry.visible = is_visible; - new_geometry.rects_valid = true; - for (size_t i = 0; i < cutout_rects.size(); ++i) - new_geometry.cutout_rects.push_back(cutout_rects[i]); - - // Only send DidMovePlugin if the geometry changed in some way. - if (window_ && - page_delegate_ && - (first_geometry_update_ || !new_geometry.Equals(geometry_))) { - page_delegate_->DidMovePlugin(new_geometry); - } - - // Only UpdateGeometry if either the window or clip rects have changed. - if (first_geometry_update_ || - new_geometry.window_rect != geometry_.window_rect || - new_geometry.clip_rect != geometry_.clip_rect) { - // Notify the plugin that its parameters have changed. - delegate_->UpdateGeometry(new_geometry.window_rect, new_geometry.clip_rect); - } - - // Initiate a download on the plugin url. This should be done for the - // first update geometry sequence. We need to ensure that the plugin - // receives the geometry update before it starts receiving data. - if (first_geometry_update_) { - // An empty url corresponds to an EMBED tag with no src attribute. - if (!load_manually_ && plugin_url_.is_valid()) { - // The Flash plugin hangs for a while if it receives data before - // receiving valid plugin geometry. By valid geometry we mean the - // geometry received by a call to setFrameRect in the Webkit - // layout code path. To workaround this issue we download the - // plugin source url on a timer. - MessageLoop::current()->PostDelayedTask( - FROM_HERE, method_factory_.NewRunnableMethod( - &WebPluginImpl::OnDownloadPluginSrcUrl), 0); - } - } - -#if defined(OS_WIN) - // Don't cache the geometry during the first geometry update. The first - // geometry update sequence is received when Widget::setParent is called. - // For plugins like media player which have a bug where they only honor - // the first geometry update, we have a quirk which ignores the first - // geometry update. To ensure that these plugins work correctly in cases - // where we receive only one geometry update from webkit, we also force - // a geometry update during paint which should go out correctly as the - // initial geometry update was not cached. - if (!first_geometry_update_) - geometry_ = new_geometry; -#else // OS_WIN - geometry_ = new_geometry; -#endif // OS_WIN - first_geometry_update_ = false; -} - -unsigned WebPluginImpl::getBackingTextureId() { - // Regular plugins do not have a backing texture. - return 0; -} - -void WebPluginImpl::updateFocus(bool focused) { - if (accepts_input_events_) - delegate_->SetFocus(focused); -} - -void WebPluginImpl::updateVisibility(bool visible) { - if (!window_ || !page_delegate_) - return; - - WebPluginGeometry move; - move.window = window_; - move.window_rect = gfx::Rect(); - move.clip_rect = gfx::Rect(); - move.rects_valid = false; - move.visible = visible; - - page_delegate_->DidMovePlugin(move); -} - -bool WebPluginImpl::acceptsInputEvents() { - return accepts_input_events_; -} - -bool WebPluginImpl::handleInputEvent( - const WebInputEvent& event, WebCursorInfo& cursor_info) { - // Swallow context menu events in order to suppress the default context menu. - if (event.type == WebInputEvent::ContextMenu) - return true; - - return delegate_->HandleInputEvent(event, &cursor_info); -} - -void WebPluginImpl::didReceiveResponse(const WebURLResponse& response) { - ignore_response_error_ = false; - - ResponseInfo response_info; - GetResponseInfo(response, &response_info); - - delegate_->DidReceiveManualResponse( - response_info.url, - response_info.mime_type, - GetAllHeaders(response), - response_info.expected_length, - response_info.last_modified); -} - -void WebPluginImpl::didReceiveData(const char* data, int data_length) { - delegate_->DidReceiveManualData(data, data_length); -} - -void WebPluginImpl::didFinishLoading() { - delegate_->DidFinishManualLoading(); -} - -void WebPluginImpl::didFailLoading(const WebURLError& error) { - if (!ignore_response_error_) - delegate_->DidManualLoadFail(); -} - -void WebPluginImpl::didFinishLoadingFrameRequest( - const WebURL& url, void* notify_data) { - if (delegate_) { - // We're converting a void* into an arbitrary int id. Though - // these types are the same size on all the platforms we support, - // the compiler may complain as though they are different, so to - // make the casting gods happy go through an intptr_t (the union - // of void* and int) rather than converting straight across. - delegate_->DidFinishLoadWithReason( - url, NPRES_DONE, reinterpret_cast<intptr_t>(notify_data)); - } -} - -void WebPluginImpl::didFailLoadingFrameRequest( - const WebURL& url, void* notify_data, const WebURLError& error) { - if (!delegate_) - return; - - NPReason reason = - error.reason == net::ERR_ABORTED ? NPRES_USER_BREAK : NPRES_NETWORK_ERR; - // See comment in didFinishLoadingFrameRequest about the cast here. - delegate_->DidFinishLoadWithReason( - url, reason, reinterpret_cast<intptr_t>(notify_data)); -} - -bool WebPluginImpl::supportsPaginatedPrint() { - if (!delegate_) - return false; - return delegate_->PrintSupportsPrintExtension(); -} - -int WebPluginImpl::printBegin(const WebRect& printable_area, int printer_dpi) { - if (!delegate_) - return 0; - - if (!supportsPaginatedPrint()) - return 0; - - return delegate_->PrintBegin(printable_area, printer_dpi); -} - -bool WebPluginImpl::printPage(int page_number, WebCanvas* canvas) { - if (!delegate_) - return false; - - return delegate_->PrintPage(page_number, canvas); -} - -void WebPluginImpl::printEnd() { - if (delegate_) - delegate_->PrintEnd(); -} - -bool WebPluginImpl::hasSelection() const { - if (!delegate_) - return false; - - return delegate_->HasSelection(); -} - -WebKit::WebString WebPluginImpl::selectionAsText() const { - if (!delegate_) - return WebString(); - - return delegate_->GetSelectionAsText(); -} - -WebKit::WebString WebPluginImpl::selectionAsMarkup() const { - if (!delegate_) - return WebString(); - - return delegate_->GetSelectionAsMarkup(); -} - -void WebPluginImpl::setZoomFactor(float scale, bool text_only) { - if (delegate_) - delegate_->SetZoomFactor(scale, text_only); -} - -bool WebPluginImpl::startFind(const WebKit::WebString& search_text, - bool case_sensitive, - int identifier) { - if (!delegate_) - return false; - return delegate_->StartFind(search_text, case_sensitive, identifier); -} - -void WebPluginImpl::selectFindResult(bool forward) { - if (delegate_) - delegate_->SelectFindResult(forward); -} - -void WebPluginImpl::stopFind() { - if (delegate_) - delegate_->StopFind(); -} - - -// ----------------------------------------------------------------------------- - -WebPluginImpl::WebPluginImpl( - WebFrame* webframe, - const WebPluginParams& params, - const FilePath& file_path, - const std::string& mime_type, - const base::WeakPtr<WebPluginPageDelegate>& page_delegate) - : windowless_(false), - window_(gfx::kNullPluginWindow), - accepts_input_events_(false), - page_delegate_(page_delegate), - webframe_(webframe), - delegate_(NULL), - container_(NULL), - plugin_url_(params.url), - load_manually_(params.loadManually), - first_geometry_update_(true), - ignore_response_error_(false), - file_path_(file_path), - mime_type_(mime_type), - ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { - DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size()); - StringToLowerASCII(&mime_type_); - - for (size_t i = 0; i < params.attributeNames.size(); ++i) { - arg_names_.push_back(params.attributeNames[i].utf8()); - arg_values_.push_back(params.attributeValues[i].utf8()); - } -} - -WebPluginImpl::~WebPluginImpl() { -} - -void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window) { -#if defined(OS_MACOSX) - // The only time this is called twice, and the second time with a - // non-zero PluginWindowHandle, is the case when this WebPluginImpl - // is created on behalf of the GPU plugin. This entire code path - // will go away soon, as soon as the GPU plugin becomes the GPU - // process, so it is being separated out for easy deletion. - - // The logic we want here is: if (window) DCHECK(!window_); - DCHECK(!(window_ && window)); - window_ = window; - // Lie to ourselves about being windowless even if we got a fake - // plugin window handle, so we continue to get input events. - windowless_ = true; - accepts_input_events_ = true; - // We do not really need to notify the page delegate that a plugin - // window was created -- so don't. -#else - if (window) { - DCHECK(!windowless_); - window_ = window; - accepts_input_events_ = false; - if (page_delegate_) { - // Tell the view delegate that the plugin window was created, so that it - // can create necessary container widgets. - page_delegate_->CreatedPluginWindow(window); - } - } else { - DCHECK(!window_); // Make sure not called twice. - windowless_ = true; - accepts_input_events_ = true; - } -#endif -} - -void WebPluginImpl::WillDestroyWindow(gfx::PluginWindowHandle window) { - DCHECK_EQ(window, window_); - window_ = gfx::kNullPluginWindow; - if (page_delegate_) - page_delegate_->WillDestroyPluginWindow(window); -} - -GURL WebPluginImpl::CompleteURL(const char* url) { - if (!webframe_) { - NOTREACHED(); - return GURL(); - } - // TODO(darin): Is conversion from UTF8 correct here? - return webframe_->document().completeURL(WebString::fromUTF8(url)); -} - -void WebPluginImpl::CancelResource(unsigned long id) { - for (size_t i = 0; i < clients_.size(); ++i) { - if (clients_[i].id == id) { - if (clients_[i].loader.get()) { - clients_[i].loader->setDefersLoading(false); - clients_[i].loader->cancel(); - RemoveClient(i); - } - return; - } - } -} - -bool WebPluginImpl::SetPostData(WebURLRequest* request, - const char *buf, - uint32 length) { - std::vector<std::string> names; - std::vector<std::string> values; - std::vector<char> body; - bool rv = NPAPI::PluginHost::SetPostData(buf, length, &names, &values, &body); - - for (size_t i = 0; i < names.size(); ++i) { - request->addHTTPHeaderField(WebString::fromUTF8(names[i]), - WebString::fromUTF8(values[i])); - } - - WebString content_type_header = WebString::fromUTF8("Content-Type"); - const WebString& content_type = - request->httpHeaderField(content_type_header); - if (content_type.isEmpty()) { - request->setHTTPHeaderField( - content_type_header, - WebString::fromUTF8("application/x-www-form-urlencoded")); - } - - WebHTTPBody http_body; - if (body.size()) { - http_body.initialize(); - http_body.appendData(WebData(&body[0], body.size())); - } - request->setHTTPBody(http_body); - - return rv; -} - -bool WebPluginImpl::IsValidUrl(const GURL& url, Referrer referrer_flag) { - if (referrer_flag == PLUGIN_SRC && - mime_type_ == "application/x-shockwave-flash" && - url.GetOrigin() != plugin_url_.GetOrigin()) { - // Do url check to make sure that there are no @, ;, \ chars in between url - // scheme and url path. - const char* url_to_check(url.spec().data()); - url_parse::Parsed parsed; - url_parse::ParseStandardURL(url_to_check, strlen(url_to_check), &parsed); - if (parsed.path.begin <= parsed.scheme.end()) - return true; - std::string string_to_search; - string_to_search.assign(url_to_check + parsed.scheme.end(), - parsed.path.begin - parsed.scheme.end()); - if (string_to_search.find("@") != std::string::npos || - string_to_search.find(";") != std::string::npos || - string_to_search.find("\\") != std::string::npos) - return false; - } - - return true; -} - -WebPluginImpl::RoutingStatus WebPluginImpl::RouteToFrame( - const char* url, - bool is_javascript_url, - const char* method, - const char* target, - const char* buf, - unsigned int len, - int notify_id, - Referrer referrer_flag) { - // If there is no target, there is nothing to do - if (!target) - return NOT_ROUTED; - - // This could happen if the WebPluginContainer was already deleted. - if (!webframe_) - return NOT_ROUTED; - - WebString target_str = WebString::fromUTF8(target); - - // Take special action for JavaScript URLs - if (is_javascript_url) { - WebFrame* target_frame = - webframe_->view()->findFrameByName(target_str, webframe_); - // For security reasons, do not allow JavaScript on frames - // other than this frame. - if (target_frame != webframe_) { - // TODO(darin): Localize this message. - const char kMessage[] = - "Ignoring cross-frame javascript URL load requested by plugin."; - webframe_->addMessageToConsole( - WebConsoleMessage(WebConsoleMessage::LevelError, - WebString::fromUTF8(kMessage))); - return ROUTED; - } - - // Route javascript calls back to the plugin. - return NOT_ROUTED; - } - - // If we got this far, we're routing content to a target frame. - // Go fetch the URL. - - GURL complete_url = CompleteURL(url); - // Remove when flash bug is fixed. http://crbug.com/40016. - if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag)) - return INVALID_URL; - - if (strcmp(method, "GET") != 0) { - // We're only going to route HTTP/HTTPS requests - if (!(complete_url.SchemeIs("http") || complete_url.SchemeIs("https"))) - return INVALID_URL; - } - - WebURLRequest request(complete_url); - SetReferrer(&request, referrer_flag); - - request.setHTTPMethod(WebString::fromUTF8(method)); - request.setFirstPartyForCookies( - webframe_->document().firstPartyForCookies()); - if (len > 0) { - if (!SetPostData(&request, buf, len)) { - // Uhoh - we're in trouble. There isn't a good way - // to recover at this point. Break out. - NOTREACHED(); - return ROUTED; - } - } - - container_->loadFrameRequest( - request, target_str, notify_id != 0, reinterpret_cast<void*>(notify_id)); - return ROUTED; -} - -NPObject* WebPluginImpl::GetWindowScriptNPObject() { - if (!webframe_) { - NOTREACHED(); - return NULL; - } - return webframe_->windowObject(); -} - -NPObject* WebPluginImpl::GetPluginElement() { - return container_->scriptableObjectForElement(); -} - -void WebPluginImpl::SetCookie(const GURL& url, - const GURL& first_party_for_cookies, - const std::string& cookie) { - if (!page_delegate_) - return; - - WebCookieJar* cookie_jar = page_delegate_->GetCookieJar(); - if (!cookie_jar) { - DLOG(WARNING) << "No cookie jar!"; - return; - } - - cookie_jar->setCookie( - url, first_party_for_cookies, WebString::fromUTF8(cookie)); -} - -std::string WebPluginImpl::GetCookies(const GURL& url, - const GURL& first_party_for_cookies) { - if (!page_delegate_) - return std::string(); - - WebCookieJar* cookie_jar = page_delegate_->GetCookieJar(); - if (!cookie_jar) { - DLOG(WARNING) << "No cookie jar!"; - return std::string(); - } - - return UTF16ToUTF8(cookie_jar->cookies(url, first_party_for_cookies)); -} - -void WebPluginImpl::ShowModalHTMLDialog(const GURL& url, int width, int height, - const std::string& json_arguments, - std::string* json_retval) { - if (page_delegate_) { - page_delegate_->ShowModalHTMLDialogForPlugin( - url, gfx::Size(width, height), json_arguments, json_retval); - } -} - -void WebPluginImpl::OnMissingPluginStatus(int status) { - NOTREACHED(); -} - -void WebPluginImpl::URLRedirectResponse(bool allow, int resource_id) { - for (size_t i = 0; i < clients_.size(); ++i) { - if (clients_[i].id == static_cast<unsigned long>(resource_id)) { - if (clients_[i].loader.get()) { - if (allow) { - clients_[i].loader->setDefersLoading(false); - } else { - clients_[i].loader->cancel(); - clients_[i].client->DidFail(); - } - } - break; - } - } -} - -void WebPluginImpl::Invalidate() { - if (container_) - container_->invalidate(); -} - -void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) { - if (container_) - container_->invalidateRect(rect); -} - -void WebPluginImpl::OnDownloadPluginSrcUrl() { - HandleURLRequestInternal( - plugin_url_.spec().c_str(), "GET", NULL, NULL, 0, 0, false, DOCUMENT_URL, - false); -} - -WebPluginResourceClient* WebPluginImpl::GetClientFromLoader( - WebURLLoader* loader) { - ClientInfo* client_info = GetClientInfoFromLoader(loader); - if (client_info) - return client_info->client; - return NULL; -} - -WebPluginImpl::ClientInfo* WebPluginImpl::GetClientInfoFromLoader( - WebURLLoader* loader) { - for (size_t i = 0; i < clients_.size(); ++i) { - if (clients_[i].loader.get() == loader) - return &clients_[i]; - } - - NOTREACHED(); - return 0; -} - -void WebPluginImpl::willSendRequest(WebURLLoader* loader, - WebURLRequest& request, - const WebURLResponse& response) { - WebPluginImpl::ClientInfo* client_info = GetClientInfoFromLoader(loader); - if (client_info) { - if (net::HttpResponseHeaders::IsRedirectResponseCode( - response.httpStatusCode())) { - // If the plugin does not participate in url redirect notifications then - // just block cross origin 307 POST redirects. - if (!client_info->notify_redirects) { - if (response.httpStatusCode() == 307 && - LowerCaseEqualsASCII(request.httpMethod().utf8(), "post")) { - GURL original_request_url(response.url()); - GURL response_url(request.url()); - if (original_request_url.GetOrigin() != response_url.GetOrigin()) { - loader->setDefersLoading(true); - loader->cancel(); - client_info->client->DidFail(); - return; - } - } - } else { - loader->setDefersLoading(true); - } - } - client_info->client->WillSendRequest(request.url(), - response.httpStatusCode()); - } -} - -void WebPluginImpl::didSendData(WebURLLoader* loader, - unsigned long long bytes_sent, - unsigned long long total_bytes_to_be_sent) { -} - -void WebPluginImpl::didReceiveResponse(WebURLLoader* loader, - const WebURLResponse& response) { - static const int kHttpPartialResponseStatusCode = 206; - static const int kHttpResponseSuccessStatusCode = 200; - - WebPluginResourceClient* client = GetClientFromLoader(loader); - if (!client) - return; - - ResponseInfo response_info; - GetResponseInfo(response, &response_info); - - bool request_is_seekable = true; - if (client->IsMultiByteResponseExpected()) { - if (response.httpStatusCode() == kHttpPartialResponseStatusCode) { - HandleHttpMultipartResponse(response, client); - return; - } else if (response.httpStatusCode() == kHttpResponseSuccessStatusCode) { - // If the client issued a byte range request and the server responds with - // HTTP 200 OK, it indicates that the server does not support byte range - // requests. - // We need to emulate Firefox behavior by doing the following:- - // 1. Destroy the plugin instance in the plugin process. Ensure that - // existing resource requests initiated for the plugin instance - // continue to remain valid. - // 2. Create a new plugin instance and notify it about the response - // received here. - if (!ReinitializePluginForResponse(loader)) { - NOTREACHED(); - return; - } - - // The server does not support byte range requests. No point in creating - // seekable streams. - request_is_seekable = false; - - delete client; - client = NULL; - - // Create a new resource client for this request. - for (size_t i = 0; i < clients_.size(); ++i) { - if (clients_[i].loader.get() == loader) { - WebPluginResourceClient* resource_client = - delegate_->CreateResourceClient(clients_[i].id, plugin_url_, 0); - clients_[i].client = resource_client; - client = resource_client; - break; - } - } - - DCHECK(client != NULL); - } - } - - // Calling into a plugin could result in reentrancy if the plugin yields - // control to the OS like entering a modal loop etc. Prevent this by - // stopping further loading until the plugin notifies us that it is ready to - // accept data - loader->setDefersLoading(true); - - client->DidReceiveResponse( - response_info.mime_type, - GetAllHeaders(response), - response_info.expected_length, - response_info.last_modified, - request_is_seekable); - - if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) { - ClientInfo* client_info = GetClientInfoFromLoader(loader); - if (client_info) - devtools_agent->didReceiveResponse(client_info->id, response); - } - - // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP - // error codes in the stream header and as a result, was unaware of the - // fate of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF - // destroy the stream and invoke the NPP_DestroyStream function on the - // plugin if the HTTP request fails. - const GURL& url = response.url(); - if (url.SchemeIs("http") || url.SchemeIs("https")) { - if (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400) { - // The plugin instance could be in the process of deletion here. - // Verify if the WebPluginResourceClient instance still exists before - // use. - ClientInfo* client_info = GetClientInfoFromLoader(loader); - if (client_info) { - client_info->pending_failure_notification = true; - } - } - } -} - -void WebPluginImpl::didReceiveData(WebURLLoader* loader, - const char *buffer, - int length) { - WebPluginResourceClient* client = GetClientFromLoader(loader); - if (!client) - return; - - // ClientInfo can be removed from clients_ vector by next statements. - if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) { - ClientInfo* client_info = GetClientInfoFromLoader(loader); - if (client_info) - devtools_agent->didReceiveData(client_info->id, length); - } - MultiPartResponseHandlerMap::iterator index = - multi_part_response_map_.find(client); - if (index != multi_part_response_map_.end()) { - MultipartResponseDelegate* multi_part_handler = (*index).second; - DCHECK(multi_part_handler != NULL); - multi_part_handler->OnReceivedData(buffer, length); - } else { - loader->setDefersLoading(true); - client->DidReceiveData(buffer, length, 0); - } -} - -void WebPluginImpl::didFinishLoading(WebURLLoader* loader, double finishTime) { - ClientInfo* client_info = GetClientInfoFromLoader(loader); - if (client_info && client_info->client) { - MultiPartResponseHandlerMap::iterator index = - multi_part_response_map_.find(client_info->client); - if (index != multi_part_response_map_.end()) { - delete (*index).second; - multi_part_response_map_.erase(index); - if (page_delegate_) - page_delegate_->DidStopLoadingForPlugin(); - } - loader->setDefersLoading(true); - WebPluginResourceClient* resource_client = client_info->client; - // The ClientInfo can get deleted in the call to DidFinishLoading below. - // It is not safe to access this structure after that. - client_info->client = NULL; - resource_client->DidFinishLoading(); - - if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) - devtools_agent->didFinishLoading(client_info->id); - } -} - -void WebPluginImpl::didFail(WebURLLoader* loader, - const WebURLError& error) { - ClientInfo* client_info = GetClientInfoFromLoader(loader); - if (client_info && client_info->client) { - loader->setDefersLoading(true); - WebPluginResourceClient* resource_client = client_info->client; - // The ClientInfo can get deleted in the call to DidFail below. - // It is not safe to access this structure after that. - client_info->client = NULL; - resource_client->DidFail(); - - if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) - devtools_agent->didFailLoading(client_info->id, error); - } -} - -void WebPluginImpl::RemoveClient(size_t i) { - clients_.erase(clients_.begin() + i); -} - -void WebPluginImpl::RemoveClient(WebURLLoader* loader) { - for (size_t i = 0; i < clients_.size(); ++i) { - if (clients_[i].loader.get() == loader) { - RemoveClient(i); - return; - } - } -} - -void WebPluginImpl::SetContainer(WebPluginContainer* container) { - if (!container) - TearDownPluginInstance(NULL); - container_ = container; -} - -void WebPluginImpl::HandleURLRequest(const char* url, - const char* method, - const char* target, - const char* buf, - unsigned int len, - int notify_id, - bool popups_allowed, - bool notify_redirects) { - // GetURL/PostURL requests initiated explicitly by plugins should specify the - // plugin SRC url as the referrer if it is available. - HandleURLRequestInternal( - url, method, target, buf, len, notify_id, popups_allowed, PLUGIN_SRC, - notify_redirects); -} - -void WebPluginImpl::HandleURLRequestInternal(const char* url, - const char* method, - const char* target, - const char* buf, - unsigned int len, - int notify_id, - bool popups_allowed, - Referrer referrer_flag, - bool notify_redirects) { - // For this request, we either route the output to a frame - // because a target has been specified, or we handle the request - // here, i.e. by executing the script if it is a javascript url - // or by initiating a download on the URL, etc. There is one special - // case in that the request is a javascript url and the target is "_self", - // in which case we route the output to the plugin rather than routing it - // to the plugin's frame. - bool is_javascript_url = StartsWithASCII(url, "javascript:", false); - RoutingStatus routing_status = RouteToFrame( - url, is_javascript_url, method, target, buf, len, notify_id, - referrer_flag); - if (routing_status == ROUTED) - return; - - if (is_javascript_url) { - GURL gurl(url); - WebString result = container_->executeScriptURL(gurl, popups_allowed); - - // delegate_ could be NULL because executeScript caused the container to - // be deleted. - if (delegate_) { - delegate_->SendJavaScriptStream( - gurl, result.utf8(), !result.isNull(), notify_id); - } - - return; - } - - unsigned long resource_id = GetNextResourceId(); - if (!resource_id) - return; - - GURL complete_url = CompleteURL(url); - // Remove when flash bug is fixed. http://crbug.com/40016. - if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag)) - return; - - WebPluginResourceClient* resource_client = delegate_->CreateResourceClient( - resource_id, complete_url, notify_id); - if (!resource_client) - return; - - // If the RouteToFrame call returned a failure then inform the result - // back to the plugin asynchronously. - if ((routing_status == INVALID_URL) || - (routing_status == GENERAL_FAILURE)) { - resource_client->DidFail(); - return; - } - - // CreateResourceClient() sends a synchronous IPC message so it's possible - // that TearDownPluginInstance() may have been called in the nested - // message loop. If so, don't start the request. - if (!delegate_) - return; - - InitiateHTTPRequest(resource_id, resource_client, complete_url, method, buf, - len, NULL, referrer_flag, notify_redirects); -} - -unsigned long WebPluginImpl::GetNextResourceId() { - if (!webframe_) - return 0; - WebView* view = webframe_->view(); - if (!view) - return 0; - return view->createUniqueIdentifierForRequest(); -} - -bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id, - WebPluginResourceClient* client, - const GURL& url, - const char* method, - const char* buf, - int buf_len, - const char* range_info, - Referrer referrer_flag, - bool notify_redirects) { - if (!client) { - NOTREACHED(); - return false; - } - - ClientInfo info; - info.id = resource_id; - info.client = client; - info.request.initialize(); - info.request.setURL(url); - info.request.setFirstPartyForCookies( - webframe_->document().firstPartyForCookies()); - info.request.setRequestorProcessID(delegate_->GetProcessId()); - info.request.setTargetType(WebURLRequest::TargetIsObject); - info.request.setHTTPMethod(WebString::fromUTF8(method)); - info.pending_failure_notification = false; - info.notify_redirects = notify_redirects; - - if (range_info) { - info.request.addHTTPHeaderField(WebString::fromUTF8("Range"), - WebString::fromUTF8(range_info)); - } - - if (strcmp(method, "POST") == 0) { - // Adds headers or form data to a request. This must be called before - // we initiate the actual request. - SetPostData(&info.request, buf, buf_len); - } - - SetReferrer(&info.request, referrer_flag); - - // Sets the routing id to associate the ResourceRequest with the RenderView. - webframe_->dispatchWillSendRequest(info.request); - - // Sets the appcache host id to allow retrieval from the appcache. - if (WebApplicationCacheHostImpl* appcache_host = - WebApplicationCacheHostImpl::FromFrame(webframe_)) { - appcache_host->willStartSubResourceRequest(info.request); - } - - if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) { - devtools_agent->identifierForInitialRequest(resource_id, webframe_, - info.request); - devtools_agent->willSendRequest(resource_id, info.request); - } - - info.loader.reset(WebKit::webKitClient()->createURLLoader()); - if (!info.loader.get()) - return false; - info.loader->loadAsynchronously(info.request, this); - - clients_.push_back(info); - return true; -} - -void WebPluginImpl::CancelDocumentLoad() { - if (webframe_) { - ignore_response_error_ = true; - webframe_->stopLoading(); - } -} - -void WebPluginImpl::InitiateHTTPRangeRequest( - const char* url, const char* range_info, int range_request_id) { - unsigned long resource_id = GetNextResourceId(); - if (!resource_id) - return; - - GURL complete_url = CompleteURL(url); - // Remove when flash bug is fixed. http://crbug.com/40016. - if (!WebPluginImpl::IsValidUrl(complete_url, - load_manually_ ? NO_REFERRER : PLUGIN_SRC)) - return; - - WebPluginResourceClient* resource_client = - delegate_->CreateSeekableResourceClient(resource_id, range_request_id); - InitiateHTTPRequest( - resource_id, resource_client, complete_url, "GET", NULL, 0, range_info, - load_manually_ ? NO_REFERRER : PLUGIN_SRC, false); -} - -void WebPluginImpl::SetDeferResourceLoading(unsigned long resource_id, - bool defer) { - std::vector<ClientInfo>::iterator client_index = clients_.begin(); - while (client_index != clients_.end()) { - ClientInfo& client_info = *client_index; - - if (client_info.id == resource_id) { - client_info.loader->setDefersLoading(defer); - - // If we determined that the request had failed via the HTTP headers - // in the response then we send out a failure notification to the - // plugin process, as certain plugins don't handle HTTP failure codes - // correctly. - if (!defer && client_info.client && - client_info.pending_failure_notification) { - // The ClientInfo and the iterator can become invalid due to the call - // to DidFail below. - WebPluginResourceClient* resource_client = client_info.client; - client_info.loader->cancel(); - clients_.erase(client_index++); - resource_client->DidFail(); - - // Report that resource loading finished. - if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) - devtools_agent->didFinishLoading(resource_id); - } - break; - } - client_index++; - } -} - -void WebPluginImpl::HandleHttpMultipartResponse( - const WebURLResponse& response, WebPluginResourceClient* client) { - std::string multipart_boundary; - if (!MultipartResponseDelegate::ReadMultipartBoundary( - response, &multipart_boundary)) { - NOTREACHED(); - return; - } - - if (page_delegate_) - page_delegate_->DidStartLoadingForPlugin(); - - MultiPartResponseClient* multi_part_response_client = - new MultiPartResponseClient(client); - - MultipartResponseDelegate* multi_part_response_handler = - new MultipartResponseDelegate(multi_part_response_client, NULL, - response, - multipart_boundary); - multi_part_response_map_[client] = multi_part_response_handler; -} - -bool WebPluginImpl::ReinitializePluginForResponse( - WebURLLoader* loader) { - WebFrame* webframe = webframe_; - if (!webframe) - return false; - - WebView* webview = webframe->view(); - if (!webview) - return false; - - WebPluginContainer* container_widget = container_; - - // Destroy the current plugin instance. - TearDownPluginInstance(loader); - - container_ = container_widget; - webframe_ = webframe; - - WebPluginDelegate* plugin_delegate = page_delegate_->CreatePluginDelegate( - file_path_, mime_type_); - - bool ok = plugin_delegate && plugin_delegate->Initialize( - plugin_url_, arg_names_, arg_values_, this, load_manually_); - - if (!ok) { - container_ = NULL; - // TODO(iyengar) Should we delete the current plugin instance here? - return false; - } - - delegate_ = plugin_delegate; - - // Force a geometry update to occur to ensure that the plugin becomes - // visible. - container_->reportGeometry(); - - // The plugin move sequences accumulated via DidMove are sent to the browser - // whenever the renderer paints. Force a paint here to ensure that changes - // to the plugin window are propagated to the browser. - container_->invalidate(); - return true; -} - -void WebPluginImpl::TearDownPluginInstance( - WebURLLoader* loader_to_ignore) { - // The container maintains a list of JSObjects which are related to this - // plugin. Tell the frame we're gone so that it can invalidate all of - // those sub JSObjects. - if (container_) - container_->clearScriptObjects(); - - if (delegate_) { - // Call PluginDestroyed() first to prevent the plugin from calling us back - // in the middle of tearing down the render tree. - delegate_->PluginDestroyed(); - delegate_ = NULL; - } - - // Cancel any pending requests because otherwise this deleted object will - // be called by the ResourceDispatcher. - std::vector<ClientInfo>::iterator client_index = clients_.begin(); - while (client_index != clients_.end()) { - ClientInfo& client_info = *client_index; - - if (loader_to_ignore == client_info.loader) { - client_index++; - continue; - } - - if (client_info.loader.get()) - client_info.loader->cancel(); - - client_index = clients_.erase(client_index); - } - - // This needs to be called now and not in the destructor since the - // webframe_ might not be valid anymore. - webframe_ = NULL; - method_factory_.RevokeAll(); -} - -void WebPluginImpl::SetReferrer(WebKit::WebURLRequest* request, - Referrer referrer_flag) { - switch (referrer_flag) { - case DOCUMENT_URL: - webframe_->setReferrerForRequest(*request, GURL()); - break; - - case PLUGIN_SRC: - webframe_->setReferrerForRequest(*request, plugin_url_); - break; - - default: - break; - } -} - -WebDevToolsAgent* WebPluginImpl::GetDevToolsAgent() { - if (!webframe_) - return NULL; - WebView* view = webframe_->view(); - if (!view) - return NULL; - return view->devToolsAgent(); -} - -} // namespace webkit_glue |