/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape 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/NPL/ * * 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 mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * Chak Nanga */ #include "nsViewSourceChannel.h" #include "nsIIOService.h" #include "nsIServiceManager.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsXPIDLString.h" #include "nsMimeTypes.h" #include "nsNetUtil.h" // nsViewSourceChannel methods nsViewSourceChannel::nsViewSourceChannel() { NS_INIT_REFCNT(); } nsViewSourceChannel::~nsViewSourceChannel() { } NS_IMPL_THREADSAFE_ISUPPORTS5(nsViewSourceChannel, nsIRequest, nsIChannel, nsIViewSourceChannel, nsIStreamListener, nsIRequestObserver) nsresult nsViewSourceChannel::Init(nsIURI* uri) { nsresult rv; nsXPIDLCString path; rv = uri->GetPath(getter_Copies(path)); if (NS_FAILED(rv)) return rv; nsCOMPtr pService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); if (NS_FAILED(rv)) return rv; rv = pService->NewChannel(path, nsnull, getter_AddRefs(mChannel)); return rv; } NS_METHOD nsViewSourceChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) { nsViewSourceChannel* fc = new nsViewSourceChannel(); if (fc == nsnull) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(fc); nsresult rv = fc->QueryInterface(aIID, aResult); NS_RELEASE(fc); return rv; } //////////////////////////////////////////////////////////////////////////////// // nsIRequest methods: NS_IMETHODIMP nsViewSourceChannel::GetName(PRUnichar* *result) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsViewSourceChannel::IsPending(PRBool *result) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->IsPending(result); } NS_IMETHODIMP nsViewSourceChannel::GetStatus(nsresult *status) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->GetStatus(status); } NS_IMETHODIMP nsViewSourceChannel::Cancel(nsresult status) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->Cancel(status); } NS_IMETHODIMP nsViewSourceChannel::Suspend(void) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->Suspend(); } NS_IMETHODIMP nsViewSourceChannel::Resume(void) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->Resume(); } //////////////////////////////////////////////////////////////////////////////// // nsIChannel methods: NS_IMETHODIMP nsViewSourceChannel::GetOriginalURI(nsIURI* *aURI) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->GetOriginalURI(aURI); } NS_IMETHODIMP nsViewSourceChannel::SetOriginalURI(nsIURI* aURI) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->SetOriginalURI(aURI); } NS_IMETHODIMP nsViewSourceChannel::GetURI(nsIURI* *aURI) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->GetURI(aURI); } NS_IMETHODIMP nsViewSourceChannel::Open(nsIInputStream **_retval) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->Open(_retval); } NS_IMETHODIMP nsViewSourceChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); mListener = aListener; return mChannel->AsyncOpen(this, ctxt); } NS_IMETHODIMP nsViewSourceChannel::GetLoadFlags(PRUint32 *aLoadFlags) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->GetLoadFlags(aLoadFlags); } NS_IMETHODIMP nsViewSourceChannel::SetLoadFlags(PRUint32 aLoadFlags) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); // "View source" always wants the currently cached content. return mChannel->SetLoadFlags(aLoadFlags | nsIRequest::LOAD_FROM_CACHE); } #define X_VIEW_SOURCE_PARAM "; x-view-type=view-source" NS_IMETHODIMP nsViewSourceChannel::GetContentType(char* *aContentType) { NS_ENSURE_ARG_POINTER(aContentType); NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); if(mContentType.IsEmpty()) { // Get the current content type nsresult rv; nsXPIDLCString contentType; rv = mChannel->GetContentType(getter_Copies(contentType)); if (NS_FAILED(rv)) return rv; // Tack on the view-source param to the content type // Doing this so as to preserve the original content // type as received from the webserver. But, by adding // the x-view-type param we're indicating a custom preference // of how this should be displayed - viewsource or regular view nsCAutoString viewSrcContentType; viewSrcContentType.Append(contentType); viewSrcContentType.Append(X_VIEW_SOURCE_PARAM); // At this stage the content-type string will be // of the form "text/html; x-view-type=view-source" *aContentType = nsCRT::strdup(viewSrcContentType.get()); if (!*aContentType) return NS_ERROR_OUT_OF_MEMORY; mContentType = *aContentType; return NS_OK; } else { *aContentType = mContentType.ToNewCString(); if (!*aContentType) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } } NS_IMETHODIMP nsViewSourceChannel::SetContentType(const char *aContentType) { NS_ENSURE_ARG(aContentType); // Our GetContentType() currently returns strings of the // form "text/html; x-view-type=view-source"(see above) // // However, during the parsing phase the parser calls our channels' // GetContentType(). Returing a string of the form given above // trips up the parser. In order to avoid messy changes and not to have // the parser depend on nsIViewSourceChannel Vidur proposed the // following solution: // // The ViewSourceChannel initially returns a content type of the // form "text/html; x-view-type=view-source". Based on this type // decisions to create a viewer for doing a view source are made. // After the viewer is created, nsLayoutDLF::CreateInstance() // calls this SetContentType() with the original content type. // When it's time for the parser to find out the content type it // will call our channels' GetContentType() and it will get the // original content type, such as, text/html and everything // is kosher from then on mContentType = aContentType; return NS_OK; } NS_IMETHODIMP nsViewSourceChannel::GetContentLength(PRInt32 *aContentLength) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->GetContentLength(aContentLength); } NS_IMETHODIMP nsViewSourceChannel::SetContentLength(PRInt32 aContentLength) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->SetContentLength(aContentLength); } NS_IMETHODIMP nsViewSourceChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->GetLoadGroup(aLoadGroup); } NS_IMETHODIMP nsViewSourceChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->SetLoadGroup(aLoadGroup); } NS_IMETHODIMP nsViewSourceChannel::GetOwner(nsISupports* *aOwner) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->GetOwner(aOwner); } NS_IMETHODIMP nsViewSourceChannel::SetOwner(nsISupports* aOwner) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->SetOwner(aOwner); } NS_IMETHODIMP nsViewSourceChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->GetNotificationCallbacks(aNotificationCallbacks); } NS_IMETHODIMP nsViewSourceChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->SetNotificationCallbacks(aNotificationCallbacks); } NS_IMETHODIMP nsViewSourceChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) { NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->GetSecurityInfo(aSecurityInfo); } // nsIViewSourceChannel methods NS_IMETHODIMP nsViewSourceChannel::GetOriginalContentType(char* *aContentType) { NS_ENSURE_ARG_POINTER(aContentType); NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); return mChannel->GetContentType(aContentType); } // nsIRequestObserver methods NS_IMETHODIMP nsViewSourceChannel::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) { NS_ENSURE_TRUE(mListener, NS_ERROR_FAILURE); return mListener->OnStartRequest(this, aContext); } NS_IMETHODIMP nsViewSourceChannel::OnStopRequest(nsIRequest *aRequest, nsISupports* aContext, nsresult aStatus) { NS_ENSURE_TRUE(mListener, NS_ERROR_FAILURE); return mListener->OnStopRequest(this, aContext, aStatus); } // nsIStreamListener methods NS_IMETHODIMP nsViewSourceChannel::OnDataAvailable(nsIRequest *aRequest, nsISupports* aContext, nsIInputStream *aInputStream, PRUint32 aSourceOffset, PRUint32 aLength) { NS_ENSURE_TRUE(mListener, NS_ERROR_FAILURE); return mListener->OnDataAvailable(this, aContext, aInputStream, aSourceOffset, aLength); }