1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:set ts=4 sw=4 sts=4 et: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Chak Nanga <chak@netscape.com>
25 * Darin Fisher <darin@meer.net>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsViewSourceChannel.h"
42 #include "nsIIOService.h"
43 #include "nsIServiceManager.h"
44 #include "nsIInterfaceRequestor.h"
45 #include "nsIInterfaceRequestorUtils.h"
46 #include "nsXPIDLString.h"
47 #include "nsReadableUtils.h"
48 #include "nsMimeTypes.h"
49 #include "nsNetUtil.h"
50 #include "nsIHttpHeaderVisitor.h"
52 NS_IMPL_ADDREF(nsViewSourceChannel
)
53 NS_IMPL_RELEASE(nsViewSourceChannel
)
55 This QI uses NS_INTERFACE_MAP_ENTRY_CONDITIONAL to check for
56 non-nullness of mHttpChannel, mCachingChannel, and mUploadChannel.
58 NS_INTERFACE_MAP_BEGIN(nsViewSourceChannel
)
59 NS_INTERFACE_MAP_ENTRY(nsIViewSourceChannel
)
60 NS_INTERFACE_MAP_ENTRY(nsIStreamListener
)
61 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver
)
62 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIHttpChannel
, mHttpChannel
)
63 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICachingChannel
, mCachingChannel
)
64 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIUploadChannel
, mUploadChannel
)
65 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIRequest
, nsIViewSourceChannel
)
66 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIChannel
, nsIViewSourceChannel
)
67 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIViewSourceChannel
)
71 nsViewSourceChannel::Init(nsIURI
* uri
)
76 nsresult rv
= uri
->GetPath(path
);
80 nsCOMPtr
<nsIIOService
> pService(do_GetIOService(&rv
));
81 if (NS_FAILED(rv
)) return rv
;
84 rv
= pService
->ExtractScheme(path
, scheme
);
88 // prevent viewing source of javascript URIs (see bug 204779)
89 if (scheme
.LowerCaseEqualsLiteral("javascript")) {
90 NS_WARNING("blocking view-source:javascript:");
91 return NS_ERROR_INVALID_ARG
;
94 rv
= pService
->NewChannel(path
, nsnull
, nsnull
, getter_AddRefs(mChannel
));
98 mChannel
->SetOriginalURI(mOriginalURI
);
99 mHttpChannel
= do_QueryInterface(mChannel
);
100 mCachingChannel
= do_QueryInterface(mChannel
);
101 mUploadChannel
= do_QueryInterface(mChannel
);
106 ////////////////////////////////////////////////////////////////////////////////
107 // nsIRequest methods:
110 nsViewSourceChannel::GetName(nsACString
&result
)
112 return NS_ERROR_NOT_IMPLEMENTED
;
116 nsViewSourceChannel::IsPending(PRBool
*result
)
118 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
120 return mChannel
->IsPending(result
);
124 nsViewSourceChannel::GetStatus(nsresult
*status
)
126 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
128 return mChannel
->GetStatus(status
);
132 nsViewSourceChannel::Cancel(nsresult status
)
134 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
136 return mChannel
->Cancel(status
);
140 nsViewSourceChannel::Suspend(void)
142 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
144 return mChannel
->Suspend();
148 nsViewSourceChannel::Resume(void)
150 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
152 return mChannel
->Resume();
155 ////////////////////////////////////////////////////////////////////////////////
156 // nsIChannel methods:
159 nsViewSourceChannel::GetOriginalURI(nsIURI
* *aURI
)
161 NS_ASSERTION(aURI
, "Null out param!");
162 *aURI
= mOriginalURI
;
168 nsViewSourceChannel::SetOriginalURI(nsIURI
* aURI
)
170 NS_ENSURE_ARG_POINTER(aURI
);
176 nsViewSourceChannel::GetURI(nsIURI
* *aURI
)
178 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
180 nsCOMPtr
<nsIURI
> uri
;
181 nsresult rv
= mChannel
->GetURI(getter_AddRefs(uri
));
185 // protect ourselves against broken channel implementations
187 NS_ERROR("inner channel returned NS_OK and a null URI");
188 return NS_ERROR_UNEXPECTED
;
194 /* XXX Gross hack -- NS_NewURI goes into an infinite loop on
195 non-flat specs. See bug 136980 */
196 return NS_NewURI(aURI
, nsCAutoString(NS_LITERAL_CSTRING("view-source:")+spec
), nsnull
);
200 nsViewSourceChannel::Open(nsIInputStream
**_retval
)
202 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
204 nsresult rv
= mChannel
->Open(_retval
);
205 if (NS_SUCCEEDED(rv
)) {
213 nsViewSourceChannel::AsyncOpen(nsIStreamListener
*aListener
, nsISupports
*ctxt
)
215 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
217 mListener
= aListener
;
220 * We want to add ourselves to the loadgroup before opening
221 * mChannel, since we want to make sure we're in the loadgroup
222 * when mChannel finishes and fires OnStopRequest()
225 nsCOMPtr
<nsILoadGroup
> loadGroup
;
226 mChannel
->GetLoadGroup(getter_AddRefs(loadGroup
));
228 loadGroup
->AddRequest(static_cast<nsIViewSourceChannel
*>
231 nsresult rv
= mChannel
->AsyncOpen(this, ctxt
);
233 if (NS_FAILED(rv
) && loadGroup
)
234 loadGroup
->RemoveRequest(static_cast<nsIViewSourceChannel
*>
238 if (NS_SUCCEEDED(rv
)) {
246 * Both the view source channel and mChannel are added to the
247 * loadgroup. There should never be more than one request in the
248 * loadgroup that has LOAD_DOCUMENT_URI set. The one that has this
249 * flag set is the request whose URI is used to refetch the document,
250 * so it better be the viewsource channel.
252 * Therefore, we need to make sure that
253 * 1) The load flags on mChannel _never_ include LOAD_DOCUMENT_URI
254 * 2) The load flags on |this| include LOAD_DOCUMENT_URI when it was
255 * set via SetLoadFlags (mIsDocument keeps track of this flag).
259 nsViewSourceChannel::GetLoadFlags(PRUint32
*aLoadFlags
)
261 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
263 nsresult rv
= mChannel
->GetLoadFlags(aLoadFlags
);
267 // This should actually be just LOAD_DOCUMENT_URI but the win32 compiler
268 // fails to deal due to amiguous inheritance. nsIChannel::LOAD_DOCUMENT_URI
269 // also fails; the Win32 compiler thinks that's supposed to be a method.
271 *aLoadFlags
|= ::nsIChannel::LOAD_DOCUMENT_URI
;
277 nsViewSourceChannel::SetLoadFlags(PRUint32 aLoadFlags
)
279 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
281 // "View source" always wants the currently cached content.
282 // We also want to have _this_ channel, not mChannel to be the
283 // 'document' channel in the loadgroup.
285 // These should actually be just LOAD_FROM_CACHE and LOAD_DOCUMENT_URI but
286 // the win32 compiler fails to deal due to amiguous inheritance.
287 // nsIChannel::LOAD_DOCUMENT_URI/nsIRequest::LOAD_FROM_CACHE also fails; the
288 // Win32 compiler thinks that's supposed to be a method.
289 mIsDocument
= (aLoadFlags
& ::nsIChannel::LOAD_DOCUMENT_URI
) ? PR_TRUE
: PR_FALSE
;
291 return mChannel
->SetLoadFlags((aLoadFlags
|
292 ::nsIRequest::LOAD_FROM_CACHE
) &
293 ~::nsIChannel::LOAD_DOCUMENT_URI
);
297 nsViewSourceChannel::GetContentType(nsACString
&aContentType
)
299 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
301 aContentType
.Truncate();
303 if (mContentType
.IsEmpty())
305 // Get the current content type
307 nsCAutoString contentType
;
308 rv
= mChannel
->GetContentType(contentType
);
309 if (NS_FAILED(rv
)) return rv
;
311 // If we don't know our type, just say so. The unknown
312 // content decoder will then kick in automatically, and it
313 // will call our SetOriginalContentType method instead of our
314 // SetContentType method to set the type it determines.
315 if (!contentType
.Equals(UNKNOWN_CONTENT_TYPE
)) {
316 contentType
= VIEWSOURCE_CONTENT_TYPE
;
319 mContentType
= contentType
;
322 aContentType
= mContentType
;
327 nsViewSourceChannel::SetContentType(const nsACString
&aContentType
)
329 // Our GetContentType() currently returns VIEWSOURCE_CONTENT_TYPE
331 // However, during the parsing phase the parser calls our
332 // channel's GetContentType(). Returning the string above trips up
333 // the parser. In order to avoid messy changes and not to have the
334 // parser depend on nsIViewSourceChannel Vidur proposed the
335 // following solution:
337 // The ViewSourceChannel initially returns a content type of
338 // VIEWSOURCE_CONTENT_TYPE. Based on this type decisions to
339 // create a viewer for doing a view source are made. After the
340 // viewer is created, nsLayoutDLF::CreateInstance() calls this
341 // SetContentType() with the original content type. When it's
342 // time for the parser to find out the content type it will call
343 // our channel's GetContentType() and it will get the original
344 // content type, such as, text/html and everything is kosher from
348 // We do not take hints
349 return NS_ERROR_NOT_AVAILABLE
;
352 mContentType
= aContentType
;
357 nsViewSourceChannel::GetContentCharset(nsACString
&aContentCharset
)
359 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
361 return mChannel
->GetContentCharset(aContentCharset
);
365 nsViewSourceChannel::SetContentCharset(const nsACString
&aContentCharset
)
367 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
369 return mChannel
->SetContentCharset(aContentCharset
);
373 nsViewSourceChannel::GetContentLength(PRInt32
*aContentLength
)
375 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
377 return mChannel
->GetContentLength(aContentLength
);
381 nsViewSourceChannel::SetContentLength(PRInt32 aContentLength
)
383 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
385 return mChannel
->SetContentLength(aContentLength
);
389 nsViewSourceChannel::GetLoadGroup(nsILoadGroup
* *aLoadGroup
)
391 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
393 return mChannel
->GetLoadGroup(aLoadGroup
);
397 nsViewSourceChannel::SetLoadGroup(nsILoadGroup
* aLoadGroup
)
399 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
401 return mChannel
->SetLoadGroup(aLoadGroup
);
405 nsViewSourceChannel::GetOwner(nsISupports
* *aOwner
)
407 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
409 return mChannel
->GetOwner(aOwner
);
413 nsViewSourceChannel::SetOwner(nsISupports
* aOwner
)
415 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
417 return mChannel
->SetOwner(aOwner
);
421 nsViewSourceChannel::GetNotificationCallbacks(nsIInterfaceRequestor
* *aNotificationCallbacks
)
423 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
425 return mChannel
->GetNotificationCallbacks(aNotificationCallbacks
);
429 nsViewSourceChannel::SetNotificationCallbacks(nsIInterfaceRequestor
* aNotificationCallbacks
)
431 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
433 return mChannel
->SetNotificationCallbacks(aNotificationCallbacks
);
437 nsViewSourceChannel::GetSecurityInfo(nsISupports
* *aSecurityInfo
)
439 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
441 return mChannel
->GetSecurityInfo(aSecurityInfo
);
444 // nsIViewSourceChannel methods
446 nsViewSourceChannel::GetOriginalContentType(nsACString
&aContentType
)
448 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
450 return mChannel
->GetContentType(aContentType
);
454 nsViewSourceChannel::SetOriginalContentType(const nsACString
&aContentType
)
456 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
458 // clear our cached content-type value
459 mContentType
.Truncate();
461 return mChannel
->SetContentType(aContentType
);
464 // nsIRequestObserver methods
466 nsViewSourceChannel::OnStartRequest(nsIRequest
*aRequest
, nsISupports
*aContext
)
468 NS_ENSURE_TRUE(mListener
, NS_ERROR_FAILURE
);
469 // The channel may have gotten redirected... Time to update our info
470 mChannel
= do_QueryInterface(aRequest
);
471 mHttpChannel
= do_QueryInterface(aRequest
);
472 mCachingChannel
= do_QueryInterface(aRequest
);
473 mUploadChannel
= do_QueryInterface(aRequest
);
475 return mListener
->OnStartRequest(static_cast<nsIViewSourceChannel
*>
482 nsViewSourceChannel::OnStopRequest(nsIRequest
*aRequest
, nsISupports
* aContext
,
485 NS_ENSURE_TRUE(mListener
, NS_ERROR_FAILURE
);
488 nsCOMPtr
<nsILoadGroup
> loadGroup
;
489 mChannel
->GetLoadGroup(getter_AddRefs(loadGroup
));
492 loadGroup
->RemoveRequest(static_cast<nsIViewSourceChannel
*>
497 return mListener
->OnStopRequest(static_cast<nsIViewSourceChannel
*>
503 // nsIStreamListener methods
505 nsViewSourceChannel::OnDataAvailable(nsIRequest
*aRequest
, nsISupports
* aContext
,
506 nsIInputStream
*aInputStream
, PRUint32 aSourceOffset
,
509 NS_ENSURE_TRUE(mListener
, NS_ERROR_FAILURE
);
510 return mListener
->OnDataAvailable(static_cast<nsIViewSourceChannel
*>
512 aContext
, aInputStream
,
513 aSourceOffset
, aLength
);
517 // nsIHttpChannel methods
519 // We want to forward most of nsIHttpChannel over to mHttpChannel, but we want
520 // to override GetRequestHeader and VisitHeaders. The reason is that we don't
521 // want various headers like Link: and Refresh: applying to view-source.
523 nsViewSourceChannel::GetRequestMethod(nsACString
& aRequestMethod
)
525 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
526 mHttpChannel
->GetRequestMethod(aRequestMethod
);
530 nsViewSourceChannel::SetRequestMethod(const nsACString
& aRequestMethod
)
532 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
533 mHttpChannel
->SetRequestMethod(aRequestMethod
);
537 nsViewSourceChannel::GetReferrer(nsIURI
* *aReferrer
)
539 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
540 mHttpChannel
->GetReferrer(aReferrer
);
544 nsViewSourceChannel::SetReferrer(nsIURI
* aReferrer
)
546 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
547 mHttpChannel
->SetReferrer(aReferrer
);
551 nsViewSourceChannel::GetRequestHeader(const nsACString
& aHeader
,
554 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
555 mHttpChannel
->GetRequestHeader(aHeader
, aValue
);
559 nsViewSourceChannel::SetRequestHeader(const nsACString
& aHeader
,
560 const nsACString
& aValue
,
563 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
564 mHttpChannel
->SetRequestHeader(aHeader
, aValue
, aMerge
);
568 nsViewSourceChannel::VisitRequestHeaders(nsIHttpHeaderVisitor
*aVisitor
)
570 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
571 mHttpChannel
->VisitRequestHeaders(aVisitor
);
575 nsViewSourceChannel::GetAllowPipelining(PRBool
*aAllowPipelining
)
577 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
578 mHttpChannel
->GetAllowPipelining(aAllowPipelining
);
582 nsViewSourceChannel::SetAllowPipelining(PRBool aAllowPipelining
)
584 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
585 mHttpChannel
->SetAllowPipelining(aAllowPipelining
);
589 nsViewSourceChannel::GetRedirectionLimit(PRUint32
*aRedirectionLimit
)
591 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
592 mHttpChannel
->GetRedirectionLimit(aRedirectionLimit
);
596 nsViewSourceChannel::SetRedirectionLimit(PRUint32 aRedirectionLimit
)
598 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
599 mHttpChannel
->SetRedirectionLimit(aRedirectionLimit
);
603 nsViewSourceChannel::GetResponseStatus(PRUint32
*aResponseStatus
)
605 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
606 mHttpChannel
->GetResponseStatus(aResponseStatus
);
610 nsViewSourceChannel::GetResponseStatusText(nsACString
& aResponseStatusText
)
612 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
613 mHttpChannel
->GetResponseStatusText(aResponseStatusText
);
617 nsViewSourceChannel::GetRequestSucceeded(PRBool
*aRequestSucceeded
)
619 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
620 mHttpChannel
->GetRequestSucceeded(aRequestSucceeded
);
624 nsViewSourceChannel::GetResponseHeader(const nsACString
& aHeader
,
628 return NS_ERROR_NULL_POINTER
;
630 if (!aHeader
.Equals(NS_LITERAL_CSTRING("Content-Type"),
631 nsCaseInsensitiveCStringComparator())) {
636 return mHttpChannel
->GetResponseHeader(aHeader
, aValue
);
640 nsViewSourceChannel::SetResponseHeader(const nsACString
& header
,
641 const nsACString
& value
, PRBool merge
)
643 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
644 mHttpChannel
->SetResponseHeader(header
, value
, merge
);
648 nsViewSourceChannel::VisitResponseHeaders(nsIHttpHeaderVisitor
*aVisitor
)
651 return NS_ERROR_NULL_POINTER
;
653 NS_NAMED_LITERAL_CSTRING(contentTypeStr
, "Content-Type");
654 nsCAutoString contentType
;
656 mHttpChannel
->GetResponseHeader(contentTypeStr
, contentType
);
657 if (NS_SUCCEEDED(rv
))
658 aVisitor
->VisitHeader(contentTypeStr
, contentType
);
663 nsViewSourceChannel::IsNoStoreResponse(PRBool
*_retval
)
665 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
666 mHttpChannel
->IsNoStoreResponse(_retval
);
670 nsViewSourceChannel::IsNoCacheResponse(PRBool
*_retval
)
672 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
673 mHttpChannel
->IsNoCacheResponse(_retval
);