/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Mozilla browser. * * The Initial Developer of the Original Code is * Netscape Communications, Inc. * Portions created by the Initial Developer are Copyright (C) 1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Travis Bogard * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsDocShell.h" #include "nsDSURIContentListener.h" #include "nsIChannel.h" #include "nsServiceManagerUtils.h" #include "nsXPIDLString.h" #include "nsDocShellCID.h" #include "nsIWebNavigationInfo.h" #include "nsIDOMWindowInternal.h" #include "nsAutoPtr.h" //***************************************************************************** //*** nsDSURIContentListener: Object Management //***************************************************************************** nsDSURIContentListener::nsDSURIContentListener(nsDocShell* aDocShell) : mDocShell(aDocShell), mParentContentListener(nsnull) { } nsDSURIContentListener::~nsDSURIContentListener() { } nsresult nsDSURIContentListener::Init() { nsresult rv; mNavInfo = do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID, &rv); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to get webnav info"); return rv; } //***************************************************************************** // nsDSURIContentListener::nsISupports //***************************************************************************** NS_IMPL_THREADSAFE_ADDREF(nsDSURIContentListener) NS_IMPL_THREADSAFE_RELEASE(nsDSURIContentListener) NS_INTERFACE_MAP_BEGIN(nsDSURIContentListener) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURIContentListener) NS_INTERFACE_MAP_ENTRY(nsIURIContentListener) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_END //***************************************************************************** // nsDSURIContentListener::nsIURIContentListener //***************************************************************************** NS_IMETHODIMP nsDSURIContentListener::OnStartURIOpen(nsIURI* aURI, PRBool* aAbortOpen) { nsCOMPtr parentListener; GetParentContentListener(getter_AddRefs(parentListener)); if (parentListener) return parentListener->OnStartURIOpen(aURI, aAbortOpen); return NS_OK; } NS_IMETHODIMP nsDSURIContentListener::DoContent(const char* aContentType, PRBool aIsContentPreferred, nsIRequest* request, nsIStreamListener** aContentHandler, PRBool* aAbortProcess) { nsresult rv; NS_ENSURE_ARG_POINTER(aContentHandler); NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); if(aAbortProcess) *aAbortProcess = PR_FALSE; // determine if the channel has just been retargeted to us... nsLoadFlags loadFlags = 0; nsCOMPtr aOpenedChannel = do_QueryInterface(request); if (aOpenedChannel) aOpenedChannel->GetLoadFlags(&loadFlags); if(loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) { // XXX: Why does this not stop the content too? mDocShell->Stop(nsIWebNavigation::STOP_NETWORK); mDocShell->SetLoadType(aIsContentPreferred ? LOAD_LINK : LOAD_NORMAL); } rv = mDocShell->CreateContentViewer(aContentType, request, aContentHandler); if (NS_FAILED(rv)) { // it's okay if we don't know how to handle the content return NS_OK; } if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) { nsCOMPtr domWindow = do_GetInterface(NS_STATIC_CAST(nsIDocShell*, mDocShell)); NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE); domWindow->Focus(); } return NS_OK; } NS_IMETHODIMP nsDSURIContentListener::IsPreferred(const char* aContentType, char ** aDesiredContentType, PRBool* aCanHandle) { NS_ENSURE_ARG_POINTER(aCanHandle); NS_ENSURE_ARG_POINTER(aDesiredContentType); // the docshell has no idea if it is the preferred content provider or not. // It needs to ask it's parent if it is the preferred content handler or not... nsCOMPtr parentListener; GetParentContentListener(getter_AddRefs(parentListener)); if (parentListener) { return parentListener->IsPreferred(aContentType, aDesiredContentType, aCanHandle); } // we used to return false here if we didn't have a parent properly // registered at the top of the docshell hierarchy to dictate what // content types this docshell should be a preferred handler for. But // this really makes it hard for developers using iframe or browser tags // because then they need to make sure they implement // nsIURIContentListener otherwise all link clicks would get sent to // another window because we said we weren't the preferred handler type. // I'm going to change the default now...if we can handle the content, // and someone didn't EXPLICITLY set a nsIURIContentListener at the top // of our docshell chain, then we'll now always attempt to process the // content ourselves... return CanHandleContent(aContentType, PR_TRUE, aDesiredContentType, aCanHandle); } NS_IMETHODIMP nsDSURIContentListener::CanHandleContent(const char* aContentType, PRBool aIsContentPreferred, char ** aDesiredContentType, PRBool* aCanHandleContent) { NS_PRECONDITION(aCanHandleContent, "Null out param?"); NS_ENSURE_ARG_POINTER(aDesiredContentType); *aCanHandleContent = PR_FALSE; *aDesiredContentType = nsnull; nsresult rv = NS_OK; if (aContentType) { PRUint32 canHandle = nsIWebNavigationInfo::UNSUPPORTED; rv = mNavInfo->IsTypeSupported(nsDependentCString(aContentType), mDocShell, &canHandle); *aCanHandleContent = (canHandle != nsIWebNavigationInfo::UNSUPPORTED); } return rv; } NS_IMETHODIMP nsDSURIContentListener::GetLoadCookie(nsISupports ** aLoadCookie) { NS_IF_ADDREF(*aLoadCookie = nsDocShell::GetAsSupports(mDocShell)); return NS_OK; } NS_IMETHODIMP nsDSURIContentListener::SetLoadCookie(nsISupports * aLoadCookie) { #ifdef DEBUG nsRefPtr cookieAsDocLoader = nsDocLoader::GetAsDocLoader(aLoadCookie); NS_ASSERTION(cookieAsDocLoader && cookieAsDocLoader == mDocShell, "Invalid load cookie being set!"); #endif return NS_OK; } NS_IMETHODIMP nsDSURIContentListener::GetParentContentListener(nsIURIContentListener** aParentListener) { if (mWeakParentContentListener) { nsCOMPtr tempListener = do_QueryReferent(mWeakParentContentListener); *aParentListener = tempListener; NS_IF_ADDREF(*aParentListener); } else { *aParentListener = mParentContentListener; NS_IF_ADDREF(*aParentListener); } return NS_OK; } NS_IMETHODIMP nsDSURIContentListener::SetParentContentListener(nsIURIContentListener* aParentListener) { if (aParentListener) { // Store the parent listener as a weak ref. Parents not supporting // nsISupportsWeakReference assert but may still be used. mParentContentListener = nsnull; mWeakParentContentListener = do_GetWeakReference(aParentListener); if (!mWeakParentContentListener) { mParentContentListener = aParentListener; } } else { mWeakParentContentListener = nsnull; mParentContentListener = nsnull; } return NS_OK; }