1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "nsDataChannel.h"
10 #include "mozilla/Base64.h"
11 #include "mozilla/dom/MimeType.h"
12 #include "nsDataHandler.h"
13 #include "nsIInputStream.h"
15 #include "nsStringStream.h"
16 #include "nsIObserverService.h"
17 #include "mozilla/dom/ContentParent.h"
19 using namespace mozilla
;
22 * Helper for performing a fallible unescape.
24 * @param aStr The string to unescape.
25 * @param aBuffer Buffer to unescape into if necessary.
26 * @param rv Out: nsresult indicating success or failure of unescaping.
27 * @return Reference to the string containing the unescaped data.
29 const nsACString
& Unescape(const nsACString
& aStr
, nsACString
& aBuffer
,
33 bool appended
= false;
34 *rv
= NS_UnescapeURL(aStr
.Data(), aStr
.Length(), /* aFlags = */ 0, aBuffer
,
35 appended
, mozilla::fallible
);
36 if (NS_FAILED(*rv
) || !appended
) {
43 nsresult
nsDataChannel::OpenContentStream(bool async
, nsIInputStream
** result
,
44 nsIChannel
** channel
) {
45 NS_ENSURE_TRUE(URI(), NS_ERROR_NOT_INITIALIZED
);
49 // In order to avoid potentially building up a new path including the
50 // ref portion of the URI, which we don't care about, we clone a version
51 // of the URI that does not have a ref and in most cases should share
52 // string buffers with the original URI.
54 rv
= NS_GetURIWithoutRef(URI(), getter_AddRefs(uri
));
55 if (NS_FAILED(rv
)) return rv
;
58 rv
= uri
->GetPathQueryRef(path
);
59 if (NS_FAILED(rv
)) return rv
;
61 nsCString contentType
, contentCharset
;
62 nsDependentCSubstring dataRange
;
63 RefPtr
<CMimeType
> fullMimeType
;
65 rv
= nsDataHandler::ParsePathWithoutRef(path
, contentType
, &contentCharset
,
66 lBase64
, &dataRange
, &fullMimeType
);
67 if (NS_FAILED(rv
)) return rv
;
69 // This will avoid a copy if nothing needs to be unescaped.
70 nsAutoCString unescapedBuffer
;
71 const nsACString
& data
= Unescape(dataRange
, unescapedBuffer
, &rv
);
76 if (lBase64
&& &data
== &unescapedBuffer
) {
77 // Don't allow spaces in base64-encoded content. This is only
78 // relevant for escaped spaces; other spaces are stripped in
79 // NewURI. We know there were no escaped spaces if the data buffer
80 // wasn't used in |Unescape|.
81 unescapedBuffer
.StripWhitespace();
84 nsCOMPtr
<nsIInputStream
> bufInStream
;
87 nsAutoCString decodedData
;
88 rv
= Base64Decode(data
, decodedData
);
90 // Returning this error code instead of what Base64Decode returns
91 // (NS_ERROR_ILLEGAL_VALUE) will prevent rendering of redirect response
92 // content by HTTP channels. It's also more logical error to return.
93 // Here we know the URL is actually corrupted.
94 return NS_ERROR_MALFORMED_URI
;
97 contentLen
= decodedData
.Length();
98 rv
= NS_NewCStringInputStream(getter_AddRefs(bufInStream
), decodedData
);
100 contentLen
= data
.Length();
101 rv
= NS_NewCStringInputStream(getter_AddRefs(bufInStream
), data
);
104 if (NS_FAILED(rv
)) return rv
;
106 SetContentType(contentType
);
107 SetContentCharset(contentCharset
);
108 SetFullMimeType(std::move(fullMimeType
));
109 mContentLength
= contentLen
;
111 // notify "data-channel-opened" observers
112 MaybeSendDataChannelOpenNotification();
114 bufInStream
.forget(result
);
119 nsresult
nsDataChannel::MaybeSendDataChannelOpenNotification() {
120 nsCOMPtr
<nsIObserverService
> obsService
= services::GetObserverService();
125 nsCOMPtr
<nsILoadInfo
> loadInfo
;
126 nsresult rv
= GetLoadInfo(getter_AddRefs(loadInfo
));
132 rv
= loadInfo
->GetIsTopLevelLoad(&isTopLevel
);
137 uint64_t browsingContextID
;
138 rv
= loadInfo
->GetBrowsingContextID(&browsingContextID
);
143 if ((browsingContextID
!= 0 && isTopLevel
) ||
144 !loadInfo
->TriggeringPrincipal()->IsSystemPrincipal()) {
145 obsService
->NotifyObservers(static_cast<nsIChannel
*>(this),
146 "data-channel-opened", nullptr);