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(nsIHttpChannelInternal
, mHttpChannelInternal
)
64 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICachingChannel
, mCachingChannel
)
65 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIUploadChannel
, mUploadChannel
)
66 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIRequest
, nsIViewSourceChannel
)
67 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIChannel
, nsIViewSourceChannel
)
68 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIViewSourceChannel
)
72 nsViewSourceChannel::Init(nsIURI
* uri
)
77 nsresult rv
= uri
->GetPath(path
);
81 nsCOMPtr
<nsIIOService
> pService(do_GetIOService(&rv
));
82 if (NS_FAILED(rv
)) return rv
;
85 rv
= pService
->ExtractScheme(path
, scheme
);
89 // prevent viewing source of javascript URIs (see bug 204779)
90 if (scheme
.LowerCaseEqualsLiteral("javascript")) {
91 NS_WARNING("blocking view-source:javascript:");
92 return NS_ERROR_INVALID_ARG
;
95 rv
= pService
->NewChannel(path
, nsnull
, nsnull
, getter_AddRefs(mChannel
));
99 mChannel
->SetOriginalURI(mOriginalURI
);
100 mHttpChannel
= do_QueryInterface(mChannel
);
101 mHttpChannelInternal
= do_QueryInterface(mChannel
);
102 mCachingChannel
= do_QueryInterface(mChannel
);
103 mUploadChannel
= do_QueryInterface(mChannel
);
108 ////////////////////////////////////////////////////////////////////////////////
109 // nsIRequest methods:
112 nsViewSourceChannel::GetName(nsACString
&result
)
114 return NS_ERROR_NOT_IMPLEMENTED
;
118 nsViewSourceChannel::IsPending(PRBool
*result
)
120 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
122 return mChannel
->IsPending(result
);
126 nsViewSourceChannel::GetStatus(nsresult
*status
)
128 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
130 return mChannel
->GetStatus(status
);
134 nsViewSourceChannel::Cancel(nsresult status
)
136 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
138 return mChannel
->Cancel(status
);
142 nsViewSourceChannel::Suspend(void)
144 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
146 return mChannel
->Suspend();
150 nsViewSourceChannel::Resume(void)
152 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
154 return mChannel
->Resume();
157 ////////////////////////////////////////////////////////////////////////////////
158 // nsIChannel methods:
161 nsViewSourceChannel::GetOriginalURI(nsIURI
* *aURI
)
163 NS_ASSERTION(aURI
, "Null out param!");
164 *aURI
= mOriginalURI
;
170 nsViewSourceChannel::SetOriginalURI(nsIURI
* aURI
)
172 NS_ENSURE_ARG_POINTER(aURI
);
178 nsViewSourceChannel::GetURI(nsIURI
* *aURI
)
180 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
182 nsCOMPtr
<nsIURI
> uri
;
183 nsresult rv
= mChannel
->GetURI(getter_AddRefs(uri
));
187 // protect ourselves against broken channel implementations
189 NS_ERROR("inner channel returned NS_OK and a null URI");
190 return NS_ERROR_UNEXPECTED
;
196 /* XXX Gross hack -- NS_NewURI goes into an infinite loop on
197 non-flat specs. See bug 136980 */
198 return NS_NewURI(aURI
, nsCAutoString(NS_LITERAL_CSTRING("view-source:")+spec
), nsnull
);
202 nsViewSourceChannel::Open(nsIInputStream
**_retval
)
204 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
206 nsresult rv
= mChannel
->Open(_retval
);
207 if (NS_SUCCEEDED(rv
)) {
215 nsViewSourceChannel::AsyncOpen(nsIStreamListener
*aListener
, nsISupports
*ctxt
)
217 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
219 mListener
= aListener
;
222 * We want to add ourselves to the loadgroup before opening
223 * mChannel, since we want to make sure we're in the loadgroup
224 * when mChannel finishes and fires OnStopRequest()
227 nsCOMPtr
<nsILoadGroup
> loadGroup
;
228 mChannel
->GetLoadGroup(getter_AddRefs(loadGroup
));
230 loadGroup
->AddRequest(static_cast<nsIViewSourceChannel
*>
233 nsresult rv
= mChannel
->AsyncOpen(this, ctxt
);
235 if (NS_FAILED(rv
) && loadGroup
)
236 loadGroup
->RemoveRequest(static_cast<nsIViewSourceChannel
*>
240 if (NS_SUCCEEDED(rv
)) {
248 * Both the view source channel and mChannel are added to the
249 * loadgroup. There should never be more than one request in the
250 * loadgroup that has LOAD_DOCUMENT_URI set. The one that has this
251 * flag set is the request whose URI is used to refetch the document,
252 * so it better be the viewsource channel.
254 * Therefore, we need to make sure that
255 * 1) The load flags on mChannel _never_ include LOAD_DOCUMENT_URI
256 * 2) The load flags on |this| include LOAD_DOCUMENT_URI when it was
257 * set via SetLoadFlags (mIsDocument keeps track of this flag).
261 nsViewSourceChannel::GetLoadFlags(PRUint32
*aLoadFlags
)
263 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
265 nsresult rv
= mChannel
->GetLoadFlags(aLoadFlags
);
269 // This should actually be just LOAD_DOCUMENT_URI but the win32 compiler
270 // fails to deal due to amiguous inheritance. nsIChannel::LOAD_DOCUMENT_URI
271 // also fails; the Win32 compiler thinks that's supposed to be a method.
273 *aLoadFlags
|= ::nsIChannel::LOAD_DOCUMENT_URI
;
279 nsViewSourceChannel::SetLoadFlags(PRUint32 aLoadFlags
)
281 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
283 // "View source" always wants the currently cached content.
284 // We also want to have _this_ channel, not mChannel to be the
285 // 'document' channel in the loadgroup.
287 // These should actually be just LOAD_FROM_CACHE and LOAD_DOCUMENT_URI but
288 // the win32 compiler fails to deal due to amiguous inheritance.
289 // nsIChannel::LOAD_DOCUMENT_URI/nsIRequest::LOAD_FROM_CACHE also fails; the
290 // Win32 compiler thinks that's supposed to be a method.
291 mIsDocument
= (aLoadFlags
& ::nsIChannel::LOAD_DOCUMENT_URI
) ? PR_TRUE
: PR_FALSE
;
293 return mChannel
->SetLoadFlags((aLoadFlags
|
294 ::nsIRequest::LOAD_FROM_CACHE
) &
295 ~::nsIChannel::LOAD_DOCUMENT_URI
);
299 nsViewSourceChannel::GetContentType(nsACString
&aContentType
)
301 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
303 aContentType
.Truncate();
305 if (mContentType
.IsEmpty())
307 // Get the current content type
309 nsCAutoString contentType
;
310 rv
= mChannel
->GetContentType(contentType
);
311 if (NS_FAILED(rv
)) return rv
;
313 // If we don't know our type, just say so. The unknown
314 // content decoder will then kick in automatically, and it
315 // will call our SetOriginalContentType method instead of our
316 // SetContentType method to set the type it determines.
317 if (!contentType
.Equals(UNKNOWN_CONTENT_TYPE
)) {
318 contentType
= VIEWSOURCE_CONTENT_TYPE
;
321 mContentType
= contentType
;
324 aContentType
= mContentType
;
329 nsViewSourceChannel::SetContentType(const nsACString
&aContentType
)
331 // Our GetContentType() currently returns VIEWSOURCE_CONTENT_TYPE
333 // However, during the parsing phase the parser calls our
334 // channel's GetContentType(). Returning the string above trips up
335 // the parser. In order to avoid messy changes and not to have the
336 // parser depend on nsIViewSourceChannel Vidur proposed the
337 // following solution:
339 // The ViewSourceChannel initially returns a content type of
340 // VIEWSOURCE_CONTENT_TYPE. Based on this type decisions to
341 // create a viewer for doing a view source are made. After the
342 // viewer is created, nsLayoutDLF::CreateInstance() calls this
343 // SetContentType() with the original content type. When it's
344 // time for the parser to find out the content type it will call
345 // our channel's GetContentType() and it will get the original
346 // content type, such as, text/html and everything is kosher from
350 // We do not take hints
351 return NS_ERROR_NOT_AVAILABLE
;
354 mContentType
= aContentType
;
359 nsViewSourceChannel::GetContentCharset(nsACString
&aContentCharset
)
361 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
363 return mChannel
->GetContentCharset(aContentCharset
);
367 nsViewSourceChannel::SetContentCharset(const nsACString
&aContentCharset
)
369 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
371 return mChannel
->SetContentCharset(aContentCharset
);
375 nsViewSourceChannel::GetContentLength(PRInt32
*aContentLength
)
377 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
379 return mChannel
->GetContentLength(aContentLength
);
383 nsViewSourceChannel::SetContentLength(PRInt32 aContentLength
)
385 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
387 return mChannel
->SetContentLength(aContentLength
);
391 nsViewSourceChannel::GetLoadGroup(nsILoadGroup
* *aLoadGroup
)
393 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
395 return mChannel
->GetLoadGroup(aLoadGroup
);
399 nsViewSourceChannel::SetLoadGroup(nsILoadGroup
* aLoadGroup
)
401 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
403 return mChannel
->SetLoadGroup(aLoadGroup
);
407 nsViewSourceChannel::GetOwner(nsISupports
* *aOwner
)
409 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
411 return mChannel
->GetOwner(aOwner
);
415 nsViewSourceChannel::SetOwner(nsISupports
* aOwner
)
417 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
419 return mChannel
->SetOwner(aOwner
);
423 nsViewSourceChannel::GetNotificationCallbacks(nsIInterfaceRequestor
* *aNotificationCallbacks
)
425 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
427 return mChannel
->GetNotificationCallbacks(aNotificationCallbacks
);
431 nsViewSourceChannel::SetNotificationCallbacks(nsIInterfaceRequestor
* aNotificationCallbacks
)
433 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
435 return mChannel
->SetNotificationCallbacks(aNotificationCallbacks
);
439 nsViewSourceChannel::GetSecurityInfo(nsISupports
* *aSecurityInfo
)
441 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
443 return mChannel
->GetSecurityInfo(aSecurityInfo
);
446 // nsIViewSourceChannel methods
448 nsViewSourceChannel::GetOriginalContentType(nsACString
&aContentType
)
450 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
452 return mChannel
->GetContentType(aContentType
);
456 nsViewSourceChannel::SetOriginalContentType(const nsACString
&aContentType
)
458 NS_ENSURE_TRUE(mChannel
, NS_ERROR_FAILURE
);
460 // clear our cached content-type value
461 mContentType
.Truncate();
463 return mChannel
->SetContentType(aContentType
);
466 // nsIRequestObserver methods
468 nsViewSourceChannel::OnStartRequest(nsIRequest
*aRequest
, nsISupports
*aContext
)
470 NS_ENSURE_TRUE(mListener
, NS_ERROR_FAILURE
);
471 // The channel may have gotten redirected... Time to update our info
472 mChannel
= do_QueryInterface(aRequest
);
473 mHttpChannel
= do_QueryInterface(aRequest
);
474 mCachingChannel
= do_QueryInterface(aRequest
);
475 mUploadChannel
= do_QueryInterface(aRequest
);
477 return mListener
->OnStartRequest(static_cast<nsIViewSourceChannel
*>
484 nsViewSourceChannel::OnStopRequest(nsIRequest
*aRequest
, nsISupports
* aContext
,
487 NS_ENSURE_TRUE(mListener
, NS_ERROR_FAILURE
);
490 nsCOMPtr
<nsILoadGroup
> loadGroup
;
491 mChannel
->GetLoadGroup(getter_AddRefs(loadGroup
));
494 loadGroup
->RemoveRequest(static_cast<nsIViewSourceChannel
*>
499 return mListener
->OnStopRequest(static_cast<nsIViewSourceChannel
*>
505 // nsIStreamListener methods
507 nsViewSourceChannel::OnDataAvailable(nsIRequest
*aRequest
, nsISupports
* aContext
,
508 nsIInputStream
*aInputStream
, PRUint32 aSourceOffset
,
511 NS_ENSURE_TRUE(mListener
, NS_ERROR_FAILURE
);
512 return mListener
->OnDataAvailable(static_cast<nsIViewSourceChannel
*>
514 aContext
, aInputStream
,
515 aSourceOffset
, aLength
);
519 // nsIHttpChannel methods
521 // We want to forward most of nsIHttpChannel over to mHttpChannel, but we want
522 // to override GetRequestHeader and VisitHeaders. The reason is that we don't
523 // want various headers like Link: and Refresh: applying to view-source.
525 nsViewSourceChannel::GetRequestMethod(nsACString
& aRequestMethod
)
527 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
528 mHttpChannel
->GetRequestMethod(aRequestMethod
);
532 nsViewSourceChannel::SetRequestMethod(const nsACString
& aRequestMethod
)
534 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
535 mHttpChannel
->SetRequestMethod(aRequestMethod
);
539 nsViewSourceChannel::GetReferrer(nsIURI
* *aReferrer
)
541 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
542 mHttpChannel
->GetReferrer(aReferrer
);
546 nsViewSourceChannel::SetReferrer(nsIURI
* aReferrer
)
548 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
549 mHttpChannel
->SetReferrer(aReferrer
);
553 nsViewSourceChannel::GetRequestHeader(const nsACString
& aHeader
,
556 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
557 mHttpChannel
->GetRequestHeader(aHeader
, aValue
);
561 nsViewSourceChannel::SetRequestHeader(const nsACString
& aHeader
,
562 const nsACString
& aValue
,
565 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
566 mHttpChannel
->SetRequestHeader(aHeader
, aValue
, aMerge
);
570 nsViewSourceChannel::VisitRequestHeaders(nsIHttpHeaderVisitor
*aVisitor
)
572 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
573 mHttpChannel
->VisitRequestHeaders(aVisitor
);
577 nsViewSourceChannel::GetAllowPipelining(PRBool
*aAllowPipelining
)
579 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
580 mHttpChannel
->GetAllowPipelining(aAllowPipelining
);
584 nsViewSourceChannel::SetAllowPipelining(PRBool aAllowPipelining
)
586 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
587 mHttpChannel
->SetAllowPipelining(aAllowPipelining
);
591 nsViewSourceChannel::GetRedirectionLimit(PRUint32
*aRedirectionLimit
)
593 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
594 mHttpChannel
->GetRedirectionLimit(aRedirectionLimit
);
598 nsViewSourceChannel::SetRedirectionLimit(PRUint32 aRedirectionLimit
)
600 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
601 mHttpChannel
->SetRedirectionLimit(aRedirectionLimit
);
605 nsViewSourceChannel::GetResponseStatus(PRUint32
*aResponseStatus
)
607 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
608 mHttpChannel
->GetResponseStatus(aResponseStatus
);
612 nsViewSourceChannel::GetResponseStatusText(nsACString
& aResponseStatusText
)
614 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
615 mHttpChannel
->GetResponseStatusText(aResponseStatusText
);
619 nsViewSourceChannel::GetRequestSucceeded(PRBool
*aRequestSucceeded
)
621 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
622 mHttpChannel
->GetRequestSucceeded(aRequestSucceeded
);
626 nsViewSourceChannel::GetResponseHeader(const nsACString
& aHeader
,
630 return NS_ERROR_NULL_POINTER
;
632 if (!aHeader
.Equals(NS_LITERAL_CSTRING("Content-Type"),
633 nsCaseInsensitiveCStringComparator()) &&
634 !aHeader
.Equals(NS_LITERAL_CSTRING("X-Content-Security-Policy"),
635 nsCaseInsensitiveCStringComparator()) &&
636 !aHeader
.Equals(NS_LITERAL_CSTRING("X-Content-Security-Policy-Report-Only"),
637 nsCaseInsensitiveCStringComparator()) &&
638 !aHeader
.Equals(NS_LITERAL_CSTRING("X-Frame-Options"),
639 nsCaseInsensitiveCStringComparator())) {
644 return mHttpChannel
->GetResponseHeader(aHeader
, aValue
);
648 nsViewSourceChannel::SetResponseHeader(const nsACString
& header
,
649 const nsACString
& value
, PRBool merge
)
651 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
652 mHttpChannel
->SetResponseHeader(header
, value
, merge
);
656 nsViewSourceChannel::VisitResponseHeaders(nsIHttpHeaderVisitor
*aVisitor
)
659 return NS_ERROR_NULL_POINTER
;
661 NS_NAMED_LITERAL_CSTRING(contentTypeStr
, "Content-Type");
662 nsCAutoString contentType
;
664 mHttpChannel
->GetResponseHeader(contentTypeStr
, contentType
);
665 if (NS_SUCCEEDED(rv
))
666 aVisitor
->VisitHeader(contentTypeStr
, contentType
);
671 nsViewSourceChannel::IsNoStoreResponse(PRBool
*_retval
)
673 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
674 mHttpChannel
->IsNoStoreResponse(_retval
);
678 nsViewSourceChannel::IsNoCacheResponse(PRBool
*_retval
)
680 return !mHttpChannel
? NS_ERROR_NULL_POINTER
:
681 mHttpChannel
->IsNoCacheResponse(_retval
);