Bug 1795723 - Unified extensions UI should support High Contrast Mode. r=ayeddi,deskt...
[gecko.git] / dom / security / nsHTTPSOnlyStreamListener.cpp
blob936cfd8cf66a20dc291c07334a420ad05c8cd115
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "NSSErrorsService.h"
8 #include "mozilla/Telemetry.h"
9 #include "mozilla/TimeStamp.h"
10 #include "mozilla/dom/WindowGlobalParent.h"
11 #include "mozpkix/pkixnss.h"
12 #include "nsCOMPtr.h"
13 #include "nsHTTPSOnlyStreamListener.h"
14 #include "nsHTTPSOnlyUtils.h"
15 #include "nsIChannel.h"
16 #include "nsIRequest.h"
17 #include "nsITransportSecurityInfo.h"
18 #include "nsIURI.h"
19 #include "nsPrintfCString.h"
20 #include "secerr.h"
21 #include "sslerr.h"
23 NS_IMPL_ISUPPORTS(nsHTTPSOnlyStreamListener, nsIStreamListener,
24 nsIRequestObserver)
26 nsHTTPSOnlyStreamListener::nsHTTPSOnlyStreamListener(
27 nsIStreamListener* aListener, nsILoadInfo* aLoadInfo)
28 : mListener(aListener), mCreationStart(mozilla::TimeStamp::Now()) {
29 RefPtr<mozilla::dom::WindowGlobalParent> wgp =
30 mozilla::dom::WindowGlobalParent::GetByInnerWindowId(
31 aLoadInfo->GetInnerWindowID());
32 // For Top-level document loads (which don't have a requesting window-context)
33 // we compute these flags once we create the Document in nsSecureBrowserUI.
34 if (wgp) {
35 wgp->TopWindowContext()->AddSecurityState(
36 nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED);
40 NS_IMETHODIMP
41 nsHTTPSOnlyStreamListener::OnDataAvailable(nsIRequest* aRequest,
42 nsIInputStream* aInputStream,
43 uint64_t aOffset, uint32_t aCount) {
44 return mListener->OnDataAvailable(aRequest, aInputStream, aOffset, aCount);
47 NS_IMETHODIMP
48 nsHTTPSOnlyStreamListener::OnStartRequest(nsIRequest* request) {
49 return mListener->OnStartRequest(request);
52 NS_IMETHODIMP
53 nsHTTPSOnlyStreamListener::OnStopRequest(nsIRequest* request,
54 nsresult aStatus) {
55 nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
57 // Note: CouldBeHttpsOnlyError also returns true if there was no error
58 if (nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(channel, aStatus)) {
59 RecordUpgradeTelemetry(request, aStatus);
60 LogUpgradeFailure(request, aStatus);
62 // If the request failed and there is a requesting window-context, set
63 // HTTPS-Only state flag to indicate a failed upgrade.
64 // For Top-level document loads (which don't have a requesting
65 // window-context) we simply check in the UI code whether we landed on the
66 // HTTPS-Only error page.
67 if (NS_FAILED(aStatus)) {
68 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
69 RefPtr<mozilla::dom::WindowGlobalParent> wgp =
70 mozilla::dom::WindowGlobalParent::GetByInnerWindowId(
71 loadInfo->GetInnerWindowID());
73 if (wgp) {
74 wgp->TopWindowContext()->AddSecurityState(
75 nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADE_FAILED);
80 return mListener->OnStopRequest(request, aStatus);
83 void nsHTTPSOnlyStreamListener::RecordUpgradeTelemetry(nsIRequest* request,
84 nsresult aStatus) {
85 // 1. Get time between now and when the initial upgrade request started
86 int64_t duration =
87 (mozilla::TimeStamp::Now() - mCreationStart).ToMilliseconds();
89 // 2. Assemble the category string
90 // [!] All strings have to be present in Histograms.json
91 nsresult rv;
92 nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
93 if (NS_FAILED(rv)) {
94 return;
97 nsAutoCString category;
98 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
99 nsContentPolicyType internalType = loadInfo->InternalContentPolicyType();
101 if (internalType == nsIContentPolicy::TYPE_DOCUMENT) {
102 category.AppendLiteral("top_");
103 } else {
104 category.AppendLiteral("sub_");
107 if (NS_SUCCEEDED(aStatus)) {
108 category.AppendLiteral("successful");
109 } else {
110 int32_t code = -1 * NS_ERROR_GET_CODE(aStatus);
112 if (aStatus == NS_ERROR_REDIRECT_LOOP) {
113 category.AppendLiteral("f_redirectloop");
114 } else if (aStatus == NS_ERROR_NET_TIMEOUT ||
115 aStatus == NS_ERROR_NET_TIMEOUT_EXTERNAL) {
116 category.AppendLiteral("f_timeout");
117 } else if (aStatus == NS_BINDING_ABORTED) {
118 category.AppendLiteral("f_aborted");
119 } else if (aStatus == NS_ERROR_CONNECTION_REFUSED) {
120 category.AppendLiteral("f_cxnrefused");
121 } else if (mozilla::psm::IsNSSErrorCode(code)) {
122 switch (code) {
123 case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
124 category.AppendLiteral("f_ssl_selfsignd");
125 break;
126 case SSL_ERROR_BAD_CERT_DOMAIN:
127 category.AppendLiteral("f_ssl_badcertdm");
128 break;
129 case SEC_ERROR_UNKNOWN_ISSUER:
130 category.AppendLiteral("f_ssl_unkwnissr");
131 break;
132 default:
133 category.AppendLiteral("f_ssl_other");
134 break;
136 } else {
137 category.AppendLiteral("f_other");
140 mozilla::Telemetry::Accumulate(
141 mozilla::Telemetry::HTTPS_ONLY_MODE_UPGRADE_TIME_MS, category, duration);
143 bool success = NS_SUCCEEDED(aStatus);
144 ExtContentPolicyType externalType = loadInfo->GetExternalContentPolicyType();
145 auto typeKey = nsAutoCString("unknown");
147 if (externalType == ExtContentPolicy::TYPE_MEDIA) {
148 switch (internalType) {
149 case nsIContentPolicy::TYPE_INTERNAL_AUDIO:
150 case nsIContentPolicy::TYPE_INTERNAL_TRACK:
151 typeKey = "audio"_ns;
152 break;
154 case nsIContentPolicy::TYPE_INTERNAL_VIDEO:
155 typeKey = "video"_ns;
156 break;
158 default:
159 MOZ_ASSERT_UNREACHABLE();
160 break;
162 } else {
163 switch (externalType) {
164 case ExtContentPolicy::TYPE_SCRIPT:
165 typeKey = "script"_ns;
166 break;
168 case ExtContentPolicy::TYPE_OBJECT:
169 case ExtContentPolicy::TYPE_OBJECT_SUBREQUEST:
170 typeKey = "object"_ns;
171 break;
173 case ExtContentPolicy::TYPE_DOCUMENT:
174 typeKey = "document"_ns;
175 break;
177 case ExtContentPolicy::TYPE_SUBDOCUMENT:
178 typeKey = "subdocument"_ns;
179 break;
181 case ExtContentPolicy::TYPE_XMLHTTPREQUEST:
182 typeKey = "xmlhttprequest"_ns;
183 break;
185 case ExtContentPolicy::TYPE_IMAGE:
186 case ExtContentPolicy::TYPE_IMAGESET:
187 typeKey = "image"_ns;
188 break;
190 case ExtContentPolicy::TYPE_DTD:
191 typeKey = "dtd"_ns;
192 break;
194 case ExtContentPolicy::TYPE_FONT:
195 case ExtContentPolicy::TYPE_UA_FONT:
196 typeKey = "font"_ns;
197 break;
199 case ExtContentPolicy::TYPE_FETCH:
200 typeKey = "fetch"_ns;
201 break;
203 case ExtContentPolicy::TYPE_WEBSOCKET:
204 typeKey = "websocket"_ns;
205 break;
207 case ExtContentPolicy::TYPE_STYLESHEET:
208 typeKey = "stylesheet"_ns;
209 break;
211 case ExtContentPolicy::TYPE_CSP_REPORT:
212 typeKey = "cspreport"_ns;
213 break;
215 case ExtContentPolicy::TYPE_WEB_MANIFEST:
216 typeKey = "webmanifest"_ns;
217 break;
219 case ExtContentPolicy::TYPE_PING:
220 typeKey = "ping"_ns;
221 break;
223 case ExtContentPolicy::TYPE_XSLT:
224 typeKey = "xslt"_ns;
225 break;
227 case ExtContentPolicy::TYPE_PROXIED_WEBRTC_MEDIA:
228 typeKey = "proxied-webrtc"_ns;
229 break;
231 case ExtContentPolicy::TYPE_INVALID:
232 case ExtContentPolicy::TYPE_OTHER:
233 case ExtContentPolicy::TYPE_MEDIA: // already handled above
234 case ExtContentPolicy::TYPE_BEACON:
235 case ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD:
236 case ExtContentPolicy::TYPE_SPECULATIVE:
237 break;
238 // Do not add default: so that compilers can catch the missing case.
242 mozilla::Telemetry::Accumulate(
243 mozilla::Telemetry::HTTPS_ONLY_MODE_UPGRADE_TYPE, typeKey, success);
246 void nsHTTPSOnlyStreamListener::LogUpgradeFailure(nsIRequest* request,
247 nsresult aStatus) {
248 // If the request failed we'll log it to the console with the error-code
249 if (NS_SUCCEEDED(aStatus)) {
250 return;
252 nsresult rv;
253 // Try to query for the channel-object
254 nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
255 if (NS_FAILED(rv)) {
256 return;
259 nsCOMPtr<nsIURI> uri;
260 rv = channel->GetURI(getter_AddRefs(uri));
261 if (NS_FAILED(rv)) {
262 return;
264 // Logging URI as well as Module- and Error-Code
265 AutoTArray<nsString, 2> params = {
266 NS_ConvertUTF8toUTF16(uri->GetSpecOrDefault()),
267 NS_ConvertUTF8toUTF16(nsPrintfCString("M%u-C%u",
268 NS_ERROR_GET_MODULE(aStatus),
269 NS_ERROR_GET_CODE(aStatus)))};
271 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
272 nsHTTPSOnlyUtils::LogLocalizedString("HTTPSOnlyFailedRequest", params,
273 nsIScriptError::errorFlag, loadInfo,
274 uri);