1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998-2001
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Hubbie Shaw
24 : * Doug Turner <dougt@netscape.com>
25 : * Stuart Parmenter <pavlov@netscape.com>
26 : * Brian Ryner <bryner@brianryner.com>
27 : * Terry Hayes <thayes@netscape.com>
28 : * Kai Engert <kaie@netscape.com>
29 : *
30 : * Alternatively, the contents of this file may be used under the terms of
31 : * either the GNU General Public License Version 2 or later (the "GPL"), or
32 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 : * in which case the provisions of the GPL or the LGPL are applicable instead
34 : * of those above. If you wish to allow use of your version of this file only
35 : * under the terms of either the GPL or the LGPL, and not to allow others to
36 : * use your version of this file under the terms of the MPL, indicate your
37 : * decision by deleting the provisions above and replace them with the notice
38 : * and other provisions required by the GPL or the LGPL. If you do not delete
39 : * the provisions above, a recipient may use your version of this file under
40 : * the terms of any one of the MPL, the GPL or the LGPL.
41 : *
42 : * ***** END LICENSE BLOCK ***** */
43 :
44 : #ifdef MOZ_LOGGING
45 : #define FORCE_PR_LOG
46 : #endif
47 :
48 : #include "nspr.h"
49 : #include "prlog.h"
50 : #include "prmem.h"
51 :
52 : #include "nsISecureBrowserUI.h"
53 : #include "nsSecureBrowserUIImpl.h"
54 : #include "nsCOMPtr.h"
55 : #include "nsIInterfaceRequestor.h"
56 : #include "nsIInterfaceRequestorUtils.h"
57 : #include "nsIServiceManager.h"
58 : #include "nsIObserverService.h"
59 : #include "nsCURILoader.h"
60 : #include "nsIDocShell.h"
61 : #include "nsIDocument.h"
62 : #include "nsIPrincipal.h"
63 : #include "nsIDOMElement.h"
64 : #include "nsPIDOMWindow.h"
65 : #include "nsIContent.h"
66 : #include "nsIWebProgress.h"
67 : #include "nsIWebProgressListener.h"
68 : #include "nsIChannel.h"
69 : #include "nsIHttpChannel.h"
70 : #include "nsIFileChannel.h"
71 : #include "nsIWyciwygChannel.h"
72 : #include "nsIFTPChannel.h"
73 : #include "nsITransportSecurityInfo.h"
74 : #include "nsISSLStatus.h"
75 : #include "nsIURI.h"
76 : #include "nsISecurityEventSink.h"
77 : #include "nsIPrompt.h"
78 : #include "nsIFormSubmitObserver.h"
79 : #include "nsISecurityWarningDialogs.h"
80 : #include "nsISecurityInfoProvider.h"
81 : #include "imgIRequest.h"
82 : #include "nsThreadUtils.h"
83 : #include "nsNetUtil.h"
84 : #include "nsNetCID.h"
85 : #include "nsCRT.h"
86 :
87 : using namespace mozilla;
88 :
89 : #define SECURITY_STRING_BUNDLE_URL "chrome://pipnss/locale/security.properties"
90 :
91 : #define IS_SECURE(state) ((state & 0xFFFF) == STATE_IS_SECURE)
92 :
93 : #if defined(PR_LOGGING)
94 : //
95 : // Log module for nsSecureBrowserUI logging...
96 : //
97 : // To enable logging (see prlog.h for full details):
98 : //
99 : // set NSPR_LOG_MODULES=nsSecureBrowserUI:5
100 : // set NSPR_LOG_FILE=nspr.log
101 : //
102 : // this enables PR_LOG_DEBUG level information and places all output in
103 : // the file nspr.log
104 : //
105 : PRLogModuleInfo* gSecureDocLog = nsnull;
106 : #endif /* PR_LOGGING */
107 :
108 : struct RequestHashEntry : PLDHashEntryHdr {
109 : void *r;
110 : };
111 :
112 : PR_STATIC_CALLBACK(bool)
113 0 : RequestMapMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
114 : const void *key)
115 : {
116 0 : const RequestHashEntry *entry = static_cast<const RequestHashEntry*>(hdr);
117 0 : return entry->r == key;
118 : }
119 :
120 : PR_STATIC_CALLBACK(bool)
121 0 : RequestMapInitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
122 : const void *key)
123 : {
124 0 : RequestHashEntry *entry = static_cast<RequestHashEntry*>(hdr);
125 0 : entry->r = (void*)key;
126 0 : return true;
127 : }
128 :
129 : static PLDHashTableOps gMapOps = {
130 : PL_DHashAllocTable,
131 : PL_DHashFreeTable,
132 : PL_DHashVoidPtrKeyStub,
133 : RequestMapMatchEntry,
134 : PL_DHashMoveEntryStub,
135 : PL_DHashClearEntryStub,
136 : PL_DHashFinalizeStub,
137 : RequestMapInitEntry
138 : };
139 :
140 : #ifdef DEBUG
141 : class nsAutoAtomic {
142 : public:
143 0 : nsAutoAtomic(PRInt32 &i)
144 0 : :mI(i) {
145 0 : PR_ATOMIC_INCREMENT(&mI);
146 0 : }
147 :
148 0 : ~nsAutoAtomic() {
149 0 : PR_ATOMIC_DECREMENT(&mI);
150 0 : }
151 :
152 : protected:
153 : PRInt32 &mI;
154 :
155 : private:
156 : nsAutoAtomic(); // not accessible
157 : };
158 : #endif
159 :
160 0 : nsSecureBrowserUIImpl::nsSecureBrowserUIImpl()
161 : : mReentrantMonitor("nsSecureBrowserUIImpl.mReentrantMonitor")
162 : , mNotifiedSecurityState(lis_no_security)
163 : , mNotifiedToplevelIsEV(false)
164 : , mNewToplevelSecurityState(STATE_IS_INSECURE)
165 : , mNewToplevelIsEV(false)
166 : , mNewToplevelSecurityStateKnown(true)
167 : , mIsViewSource(false)
168 : , mSubRequestsHighSecurity(0)
169 : , mSubRequestsLowSecurity(0)
170 : , mSubRequestsBrokenSecurity(0)
171 : , mSubRequestsNoSecurity(0)
172 : #ifdef DEBUG
173 0 : , mOnStateLocationChangeReentranceDetection(0)
174 : #endif
175 : {
176 0 : mTransferringRequests.ops = nsnull;
177 0 : ResetStateTracking();
178 :
179 : #if defined(PR_LOGGING)
180 0 : if (!gSecureDocLog)
181 0 : gSecureDocLog = PR_NewLogModule("nsSecureBrowserUI");
182 : #endif /* PR_LOGGING */
183 0 : }
184 :
185 0 : nsSecureBrowserUIImpl::~nsSecureBrowserUIImpl()
186 : {
187 0 : if (mTransferringRequests.ops) {
188 0 : PL_DHashTableFinish(&mTransferringRequests);
189 0 : mTransferringRequests.ops = nsnull;
190 : }
191 0 : }
192 :
193 0 : NS_IMPL_THREADSAFE_ISUPPORTS6(nsSecureBrowserUIImpl,
194 : nsISecureBrowserUI,
195 : nsIWebProgressListener,
196 : nsIFormSubmitObserver,
197 : nsIObserver,
198 : nsISupportsWeakReference,
199 : nsISSLStatusProvider)
200 :
201 : NS_IMETHODIMP
202 0 : nsSecureBrowserUIImpl::Init(nsIDOMWindow *aWindow)
203 : {
204 :
205 : #ifdef PR_LOGGING
206 0 : nsCOMPtr<nsIDOMWindow> window(do_QueryReferent(mWindow));
207 :
208 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
209 : ("SecureUI:%p: Init: mWindow: %p, aWindow: %p\n", this,
210 : window.get(), aWindow));
211 : #endif
212 :
213 0 : if (!aWindow) {
214 0 : NS_WARNING("Null window passed to nsSecureBrowserUIImpl::Init()");
215 0 : return NS_ERROR_INVALID_ARG;
216 : }
217 :
218 0 : if (mWindow) {
219 0 : NS_WARNING("Trying to init an nsSecureBrowserUIImpl twice");
220 0 : return NS_ERROR_ALREADY_INITIALIZED;
221 : }
222 :
223 0 : nsCOMPtr<nsPIDOMWindow> pwin(do_QueryInterface(aWindow));
224 0 : if (pwin->IsInnerWindow()) {
225 0 : pwin = pwin->GetOuterWindow();
226 : }
227 :
228 : nsresult rv;
229 0 : mWindow = do_GetWeakReference(pwin, &rv);
230 0 : NS_ENSURE_SUCCESS(rv, rv);
231 :
232 0 : nsCOMPtr<nsIStringBundleService> service(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
233 0 : if (NS_FAILED(rv)) return rv;
234 :
235 : // We do not need to test for mStringBundle here...
236 : // Anywhere we use it, we will test before using. Some
237 : // embedded users of PSM may want to reuse our
238 : // nsSecureBrowserUIImpl implementation without the
239 : // bundle.
240 0 : service->CreateBundle(SECURITY_STRING_BUNDLE_URL, getter_AddRefs(mStringBundle));
241 :
242 :
243 : // hook up to the form post notifications:
244 0 : nsCOMPtr<nsIObserverService> svc(do_GetService("@mozilla.org/observer-service;1", &rv));
245 0 : if (NS_SUCCEEDED(rv)) {
246 0 : rv = svc->AddObserver(this, NS_FORMSUBMIT_SUBJECT, true);
247 : }
248 :
249 0 : nsCOMPtr<nsPIDOMWindow> piwindow(do_QueryInterface(aWindow));
250 0 : if (!piwindow) return NS_ERROR_FAILURE;
251 :
252 0 : nsIDocShell *docShell = piwindow->GetDocShell();
253 :
254 : // The Docshell will own the SecureBrowserUI object
255 0 : if (!docShell)
256 0 : return NS_ERROR_FAILURE;
257 :
258 0 : docShell->SetSecurityUI(this);
259 :
260 : /* GetWebProgress(mWindow) */
261 : // hook up to the webprogress notifications.
262 0 : nsCOMPtr<nsIWebProgress> wp(do_GetInterface(docShell));
263 0 : if (!wp) return NS_ERROR_FAILURE;
264 : /* end GetWebProgress */
265 :
266 0 : wp->AddProgressListener(static_cast<nsIWebProgressListener*>(this),
267 : nsIWebProgress::NOTIFY_STATE_ALL |
268 : nsIWebProgress::NOTIFY_LOCATION |
269 0 : nsIWebProgress::NOTIFY_SECURITY);
270 :
271 :
272 0 : return NS_OK;
273 : }
274 :
275 : NS_IMETHODIMP
276 0 : nsSecureBrowserUIImpl::GetState(PRUint32* aState)
277 : {
278 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
279 0 : return MapInternalToExternalState(aState, mNotifiedSecurityState, mNotifiedToplevelIsEV);
280 : }
281 :
282 : // static
283 : already_AddRefed<nsISupports>
284 0 : nsSecureBrowserUIImpl::ExtractSecurityInfo(nsIRequest* aRequest)
285 : {
286 0 : nsISupports *retval = nsnull;
287 0 : nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
288 0 : if (channel)
289 0 : channel->GetSecurityInfo(&retval);
290 :
291 0 : if (!retval) {
292 0 : nsCOMPtr<nsISecurityInfoProvider> provider(do_QueryInterface(aRequest));
293 0 : if (provider)
294 0 : provider->GetSecurityInfo(&retval);
295 : }
296 :
297 0 : return retval;
298 : }
299 :
300 : nsresult
301 0 : nsSecureBrowserUIImpl::MapInternalToExternalState(PRUint32* aState, lockIconState lock, bool ev)
302 : {
303 0 : NS_ENSURE_ARG(aState);
304 :
305 0 : switch (lock)
306 : {
307 : case lis_broken_security:
308 0 : *aState = STATE_IS_BROKEN;
309 0 : break;
310 :
311 : case lis_mixed_security:
312 0 : *aState = STATE_IS_BROKEN;
313 0 : break;
314 :
315 : case lis_low_security:
316 0 : *aState = STATE_IS_SECURE | STATE_SECURE_LOW;
317 0 : break;
318 :
319 : case lis_high_security:
320 0 : *aState = STATE_IS_SECURE | STATE_SECURE_HIGH;
321 0 : break;
322 :
323 : default:
324 : case lis_no_security:
325 0 : *aState = STATE_IS_INSECURE;
326 0 : break;
327 : }
328 :
329 0 : if (ev && (*aState & STATE_IS_SECURE))
330 0 : *aState |= nsIWebProgressListener::STATE_IDENTITY_EV_TOPLEVEL;
331 :
332 0 : return NS_OK;
333 : }
334 :
335 : NS_IMETHODIMP
336 0 : nsSecureBrowserUIImpl::GetTooltipText(nsAString& aText)
337 : {
338 : lockIconState state;
339 0 : nsXPIDLString tooltip;
340 :
341 : {
342 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
343 0 : state = mNotifiedSecurityState;
344 0 : tooltip = mInfoTooltip;
345 : }
346 :
347 0 : if (state == lis_mixed_security)
348 : {
349 0 : GetBundleString(NS_LITERAL_STRING("SecurityButtonMixedContentTooltipText").get(),
350 0 : aText);
351 : }
352 0 : else if (!tooltip.IsEmpty())
353 : {
354 0 : aText = tooltip;
355 : }
356 : else
357 : {
358 0 : GetBundleString(NS_LITERAL_STRING("SecurityButtonTooltipText").get(),
359 0 : aText);
360 : }
361 :
362 0 : return NS_OK;
363 : }
364 :
365 : NS_IMETHODIMP
366 0 : nsSecureBrowserUIImpl::Observe(nsISupports*, const char*,
367 : const PRUnichar*)
368 : {
369 0 : return NS_ERROR_NOT_IMPLEMENTED;
370 : }
371 :
372 :
373 0 : static nsresult IsChildOfDomWindow(nsIDOMWindow *parent, nsIDOMWindow *child,
374 : bool* value)
375 : {
376 0 : *value = false;
377 :
378 0 : if (parent == child) {
379 0 : *value = true;
380 0 : return NS_OK;
381 : }
382 :
383 0 : nsCOMPtr<nsIDOMWindow> childsParent;
384 0 : child->GetParent(getter_AddRefs(childsParent));
385 :
386 0 : if (childsParent && childsParent.get() != child)
387 0 : IsChildOfDomWindow(parent, childsParent, value);
388 :
389 0 : return NS_OK;
390 : }
391 :
392 0 : static PRUint32 GetSecurityStateFromSecurityInfo(nsISupports *info)
393 : {
394 : nsresult res;
395 : PRUint32 securityState;
396 :
397 0 : nsCOMPtr<nsITransportSecurityInfo> psmInfo(do_QueryInterface(info));
398 0 : if (!psmInfo) {
399 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - no nsITransportSecurityInfo for %p\n",
400 : (nsISupports *)info));
401 0 : return nsIWebProgressListener::STATE_IS_INSECURE;
402 : }
403 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - info is %p\n",
404 : (nsISupports *)info));
405 :
406 0 : res = psmInfo->GetSecurityState(&securityState);
407 0 : if (NS_FAILED(res)) {
408 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - GetSecurityState failed: %d\n",
409 : res));
410 0 : securityState = nsIWebProgressListener::STATE_IS_BROKEN;
411 : }
412 :
413 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - Returning %d\n",
414 : securityState));
415 0 : return securityState;
416 : }
417 :
418 :
419 : NS_IMETHODIMP
420 0 : nsSecureBrowserUIImpl::Notify(nsIDOMHTMLFormElement* aDOMForm,
421 : nsIDOMWindow* aWindow, nsIURI* actionURL,
422 : bool* cancelSubmit)
423 : {
424 : // Return NS_OK unless we want to prevent this form from submitting.
425 0 : *cancelSubmit = false;
426 0 : if (!aWindow || !actionURL || !aDOMForm)
427 0 : return NS_OK;
428 :
429 0 : nsCOMPtr<nsIContent> formNode = do_QueryInterface(aDOMForm);
430 :
431 0 : nsCOMPtr<nsIDocument> document = formNode->GetDocument();
432 0 : if (!document) return NS_OK;
433 :
434 0 : nsIPrincipal *principal = formNode->NodePrincipal();
435 :
436 0 : if (!principal)
437 : {
438 0 : *cancelSubmit = true;
439 0 : return NS_OK;
440 : }
441 :
442 0 : nsCOMPtr<nsIURI> formURL;
443 0 : if (NS_FAILED(principal->GetURI(getter_AddRefs(formURL))) ||
444 0 : !formURL)
445 : {
446 0 : formURL = document->GetDocumentURI();
447 : }
448 :
449 : nsCOMPtr<nsIDOMWindow> postingWindow =
450 0 : do_QueryInterface(document->GetWindow());
451 : // We can't find this document's window, cancel it.
452 0 : if (!postingWindow)
453 : {
454 0 : NS_WARNING("If you see this and can explain why it should be allowed, note in Bug 332324");
455 0 : *cancelSubmit = true;
456 0 : return NS_OK;
457 : }
458 :
459 0 : nsCOMPtr<nsIDOMWindow> window;
460 : {
461 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
462 0 : window = do_QueryReferent(mWindow);
463 0 : NS_ASSERTION(window, "Window has gone away?!");
464 : }
465 :
466 : bool isChild;
467 0 : IsChildOfDomWindow(window, postingWindow, &isChild);
468 :
469 : // This notify call is not for our window, ignore it.
470 0 : if (!isChild)
471 0 : return NS_OK;
472 :
473 : bool okayToPost;
474 0 : nsresult res = CheckPost(formURL, actionURL, &okayToPost);
475 :
476 0 : if (NS_SUCCEEDED(res) && !okayToPost)
477 0 : *cancelSubmit = true;
478 :
479 0 : return res;
480 : }
481 :
482 : // nsIWebProgressListener
483 : NS_IMETHODIMP
484 0 : nsSecureBrowserUIImpl::OnProgressChange(nsIWebProgress* aWebProgress,
485 : nsIRequest* aRequest,
486 : PRInt32 aCurSelfProgress,
487 : PRInt32 aMaxSelfProgress,
488 : PRInt32 aCurTotalProgress,
489 : PRInt32 aMaxTotalProgress)
490 : {
491 0 : NS_NOTREACHED("notification excluded in AddProgressListener(...)");
492 0 : return NS_OK;
493 : }
494 :
495 0 : void nsSecureBrowserUIImpl::ResetStateTracking()
496 : {
497 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
498 :
499 0 : mInfoTooltip.Truncate();
500 0 : mDocumentRequestsInProgress = 0;
501 0 : if (mTransferringRequests.ops) {
502 0 : PL_DHashTableFinish(&mTransferringRequests);
503 0 : mTransferringRequests.ops = nsnull;
504 : }
505 : PL_DHashTableInit(&mTransferringRequests, &gMapOps, nsnull,
506 0 : sizeof(RequestHashEntry), 16);
507 0 : }
508 :
509 : nsresult
510 0 : nsSecureBrowserUIImpl::EvaluateAndUpdateSecurityState(nsIRequest* aRequest, nsISupports *info,
511 : bool withNewLocation)
512 : {
513 : /* I explicitly ignore the camelCase variable naming style here,
514 : I want to make it clear these are temp variables that relate to the
515 : member variables with the same suffix.*/
516 :
517 0 : PRUint32 temp_NewToplevelSecurityState = nsIWebProgressListener::STATE_IS_INSECURE;
518 0 : bool temp_NewToplevelIsEV = false;
519 :
520 0 : bool updateStatus = false;
521 0 : nsCOMPtr<nsISSLStatus> temp_SSLStatus;
522 :
523 0 : bool updateTooltip = false;
524 0 : nsXPIDLString temp_InfoTooltip;
525 :
526 0 : temp_NewToplevelSecurityState = GetSecurityStateFromSecurityInfo(info);
527 :
528 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
529 : ("SecureUI:%p: OnStateChange: remember mNewToplevelSecurityState => %x\n", this,
530 : temp_NewToplevelSecurityState));
531 :
532 0 : nsCOMPtr<nsISSLStatusProvider> sp = do_QueryInterface(info);
533 0 : if (sp) {
534 : // Ignore result
535 0 : updateStatus = true;
536 0 : (void) sp->GetSSLStatus(getter_AddRefs(temp_SSLStatus));
537 0 : if (temp_SSLStatus) {
538 : bool aTemp;
539 0 : if (NS_SUCCEEDED(temp_SSLStatus->GetIsExtendedValidation(&aTemp))) {
540 0 : temp_NewToplevelIsEV = aTemp;
541 : }
542 : }
543 : }
544 :
545 0 : if (info) {
546 0 : nsCOMPtr<nsITransportSecurityInfo> secInfo(do_QueryInterface(info));
547 0 : if (secInfo) {
548 0 : updateTooltip = true;
549 0 : secInfo->GetShortSecurityDescription(getter_Copies(temp_InfoTooltip));
550 : }
551 : }
552 :
553 : // assume temp_NewToplevelSecurityState was set in this scope!
554 : // see code that is directly above
555 :
556 : {
557 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
558 0 : mNewToplevelSecurityStateKnown = true;
559 0 : mNewToplevelSecurityState = temp_NewToplevelSecurityState;
560 0 : mNewToplevelIsEV = temp_NewToplevelIsEV;
561 0 : if (updateStatus) {
562 0 : mSSLStatus = temp_SSLStatus;
563 : }
564 0 : if (updateTooltip) {
565 0 : mInfoTooltip = temp_InfoTooltip;
566 : }
567 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
568 : ("SecureUI:%p: remember securityInfo %p\n", this,
569 : info));
570 : nsCOMPtr<nsIAssociatedContentSecurity> associatedContentSecurityFromRequest =
571 0 : do_QueryInterface(aRequest);
572 0 : if (associatedContentSecurityFromRequest)
573 0 : mCurrentToplevelSecurityInfo = aRequest;
574 : else
575 0 : mCurrentToplevelSecurityInfo = info;
576 : }
577 :
578 : return UpdateSecurityState(aRequest, withNewLocation,
579 0 : updateStatus, updateTooltip);
580 : }
581 :
582 : void
583 0 : nsSecureBrowserUIImpl::UpdateSubrequestMembers(nsISupports *securityInfo)
584 : {
585 : // For wyciwyg channels in subdocuments we only update our
586 : // subrequest state members.
587 0 : PRUint32 reqState = GetSecurityStateFromSecurityInfo(securityInfo);
588 :
589 : // the code above this line should run without a lock
590 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
591 :
592 0 : if (reqState & STATE_IS_SECURE) {
593 0 : if (reqState & STATE_SECURE_LOW || reqState & STATE_SECURE_MED) {
594 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
595 : ("SecureUI:%p: OnStateChange: subreq LOW\n", this));
596 0 : ++mSubRequestsLowSecurity;
597 : } else {
598 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
599 : ("SecureUI:%p: OnStateChange: subreq HIGH\n", this));
600 0 : ++mSubRequestsHighSecurity;
601 : }
602 0 : } else if (reqState & STATE_IS_BROKEN) {
603 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
604 : ("SecureUI:%p: OnStateChange: subreq BROKEN\n", this));
605 0 : ++mSubRequestsBrokenSecurity;
606 : } else {
607 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
608 : ("SecureUI:%p: OnStateChange: subreq INSECURE\n", this));
609 0 : ++mSubRequestsNoSecurity;
610 : }
611 0 : }
612 :
613 : NS_IMETHODIMP
614 0 : nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
615 : nsIRequest* aRequest,
616 : PRUint32 aProgressStateFlags,
617 : nsresult aStatus)
618 : {
619 : #ifdef DEBUG
620 0 : nsAutoAtomic atomic(mOnStateLocationChangeReentranceDetection);
621 0 : NS_ASSERTION(mOnStateLocationChangeReentranceDetection == 1,
622 : "unexpected parallel nsIWebProgress OnStateChange and/or OnLocationChange notification");
623 : #endif
624 : /*
625 : All discussion, unless otherwise mentioned, only refers to
626 : http, https, file or wyciwig requests.
627 :
628 :
629 : Redirects are evil, well, some of them.
630 : There are multiple forms of redirects.
631 :
632 : Redirects caused by http refresh content are ok, because experiments show,
633 : with those redirects, the old page contents and their requests will come to STOP
634 : completely, before any progress from new refreshed page content is reported.
635 : So we can safely treat them as separate page loading transactions.
636 :
637 : Evil are redirects at the http protocol level, like code 302.
638 :
639 : If the toplevel documents gets replaced, i.e. redirected with 302, we do not care for the
640 : security state of the initial transaction, which has now been redirected,
641 : we only care for the new page load.
642 :
643 : For the implementation of the security UI, we make an assumption, that is hopefully true.
644 :
645 : Imagine, the received page that was delivered with the 302 redirection answer,
646 : also delivered html content.
647 :
648 : What happens if the parser starts to analyze the content and tries to load contained sub objects?
649 :
650 : In that case we would see start and stop requests for subdocuments, some for the previous document,
651 : some for the new target document. And only those for the new toplevel document may be
652 : taken into consideration, when deciding about the security state of the next toplevel document.
653 :
654 : Because security state is being looked at, when loading stops for (sub)documents, this
655 : could cause real confusion, because we have to decide, whether an incoming progress
656 : belongs to the new toplevel page, or the previous, already redirected page.
657 :
658 : Can we simplify here?
659 :
660 : If a redirect at the http protocol level is seen, can we safely assume, its html content
661 : will not be parsed, anylzed, and no embedded objects will get loaded (css, js, images),
662 : because the redirect is already happening?
663 :
664 : If we can assume that, this really simplify things. Because we will never see notification
665 : for sub requests that need to get ignored.
666 :
667 : I would like to make this assumption for now, but please let me (kaie) know if I'm wrong.
668 :
669 : Excurse:
670 : If my assumption is wrong, then we would require more tracking information.
671 : We need to keep lists of all pointers to request object that had been seen since the
672 : last toplevel start event.
673 : If the start for a redirected page is seen, the list of releveant object must be cleared,
674 : and only progress for requests which start after it must be analyzed.
675 : All other events must be ignored, as they belong to now irrelevant previous top level documents.
676 :
677 :
678 : Frames are also evil.
679 :
680 : First we need a decision.
681 : kaie thinks:
682 : Only if the toplevel frame is secure, we should try to display secure lock icons.
683 : If some of the inner contents are insecure, we display mixed mode.
684 :
685 : But if the top level frame is not secure, why indicate a mixed lock icon at all?
686 : I think we should always display an open lock icon, if the top level frameset is insecure.
687 :
688 : That's the way Netscape Communicator behaves, and I think we should do the same.
689 :
690 : The user will not know which parts are secure and which are not,
691 : and any certificate information, displayed in the tooltip or in the "page info"
692 : will only be relevant for some subframe(s), and the user will not know which ones,
693 : so we shouldn't display it as a general attribute of the displayed page.
694 :
695 : Why are frames evil?
696 :
697 : Because the progress for the toplevel frame document is not easily distinguishable
698 : from subframes. The same STATE bits are reported.
699 :
700 : While at first sight, when a new page load happens,
701 : the toplevel frameset document has also the STATE_IS_NETWORK bit in it.
702 : But this can't really be used. Because in case that document causes a http 302 redirect,
703 : the real top level frameset will no longer have that bit.
704 :
705 : But we need some way to distinguish top level frames from inner frames.
706 :
707 : I saw that the web progress we get delivered has a reference to the toplevel DOM window.
708 :
709 : I suggest, we look at all incoming requests.
710 : If a request is NOT for the toplevel DOM window, we will always treat it as a subdocument request,
711 : regardless of whether the load flags indicate a top level document.
712 : */
713 :
714 0 : nsCOMPtr<nsIDOMWindow> windowForProgress;
715 0 : aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress));
716 :
717 0 : nsCOMPtr<nsIDOMWindow> window;
718 : bool isViewSource;
719 :
720 0 : nsCOMPtr<nsINetUtil> ioService;
721 :
722 : {
723 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
724 0 : window = do_QueryReferent(mWindow);
725 0 : NS_ASSERTION(window, "Window has gone away?!");
726 0 : isViewSource = mIsViewSource;
727 0 : ioService = mIOService;
728 : }
729 :
730 0 : if (!ioService)
731 : {
732 0 : ioService = do_GetService(NS_IOSERVICE_CONTRACTID);
733 0 : if (ioService)
734 : {
735 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
736 0 : mIOService = ioService;
737 : }
738 : }
739 :
740 0 : bool isNoContentResponse = false;
741 0 : nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
742 0 : if (httpChannel)
743 : {
744 : PRUint32 response;
745 0 : isNoContentResponse = NS_SUCCEEDED(httpChannel->GetResponseStatus(&response)) &&
746 0 : (response == 204 || response == 205);
747 : }
748 0 : const bool isToplevelProgress = (windowForProgress.get() == window.get()) && !isNoContentResponse;
749 :
750 : #ifdef PR_LOGGING
751 0 : if (windowForProgress)
752 : {
753 0 : if (isToplevelProgress)
754 : {
755 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
756 : ("SecureUI:%p: OnStateChange: progress: for toplevel\n", this));
757 : }
758 : else
759 : {
760 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
761 : ("SecureUI:%p: OnStateChange: progress: for something else\n", this));
762 : }
763 : }
764 : else
765 : {
766 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
767 : ("SecureUI:%p: OnStateChange: progress: no window known\n", this));
768 : }
769 : #endif
770 :
771 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
772 : ("SecureUI:%p: OnStateChange\n", this));
773 :
774 0 : if (isViewSource)
775 0 : return NS_OK;
776 :
777 0 : if (!aRequest)
778 : {
779 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
780 : ("SecureUI:%p: OnStateChange with null request\n", this));
781 0 : return NS_ERROR_NULL_POINTER;
782 : }
783 :
784 : #ifdef PR_LOGGING
785 0 : if (PR_LOG_TEST(gSecureDocLog, PR_LOG_DEBUG)) {
786 0 : nsXPIDLCString reqname;
787 0 : aRequest->GetName(reqname);
788 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
789 : ("SecureUI:%p: %p %p OnStateChange %x %s\n", this, aWebProgress,
790 : aRequest, aProgressStateFlags, reqname.get()));
791 : }
792 : #endif
793 :
794 0 : nsCOMPtr<nsISupports> securityInfo(ExtractSecurityInfo(aRequest));
795 :
796 0 : nsCOMPtr<nsIURI> uri;
797 0 : nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
798 0 : if (channel) {
799 0 : channel->GetURI(getter_AddRefs(uri));
800 : }
801 :
802 0 : nsCOMPtr<imgIRequest> imgRequest(do_QueryInterface(aRequest));
803 0 : if (imgRequest) {
804 0 : NS_ASSERTION(!channel, "How did that happen, exactly?");
805 : // for image requests, we get the URI from here
806 0 : imgRequest->GetURI(getter_AddRefs(uri));
807 : }
808 :
809 0 : if (uri) {
810 : bool vs;
811 0 : if (NS_SUCCEEDED(uri->SchemeIs("javascript", &vs)) && vs) {
812 : // We ignore the progress events for javascript URLs.
813 : // If a document loading gets triggered, we will see more events.
814 0 : return NS_OK;
815 : }
816 : }
817 :
818 0 : PRUint32 loadFlags = 0;
819 0 : aRequest->GetLoadFlags(&loadFlags);
820 :
821 : #ifdef PR_LOGGING
822 0 : if (aProgressStateFlags & STATE_START
823 : &&
824 : aProgressStateFlags & STATE_IS_REQUEST
825 : &&
826 : isToplevelProgress
827 : &&
828 : loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
829 : {
830 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
831 : ("SecureUI:%p: OnStateChange: SOMETHING STARTS FOR TOPMOST DOCUMENT\n", this));
832 : }
833 :
834 0 : if (aProgressStateFlags & STATE_STOP
835 : &&
836 : aProgressStateFlags & STATE_IS_REQUEST
837 : &&
838 : isToplevelProgress
839 : &&
840 : loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
841 : {
842 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
843 : ("SecureUI:%p: OnStateChange: SOMETHING STOPS FOR TOPMOST DOCUMENT\n", this));
844 : }
845 : #endif
846 :
847 0 : bool isSubDocumentRelevant = true;
848 :
849 : // We are only interested in requests that load in the browser window...
850 0 : if (!imgRequest) { // is not imgRequest
851 0 : nsCOMPtr<nsIHttpChannel> httpRequest(do_QueryInterface(aRequest));
852 0 : if (!httpRequest) {
853 0 : nsCOMPtr<nsIFileChannel> fileRequest(do_QueryInterface(aRequest));
854 0 : if (!fileRequest) {
855 0 : nsCOMPtr<nsIWyciwygChannel> wyciwygRequest(do_QueryInterface(aRequest));
856 0 : if (!wyciwygRequest) {
857 0 : nsCOMPtr<nsIFTPChannel> ftpRequest(do_QueryInterface(aRequest));
858 0 : if (!ftpRequest) {
859 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
860 : ("SecureUI:%p: OnStateChange: not relevant for sub content\n", this));
861 0 : isSubDocumentRelevant = false;
862 : }
863 : }
864 : }
865 : }
866 : }
867 :
868 : // This will ignore all resource, chrome, data, file, moz-icon, and anno
869 : // protocols. Local resources are treated as trusted.
870 0 : if (uri && ioService) {
871 : bool hasFlag;
872 : nsresult rv =
873 0 : ioService->URIChainHasFlags(uri,
874 : nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
875 0 : &hasFlag);
876 0 : if (NS_SUCCEEDED(rv) && hasFlag) {
877 0 : isSubDocumentRelevant = false;
878 : }
879 : }
880 :
881 : #if defined(DEBUG)
882 0 : nsCString info2;
883 0 : PRUint32 testFlags = loadFlags;
884 :
885 0 : if (testFlags & nsIChannel::LOAD_DOCUMENT_URI)
886 : {
887 0 : testFlags -= nsIChannel::LOAD_DOCUMENT_URI;
888 0 : info2.Append("LOAD_DOCUMENT_URI ");
889 : }
890 0 : if (testFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
891 : {
892 0 : testFlags -= nsIChannel::LOAD_RETARGETED_DOCUMENT_URI;
893 0 : info2.Append("LOAD_RETARGETED_DOCUMENT_URI ");
894 : }
895 0 : if (testFlags & nsIChannel::LOAD_REPLACE)
896 : {
897 0 : testFlags -= nsIChannel::LOAD_REPLACE;
898 0 : info2.Append("LOAD_REPLACE ");
899 : }
900 :
901 0 : const char *_status = NS_SUCCEEDED(aStatus) ? "1" : "0";
902 :
903 0 : nsCString info;
904 0 : PRUint32 f = aProgressStateFlags;
905 0 : if (f & nsIWebProgressListener::STATE_START)
906 : {
907 0 : f -= nsIWebProgressListener::STATE_START;
908 0 : info.Append("START ");
909 : }
910 0 : if (f & nsIWebProgressListener::STATE_REDIRECTING)
911 : {
912 0 : f -= nsIWebProgressListener::STATE_REDIRECTING;
913 0 : info.Append("REDIRECTING ");
914 : }
915 0 : if (f & nsIWebProgressListener::STATE_TRANSFERRING)
916 : {
917 0 : f -= nsIWebProgressListener::STATE_TRANSFERRING;
918 0 : info.Append("TRANSFERRING ");
919 : }
920 0 : if (f & nsIWebProgressListener::STATE_NEGOTIATING)
921 : {
922 0 : f -= nsIWebProgressListener::STATE_NEGOTIATING;
923 0 : info.Append("NEGOTIATING ");
924 : }
925 0 : if (f & nsIWebProgressListener::STATE_STOP)
926 : {
927 0 : f -= nsIWebProgressListener::STATE_STOP;
928 0 : info.Append("STOP ");
929 : }
930 0 : if (f & nsIWebProgressListener::STATE_IS_REQUEST)
931 : {
932 0 : f -= nsIWebProgressListener::STATE_IS_REQUEST;
933 0 : info.Append("IS_REQUEST ");
934 : }
935 0 : if (f & nsIWebProgressListener::STATE_IS_DOCUMENT)
936 : {
937 0 : f -= nsIWebProgressListener::STATE_IS_DOCUMENT;
938 0 : info.Append("IS_DOCUMENT ");
939 : }
940 0 : if (f & nsIWebProgressListener::STATE_IS_NETWORK)
941 : {
942 0 : f -= nsIWebProgressListener::STATE_IS_NETWORK;
943 0 : info.Append("IS_NETWORK ");
944 : }
945 0 : if (f & nsIWebProgressListener::STATE_IS_WINDOW)
946 : {
947 0 : f -= nsIWebProgressListener::STATE_IS_WINDOW;
948 0 : info.Append("IS_WINDOW ");
949 : }
950 0 : if (f & nsIWebProgressListener::STATE_IS_INSECURE)
951 : {
952 0 : f -= nsIWebProgressListener::STATE_IS_INSECURE;
953 0 : info.Append("IS_INSECURE ");
954 : }
955 0 : if (f & nsIWebProgressListener::STATE_IS_BROKEN)
956 : {
957 0 : f -= nsIWebProgressListener::STATE_IS_BROKEN;
958 0 : info.Append("IS_BROKEN ");
959 : }
960 0 : if (f & nsIWebProgressListener::STATE_IS_SECURE)
961 : {
962 0 : f -= nsIWebProgressListener::STATE_IS_SECURE;
963 0 : info.Append("IS_SECURE ");
964 : }
965 0 : if (f & nsIWebProgressListener::STATE_SECURE_HIGH)
966 : {
967 0 : f -= nsIWebProgressListener::STATE_SECURE_HIGH;
968 0 : info.Append("SECURE_HIGH ");
969 : }
970 0 : if (f & nsIWebProgressListener::STATE_SECURE_MED)
971 : {
972 0 : f -= nsIWebProgressListener::STATE_SECURE_MED;
973 0 : info.Append("SECURE_MED ");
974 : }
975 0 : if (f & nsIWebProgressListener::STATE_SECURE_LOW)
976 : {
977 0 : f -= nsIWebProgressListener::STATE_SECURE_LOW;
978 0 : info.Append("SECURE_LOW ");
979 : }
980 0 : if (f & nsIWebProgressListener::STATE_RESTORING)
981 : {
982 0 : f -= nsIWebProgressListener::STATE_RESTORING;
983 0 : info.Append("STATE_RESTORING ");
984 : }
985 :
986 0 : if (f > 0)
987 : {
988 0 : info.Append("f contains unknown flag!");
989 : }
990 :
991 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
992 : ("SecureUI:%p: OnStateChange: %s %s -- %s\n", this, _status,
993 : info.get(), info2.get()));
994 :
995 0 : if (aProgressStateFlags & STATE_STOP
996 : &&
997 0 : channel)
998 : {
999 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1000 : ("SecureUI:%p: OnStateChange: seeing STOP with security state: %d\n", this,
1001 : GetSecurityStateFromSecurityInfo(securityInfo)
1002 : ));
1003 : }
1004 : #endif
1005 :
1006 0 : if (aProgressStateFlags & STATE_TRANSFERRING
1007 : &&
1008 : aProgressStateFlags & STATE_IS_REQUEST)
1009 : {
1010 : // The listing of a request in mTransferringRequests
1011 : // means, there has already been data transfered.
1012 :
1013 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1014 0 : PL_DHashTableOperate(&mTransferringRequests, aRequest, PL_DHASH_ADD);
1015 :
1016 0 : return NS_OK;
1017 : }
1018 :
1019 0 : bool requestHasTransferedData = false;
1020 :
1021 0 : if (aProgressStateFlags & STATE_STOP
1022 : &&
1023 : aProgressStateFlags & STATE_IS_REQUEST)
1024 : {
1025 : { /* scope for the ReentrantMonitorAutoEnter */
1026 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1027 0 : PLDHashEntryHdr *entry = PL_DHashTableOperate(&mTransferringRequests, aRequest, PL_DHASH_LOOKUP);
1028 0 : if (PL_DHASH_ENTRY_IS_BUSY(entry))
1029 : {
1030 0 : PL_DHashTableOperate(&mTransferringRequests, aRequest, PL_DHASH_REMOVE);
1031 :
1032 0 : requestHasTransferedData = true;
1033 : }
1034 : }
1035 :
1036 0 : if (!requestHasTransferedData) {
1037 : // Because image loads doesn't support any TRANSFERRING notifications but
1038 : // only START and STOP we must ask them directly whether content was
1039 : // transferred. See bug 432685 for details.
1040 : nsCOMPtr<nsISecurityInfoProvider> securityInfoProvider =
1041 0 : do_QueryInterface(aRequest);
1042 : // Guess true in all failure cases to be safe. But if we're not
1043 : // an nsISecurityInfoProvider, then we just haven't transferred
1044 : // any data.
1045 : bool hasTransferred;
1046 : requestHasTransferedData =
1047 : securityInfoProvider &&
1048 0 : (NS_FAILED(securityInfoProvider->GetHasTransferredData(&hasTransferred)) ||
1049 0 : hasTransferred);
1050 : }
1051 : }
1052 :
1053 0 : bool allowSecurityStateChange = true;
1054 0 : if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
1055 : {
1056 : // The original consumer (this) is no longer the target of the load.
1057 : // Ignore any events with this flag, do not allow them to update
1058 : // our secure UI state.
1059 0 : allowSecurityStateChange = false;
1060 : }
1061 :
1062 0 : if (aProgressStateFlags & STATE_START
1063 : &&
1064 : aProgressStateFlags & STATE_IS_REQUEST
1065 : &&
1066 : isToplevelProgress
1067 : &&
1068 : loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
1069 : {
1070 : bool inProgress;
1071 :
1072 : PRInt32 saveSubHigh;
1073 : PRInt32 saveSubLow;
1074 : PRInt32 saveSubBroken;
1075 : PRInt32 saveSubNo;
1076 0 : nsCOMPtr<nsIAssociatedContentSecurity> prevContentSecurity;
1077 :
1078 0 : PRInt32 newSubHigh = 0;
1079 0 : PRInt32 newSubLow = 0;
1080 0 : PRInt32 newSubBroken = 0;
1081 0 : PRInt32 newSubNo = 0;
1082 :
1083 : {
1084 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1085 0 : inProgress = (mDocumentRequestsInProgress!=0);
1086 :
1087 0 : if (allowSecurityStateChange && !inProgress)
1088 : {
1089 0 : saveSubHigh = mSubRequestsHighSecurity;
1090 0 : saveSubLow = mSubRequestsLowSecurity;
1091 0 : saveSubBroken = mSubRequestsBrokenSecurity;
1092 0 : saveSubNo = mSubRequestsNoSecurity;
1093 0 : prevContentSecurity = do_QueryInterface(mCurrentToplevelSecurityInfo);
1094 : }
1095 : }
1096 :
1097 0 : if (allowSecurityStateChange && !inProgress)
1098 : {
1099 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1100 : ("SecureUI:%p: OnStateChange: start for toplevel document\n", this
1101 : ));
1102 :
1103 0 : if (prevContentSecurity)
1104 : {
1105 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1106 : ("SecureUI:%p: OnStateChange: start, saving current sub state\n", this
1107 : ));
1108 :
1109 : // before resetting our state, let's save information about
1110 : // sub element loads, so we can restore it later
1111 0 : prevContentSecurity->SetCountSubRequestsHighSecurity(saveSubHigh);
1112 0 : prevContentSecurity->SetCountSubRequestsLowSecurity(saveSubLow);
1113 0 : prevContentSecurity->SetCountSubRequestsBrokenSecurity(saveSubBroken);
1114 0 : prevContentSecurity->SetCountSubRequestsNoSecurity(saveSubNo);
1115 0 : prevContentSecurity->Flush();
1116 : }
1117 :
1118 0 : bool retrieveAssociatedState = false;
1119 :
1120 0 : if (securityInfo &&
1121 0 : (aProgressStateFlags & nsIWebProgressListener::STATE_RESTORING) != 0) {
1122 0 : retrieveAssociatedState = true;
1123 : } else {
1124 0 : nsCOMPtr<nsIWyciwygChannel> wyciwygRequest(do_QueryInterface(aRequest));
1125 0 : if (wyciwygRequest) {
1126 0 : retrieveAssociatedState = true;
1127 : }
1128 : }
1129 :
1130 0 : if (retrieveAssociatedState)
1131 : {
1132 : // When restoring from bfcache, we will not get events for the
1133 : // page's sub elements, so let's load the state of sub elements
1134 : // from the cache.
1135 :
1136 : nsCOMPtr<nsIAssociatedContentSecurity>
1137 0 : newContentSecurity(do_QueryInterface(securityInfo));
1138 :
1139 0 : if (newContentSecurity)
1140 : {
1141 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1142 : ("SecureUI:%p: OnStateChange: start, loading old sub state\n", this
1143 : ));
1144 :
1145 0 : newContentSecurity->GetCountSubRequestsHighSecurity(&newSubHigh);
1146 0 : newContentSecurity->GetCountSubRequestsLowSecurity(&newSubLow);
1147 0 : newContentSecurity->GetCountSubRequestsBrokenSecurity(&newSubBroken);
1148 0 : newContentSecurity->GetCountSubRequestsNoSecurity(&newSubNo);
1149 : }
1150 : }
1151 : }
1152 :
1153 : {
1154 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1155 :
1156 0 : if (allowSecurityStateChange && !inProgress)
1157 : {
1158 0 : ResetStateTracking();
1159 0 : mSubRequestsHighSecurity = newSubHigh;
1160 0 : mSubRequestsLowSecurity = newSubLow;
1161 0 : mSubRequestsBrokenSecurity = newSubBroken;
1162 0 : mSubRequestsNoSecurity = newSubNo;
1163 0 : mNewToplevelSecurityStateKnown = false;
1164 : }
1165 :
1166 : // By using a counter, this code also works when the toplevel
1167 : // document get's redirected, but the STOP request for the
1168 : // previous toplevel document has not yet have been received.
1169 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1170 : ("SecureUI:%p: OnStateChange: ++mDocumentRequestsInProgress\n", this
1171 : ));
1172 0 : ++mDocumentRequestsInProgress;
1173 : }
1174 :
1175 0 : return NS_OK;
1176 : }
1177 :
1178 0 : if (aProgressStateFlags & STATE_STOP
1179 : &&
1180 : aProgressStateFlags & STATE_IS_REQUEST
1181 : &&
1182 : isToplevelProgress
1183 : &&
1184 : loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
1185 : {
1186 : PRInt32 temp_DocumentRequestsInProgress;
1187 0 : nsCOMPtr<nsISecurityEventSink> temp_ToplevelEventSink;
1188 :
1189 : {
1190 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1191 0 : temp_DocumentRequestsInProgress = mDocumentRequestsInProgress;
1192 0 : if (allowSecurityStateChange)
1193 : {
1194 0 : temp_ToplevelEventSink = mToplevelEventSink;
1195 : }
1196 : }
1197 :
1198 0 : if (temp_DocumentRequestsInProgress <= 0)
1199 : {
1200 : // Ignore stop requests unless a document load is in progress
1201 : // Unfortunately on application start, see some stops without having seen any starts...
1202 0 : return NS_OK;
1203 : }
1204 :
1205 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1206 : ("SecureUI:%p: OnStateChange: --mDocumentRequestsInProgress\n", this
1207 : ));
1208 :
1209 0 : if (!temp_ToplevelEventSink && channel)
1210 : {
1211 0 : if (allowSecurityStateChange)
1212 : {
1213 0 : ObtainEventSink(channel, temp_ToplevelEventSink);
1214 : }
1215 : }
1216 :
1217 : {
1218 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1219 0 : if (allowSecurityStateChange)
1220 : {
1221 0 : mToplevelEventSink = temp_ToplevelEventSink;
1222 : }
1223 0 : --mDocumentRequestsInProgress;
1224 : }
1225 :
1226 0 : if (allowSecurityStateChange && requestHasTransferedData) {
1227 : // Data has been transferred for the single toplevel
1228 : // request. Evaluate the security state.
1229 :
1230 0 : return EvaluateAndUpdateSecurityState(aRequest, securityInfo, false);
1231 : }
1232 :
1233 0 : return NS_OK;
1234 : }
1235 :
1236 0 : if (aProgressStateFlags & STATE_STOP
1237 : &&
1238 : aProgressStateFlags & STATE_IS_REQUEST)
1239 : {
1240 0 : if (!isSubDocumentRelevant)
1241 0 : return NS_OK;
1242 :
1243 : // if we arrive here, LOAD_DOCUMENT_URI is not set
1244 :
1245 : // We only care for the security state of sub requests which have actually transfered data.
1246 :
1247 0 : if (allowSecurityStateChange && requestHasTransferedData)
1248 : {
1249 0 : UpdateSubrequestMembers(securityInfo);
1250 :
1251 : // Care for the following scenario:
1252 : // A new top level document load might have already started,
1253 : // but the security state of the new top level document might not yet been known.
1254 : //
1255 : // At this point, we are learning about the security state of a sub-document.
1256 : // We must not update the security state based on the sub content,
1257 : // if the new top level state is not yet known.
1258 : //
1259 : // We skip updating the security state in this case.
1260 :
1261 : bool temp_NewToplevelSecurityStateKnown;
1262 : {
1263 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1264 0 : temp_NewToplevelSecurityStateKnown = mNewToplevelSecurityStateKnown;
1265 : }
1266 :
1267 0 : if (temp_NewToplevelSecurityStateKnown)
1268 0 : return UpdateSecurityState(aRequest, false, false, false);
1269 : }
1270 :
1271 0 : return NS_OK;
1272 : }
1273 :
1274 0 : return NS_OK;
1275 : }
1276 :
1277 : // I'm keeping this as a separate function, in order to simplify the review
1278 : // for bug 412456. We should inline this in a follow up patch.
1279 0 : void nsSecureBrowserUIImpl::ObtainEventSink(nsIChannel *channel,
1280 : nsCOMPtr<nsISecurityEventSink> &sink)
1281 : {
1282 0 : if (!sink)
1283 0 : NS_QueryNotificationCallbacks(channel, sink);
1284 0 : }
1285 :
1286 0 : nsresult nsSecureBrowserUIImpl::UpdateSecurityState(nsIRequest* aRequest,
1287 : bool withNewLocation,
1288 : bool withUpdateStatus,
1289 : bool withUpdateTooltip)
1290 : {
1291 0 : lockIconState warnSecurityState = lis_no_security;
1292 0 : bool showWarning = false;
1293 0 : nsresult rv = NS_OK;
1294 :
1295 : // both parameters are both input and outout
1296 0 : bool flagsChanged = UpdateMyFlags(showWarning, warnSecurityState);
1297 :
1298 0 : if (flagsChanged || withNewLocation || withUpdateStatus || withUpdateTooltip)
1299 0 : rv = TellTheWorld(showWarning, warnSecurityState, aRequest);
1300 :
1301 0 : return rv;
1302 : }
1303 :
1304 : // must not fail, by definition, only trivial assignments
1305 : // or string operations are allowed
1306 : // returns true if our overall state has changed and we must send out notifications
1307 0 : bool nsSecureBrowserUIImpl::UpdateMyFlags(bool &showWarning, lockIconState &warnSecurityState)
1308 : {
1309 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1310 0 : bool mustTellTheWorld = false;
1311 :
1312 : lockIconState newSecurityState;
1313 :
1314 0 : if (mNewToplevelSecurityState & STATE_IS_SECURE)
1315 : {
1316 0 : if (mNewToplevelSecurityState & STATE_SECURE_LOW
1317 : ||
1318 : mNewToplevelSecurityState & STATE_SECURE_MED)
1319 : {
1320 0 : if (mSubRequestsBrokenSecurity
1321 : ||
1322 : mSubRequestsNoSecurity)
1323 : {
1324 0 : newSecurityState = lis_mixed_security;
1325 : }
1326 : else
1327 : {
1328 0 : newSecurityState = lis_low_security;
1329 : }
1330 : }
1331 : else
1332 : {
1333 : // toplevel is high security
1334 :
1335 0 : if (mSubRequestsBrokenSecurity
1336 : ||
1337 : mSubRequestsNoSecurity)
1338 : {
1339 0 : newSecurityState = lis_mixed_security;
1340 : }
1341 0 : else if (mSubRequestsLowSecurity)
1342 : {
1343 0 : newSecurityState = lis_low_security;
1344 : }
1345 : else
1346 : {
1347 0 : newSecurityState = lis_high_security;
1348 : }
1349 : }
1350 : }
1351 : else
1352 0 : if (mNewToplevelSecurityState & STATE_IS_BROKEN)
1353 : {
1354 : // indicating BROKEN is more important than MIXED.
1355 :
1356 0 : newSecurityState = lis_broken_security;
1357 : }
1358 : else
1359 : {
1360 0 : newSecurityState = lis_no_security;
1361 : }
1362 :
1363 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1364 : ("SecureUI:%p: UpdateSecurityState: old-new %d - %d\n", this,
1365 : mNotifiedSecurityState, newSecurityState
1366 : ));
1367 :
1368 0 : if (mNotifiedSecurityState != newSecurityState)
1369 : {
1370 0 : mustTellTheWorld = true;
1371 :
1372 : // we'll treat "broken" exactly like "insecure",
1373 : // i.e. we do not show alerts when switching between broken and insecure
1374 :
1375 : /*
1376 : from to shows alert
1377 : ------------------------------ ---------------
1378 :
1379 : no or broken -> no or broken => <NOTHING SHOWN>
1380 :
1381 : no or broken -> mixed => mixed alert
1382 : no or broken -> low => low alert
1383 : no or broken -> high => high alert
1384 :
1385 : mixed, high, low -> no, broken => leaving secure
1386 :
1387 : mixed -> low => low alert
1388 : mixed -> high => high alert
1389 :
1390 : high -> low => low alert
1391 : high -> mixed => mixed
1392 :
1393 : low -> high => high
1394 : low -> mixed => mixed
1395 :
1396 :
1397 : security icon
1398 : ----------------
1399 :
1400 : no open
1401 : mixed broken
1402 : broken broken
1403 : low low
1404 : high high
1405 : */
1406 :
1407 0 : showWarning = true;
1408 :
1409 0 : switch (mNotifiedSecurityState)
1410 : {
1411 : case lis_no_security:
1412 : case lis_broken_security:
1413 0 : switch (newSecurityState)
1414 : {
1415 : case lis_no_security:
1416 : case lis_broken_security:
1417 0 : showWarning = false;
1418 0 : break;
1419 :
1420 : default:
1421 0 : break;
1422 : }
1423 :
1424 : default:
1425 : break;
1426 : }
1427 :
1428 0 : if (showWarning)
1429 : {
1430 0 : warnSecurityState = newSecurityState;
1431 : }
1432 :
1433 0 : mNotifiedSecurityState = newSecurityState;
1434 :
1435 0 : if (lis_no_security == newSecurityState)
1436 : {
1437 0 : mSSLStatus = nsnull;
1438 0 : mInfoTooltip.Truncate();
1439 : }
1440 : }
1441 :
1442 0 : if (mNotifiedToplevelIsEV != mNewToplevelIsEV) {
1443 0 : mustTellTheWorld = true;
1444 0 : mNotifiedToplevelIsEV = mNewToplevelIsEV;
1445 : }
1446 :
1447 0 : return mustTellTheWorld;
1448 : }
1449 :
1450 0 : nsresult nsSecureBrowserUIImpl::TellTheWorld(bool showWarning,
1451 : lockIconState warnSecurityState,
1452 : nsIRequest* aRequest)
1453 : {
1454 0 : nsCOMPtr<nsISecurityEventSink> temp_ToplevelEventSink;
1455 : lockIconState temp_NotifiedSecurityState;
1456 : bool temp_NotifiedToplevelIsEV;
1457 :
1458 : {
1459 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1460 0 : temp_ToplevelEventSink = mToplevelEventSink;
1461 0 : temp_NotifiedSecurityState = mNotifiedSecurityState;
1462 0 : temp_NotifiedToplevelIsEV = mNotifiedToplevelIsEV;
1463 : }
1464 :
1465 0 : if (temp_ToplevelEventSink)
1466 : {
1467 0 : PRUint32 newState = STATE_IS_INSECURE;
1468 : MapInternalToExternalState(&newState,
1469 : temp_NotifiedSecurityState,
1470 0 : temp_NotifiedToplevelIsEV);
1471 :
1472 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1473 : ("SecureUI:%p: UpdateSecurityState: calling OnSecurityChange\n", this
1474 : ));
1475 :
1476 0 : temp_ToplevelEventSink->OnSecurityChange(aRequest, newState);
1477 : }
1478 : else
1479 : {
1480 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1481 : ("SecureUI:%p: UpdateSecurityState: NO mToplevelEventSink!\n", this
1482 : ));
1483 :
1484 : }
1485 :
1486 0 : if (showWarning)
1487 : {
1488 0 : switch (warnSecurityState)
1489 : {
1490 : case lis_no_security:
1491 : case lis_broken_security:
1492 0 : ConfirmLeavingSecure();
1493 0 : break;
1494 :
1495 : case lis_mixed_security:
1496 0 : ConfirmMixedMode();
1497 0 : break;
1498 :
1499 : case lis_low_security:
1500 0 : ConfirmEnteringWeak();
1501 0 : break;
1502 :
1503 : case lis_high_security:
1504 0 : ConfirmEnteringSecure();
1505 0 : break;
1506 : }
1507 : }
1508 :
1509 0 : return NS_OK;
1510 : }
1511 :
1512 : NS_IMETHODIMP
1513 0 : nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress,
1514 : nsIRequest* aRequest,
1515 : nsIURI* aLocation,
1516 : PRUint32 aFlags)
1517 : {
1518 : #ifdef DEBUG
1519 0 : nsAutoAtomic atomic(mOnStateLocationChangeReentranceDetection);
1520 0 : NS_ASSERTION(mOnStateLocationChangeReentranceDetection == 1,
1521 : "unexpected parallel nsIWebProgress OnStateChange and/or OnLocationChange notification");
1522 : #endif
1523 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1524 : ("SecureUI:%p: OnLocationChange\n", this));
1525 :
1526 0 : bool updateIsViewSource = false;
1527 0 : bool temp_IsViewSource = false;
1528 0 : nsCOMPtr<nsIDOMWindow> window;
1529 :
1530 0 : if (aLocation)
1531 : {
1532 : bool vs;
1533 :
1534 0 : nsresult rv = aLocation->SchemeIs("view-source", &vs);
1535 0 : NS_ENSURE_SUCCESS(rv, rv);
1536 :
1537 0 : if (vs) {
1538 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1539 : ("SecureUI:%p: OnLocationChange: view-source\n", this));
1540 : }
1541 :
1542 0 : updateIsViewSource = true;
1543 0 : temp_IsViewSource = vs;
1544 : }
1545 :
1546 : {
1547 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1548 0 : if (updateIsViewSource) {
1549 0 : mIsViewSource = temp_IsViewSource;
1550 : }
1551 0 : mCurrentURI = aLocation;
1552 0 : window = do_QueryReferent(mWindow);
1553 0 : NS_ASSERTION(window, "Window has gone away?!");
1554 : }
1555 :
1556 : // When |aRequest| is null, basically we don't trust that document. But if
1557 : // docshell insists that the document has not changed at all, we will reuse
1558 : // the previous security state, no matter what |aRequest| may be.
1559 0 : if (aFlags & LOCATION_CHANGE_SAME_DOCUMENT)
1560 0 : return NS_OK;
1561 :
1562 : // The location bar has changed, so we must update the security state. The
1563 : // only concern with doing this here is that a page may transition from being
1564 : // reported as completely secure to being reported as partially secure
1565 : // (mixed). This may be confusing for users, and it may bother users who
1566 : // like seeing security dialogs. However, it seems prudent given that page
1567 : // loading may never end in some edge cases (perhaps by a site with malicious
1568 : // intent).
1569 :
1570 0 : nsCOMPtr<nsIDOMWindow> windowForProgress;
1571 0 : aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress));
1572 :
1573 0 : nsCOMPtr<nsISupports> securityInfo(ExtractSecurityInfo(aRequest));
1574 :
1575 0 : if (windowForProgress.get() == window.get()) {
1576 : // For toplevel channels, update the security state right away.
1577 0 : return EvaluateAndUpdateSecurityState(aRequest, securityInfo, true);
1578 : }
1579 :
1580 : // For channels in subdocuments we only update our subrequest state members.
1581 0 : UpdateSubrequestMembers(securityInfo);
1582 :
1583 : // Care for the following scenario:
1584 :
1585 : // A new toplevel document load might have already started, but the security
1586 : // state of the new toplevel document might not yet be known.
1587 : //
1588 : // At this point, we are learning about the security state of a sub-document.
1589 : // We must not update the security state based on the sub content, if the new
1590 : // top level state is not yet known.
1591 : //
1592 : // We skip updating the security state in this case.
1593 :
1594 : bool temp_NewToplevelSecurityStateKnown;
1595 : {
1596 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1597 0 : temp_NewToplevelSecurityStateKnown = mNewToplevelSecurityStateKnown;
1598 : }
1599 :
1600 0 : if (temp_NewToplevelSecurityStateKnown)
1601 0 : return UpdateSecurityState(aRequest, true, false, false);
1602 :
1603 0 : return NS_OK;
1604 : }
1605 :
1606 : NS_IMETHODIMP
1607 0 : nsSecureBrowserUIImpl::OnStatusChange(nsIWebProgress* aWebProgress,
1608 : nsIRequest* aRequest,
1609 : nsresult aStatus,
1610 : const PRUnichar* aMessage)
1611 : {
1612 0 : NS_NOTREACHED("notification excluded in AddProgressListener(...)");
1613 0 : return NS_OK;
1614 : }
1615 :
1616 : nsresult
1617 0 : nsSecureBrowserUIImpl::OnSecurityChange(nsIWebProgress *aWebProgress,
1618 : nsIRequest *aRequest,
1619 : PRUint32 state)
1620 : {
1621 : #if defined(DEBUG)
1622 0 : nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
1623 0 : if (!channel)
1624 0 : return NS_OK;
1625 :
1626 0 : nsCOMPtr<nsIURI> aURI;
1627 0 : channel->GetURI(getter_AddRefs(aURI));
1628 :
1629 0 : if (aURI) {
1630 0 : nsCAutoString temp;
1631 0 : aURI->GetSpec(temp);
1632 0 : PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
1633 : ("SecureUI:%p: OnSecurityChange: (%x) %s\n", this,
1634 : state, temp.get()));
1635 : }
1636 : #endif
1637 :
1638 0 : return NS_OK;
1639 : }
1640 :
1641 : // nsISSLStatusProvider methods
1642 : NS_IMETHODIMP
1643 0 : nsSecureBrowserUIImpl::GetSSLStatus(nsISSLStatus** _result)
1644 : {
1645 0 : NS_ENSURE_ARG_POINTER(_result);
1646 :
1647 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1648 :
1649 0 : switch (mNotifiedSecurityState)
1650 : {
1651 : case lis_mixed_security:
1652 : case lis_low_security:
1653 : case lis_high_security:
1654 : break;
1655 :
1656 : default:
1657 0 : NS_NOTREACHED("if this is reached you must add more entries to the switch");
1658 : case lis_no_security:
1659 : case lis_broken_security:
1660 0 : *_result = nsnull;
1661 0 : return NS_OK;
1662 : }
1663 :
1664 0 : *_result = mSSLStatus;
1665 0 : NS_IF_ADDREF(*_result);
1666 :
1667 0 : return NS_OK;
1668 : }
1669 :
1670 : nsresult
1671 0 : nsSecureBrowserUIImpl::IsURLHTTPS(nsIURI* aURL, bool* value)
1672 : {
1673 0 : *value = false;
1674 :
1675 0 : if (!aURL)
1676 0 : return NS_OK;
1677 :
1678 0 : return aURL->SchemeIs("https", value);
1679 : }
1680 :
1681 : nsresult
1682 0 : nsSecureBrowserUIImpl::IsURLJavaScript(nsIURI* aURL, bool* value)
1683 : {
1684 0 : *value = false;
1685 :
1686 0 : if (!aURL)
1687 0 : return NS_OK;
1688 :
1689 0 : return aURL->SchemeIs("javascript", value);
1690 : }
1691 :
1692 : void
1693 0 : nsSecureBrowserUIImpl::GetBundleString(const PRUnichar* name,
1694 : nsAString &outString)
1695 : {
1696 0 : nsCOMPtr<nsIStringBundle> temp_StringBundle;
1697 :
1698 : {
1699 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1700 0 : temp_StringBundle = mStringBundle;
1701 : }
1702 :
1703 0 : if (temp_StringBundle && name) {
1704 0 : PRUnichar *ptrv = nsnull;
1705 0 : if (NS_SUCCEEDED(temp_StringBundle->GetStringFromName(name,
1706 : &ptrv)))
1707 0 : outString = ptrv;
1708 : else
1709 0 : outString.SetLength(0);
1710 :
1711 0 : nsMemory::Free(ptrv);
1712 :
1713 : } else {
1714 0 : outString.SetLength(0);
1715 : }
1716 0 : }
1717 :
1718 : nsresult
1719 0 : nsSecureBrowserUIImpl::CheckPost(nsIURI *formURL, nsIURI *actionURL, bool *okayToPost)
1720 : {
1721 : bool formSecure, actionSecure, actionJavaScript;
1722 0 : *okayToPost = true;
1723 :
1724 0 : nsresult rv = IsURLHTTPS(formURL, &formSecure);
1725 0 : if (NS_FAILED(rv))
1726 0 : return rv;
1727 :
1728 0 : rv = IsURLHTTPS(actionURL, &actionSecure);
1729 0 : if (NS_FAILED(rv))
1730 0 : return rv;
1731 :
1732 0 : rv = IsURLJavaScript(actionURL, &actionJavaScript);
1733 0 : if (NS_FAILED(rv))
1734 0 : return rv;
1735 :
1736 : // If we are posting to a secure link, all is okay.
1737 : // It doesn't matter whether the currently viewed page is secure or not,
1738 : // because the data will be sent to a secure URL.
1739 0 : if (actionSecure) {
1740 0 : return NS_OK;
1741 : }
1742 :
1743 : // Action is a JavaScript call, not an actual post. That's okay too.
1744 0 : if (actionJavaScript) {
1745 0 : return NS_OK;
1746 : }
1747 :
1748 : // posting to insecure webpage from a secure webpage.
1749 0 : if (formSecure) {
1750 0 : *okayToPost = ConfirmPostToInsecureFromSecure();
1751 : } else {
1752 0 : *okayToPost = ConfirmPostToInsecure();
1753 : }
1754 :
1755 0 : return NS_OK;
1756 : }
1757 :
1758 : //
1759 : // Implementation of an nsIInterfaceRequestor for use
1760 : // as context for NSS calls
1761 : //
1762 : class nsUIContext : public nsIInterfaceRequestor
1763 : {
1764 : public:
1765 : NS_DECL_ISUPPORTS
1766 : NS_DECL_NSIINTERFACEREQUESTOR
1767 :
1768 : nsUIContext(nsIDOMWindow *window);
1769 : virtual ~nsUIContext();
1770 :
1771 : private:
1772 : nsCOMPtr<nsIDOMWindow> mWindow;
1773 : };
1774 :
1775 0 : NS_IMPL_ISUPPORTS1(nsUIContext, nsIInterfaceRequestor)
1776 :
1777 0 : nsUIContext::nsUIContext(nsIDOMWindow *aWindow)
1778 0 : : mWindow(aWindow)
1779 : {
1780 0 : }
1781 :
1782 0 : nsUIContext::~nsUIContext()
1783 : {
1784 0 : }
1785 :
1786 : /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
1787 0 : NS_IMETHODIMP nsUIContext::GetInterface(const nsIID & uuid, void * *result)
1788 : {
1789 0 : NS_ENSURE_TRUE(mWindow, NS_ERROR_FAILURE);
1790 : nsresult rv;
1791 :
1792 0 : if (uuid.Equals(NS_GET_IID(nsIPrompt))) {
1793 0 : nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(mWindow, &rv);
1794 0 : if (NS_FAILED(rv)) return rv;
1795 :
1796 : nsIPrompt *prompt;
1797 :
1798 0 : rv = window->GetPrompter(&prompt);
1799 0 : *result = prompt;
1800 0 : } else if (uuid.Equals(NS_GET_IID(nsIDOMWindow))) {
1801 0 : *result = mWindow;
1802 0 : NS_ADDREF ((nsISupports*) *result);
1803 0 : rv = NS_OK;
1804 : } else {
1805 0 : rv = NS_ERROR_NO_INTERFACE;
1806 : }
1807 :
1808 0 : return rv;
1809 : }
1810 :
1811 : bool
1812 0 : nsSecureBrowserUIImpl::GetNSSDialogs(nsCOMPtr<nsISecurityWarningDialogs> & dialogs,
1813 : nsCOMPtr<nsIInterfaceRequestor> & ctx)
1814 : {
1815 0 : if (!NS_IsMainThread()) {
1816 0 : NS_ERROR("nsSecureBrowserUIImpl::GetNSSDialogs called off the main thread");
1817 0 : return false;
1818 : }
1819 :
1820 0 : dialogs = do_GetService(NS_SECURITYWARNINGDIALOGS_CONTRACTID);
1821 0 : if (!dialogs)
1822 0 : return false;
1823 :
1824 0 : nsCOMPtr<nsIDOMWindow> window;
1825 : {
1826 0 : ReentrantMonitorAutoEnter lock(mReentrantMonitor);
1827 0 : window = do_QueryReferent(mWindow);
1828 0 : NS_ASSERTION(window, "Window has gone away?!");
1829 : }
1830 0 : ctx = new nsUIContext(window);
1831 :
1832 0 : return true;
1833 : }
1834 :
1835 0 : bool nsSecureBrowserUIImpl::
1836 : ConfirmEnteringSecure()
1837 : {
1838 0 : nsCOMPtr<nsISecurityWarningDialogs> dialogs;
1839 0 : nsCOMPtr<nsIInterfaceRequestor> ctx;
1840 :
1841 0 : if (!GetNSSDialogs(dialogs, ctx)) {
1842 0 : return false; // Should this allow true for unimplemented?
1843 : }
1844 :
1845 : bool confirms;
1846 0 : dialogs->ConfirmEnteringSecure(ctx, &confirms);
1847 :
1848 0 : return confirms;
1849 : }
1850 :
1851 0 : bool nsSecureBrowserUIImpl::
1852 : ConfirmEnteringWeak()
1853 : {
1854 0 : nsCOMPtr<nsISecurityWarningDialogs> dialogs;
1855 0 : nsCOMPtr<nsIInterfaceRequestor> ctx;
1856 :
1857 0 : if (!GetNSSDialogs(dialogs, ctx)) {
1858 0 : return false; // Should this allow true for unimplemented?
1859 : }
1860 :
1861 : bool confirms;
1862 0 : dialogs->ConfirmEnteringWeak(ctx, &confirms);
1863 :
1864 0 : return confirms;
1865 : }
1866 :
1867 0 : bool nsSecureBrowserUIImpl::
1868 : ConfirmLeavingSecure()
1869 : {
1870 0 : nsCOMPtr<nsISecurityWarningDialogs> dialogs;
1871 0 : nsCOMPtr<nsIInterfaceRequestor> ctx;
1872 :
1873 0 : if (!GetNSSDialogs(dialogs, ctx)) {
1874 0 : return false; // Should this allow true for unimplemented?
1875 : }
1876 :
1877 : bool confirms;
1878 0 : dialogs->ConfirmLeavingSecure(ctx, &confirms);
1879 :
1880 0 : return confirms;
1881 : }
1882 :
1883 0 : bool nsSecureBrowserUIImpl::
1884 : ConfirmMixedMode()
1885 : {
1886 0 : nsCOMPtr<nsISecurityWarningDialogs> dialogs;
1887 0 : nsCOMPtr<nsIInterfaceRequestor> ctx;
1888 :
1889 0 : if (!GetNSSDialogs(dialogs, ctx)) {
1890 0 : return false; // Should this allow true for unimplemented?
1891 : }
1892 :
1893 : bool confirms;
1894 0 : dialogs->ConfirmMixedMode(ctx, &confirms);
1895 :
1896 0 : return confirms;
1897 : }
1898 :
1899 : /**
1900 : * ConfirmPostToInsecure - returns true if
1901 : * the user approves the submit (or doesn't care).
1902 : * returns false on errors.
1903 : */
1904 0 : bool nsSecureBrowserUIImpl::
1905 : ConfirmPostToInsecure()
1906 : {
1907 0 : nsCOMPtr<nsISecurityWarningDialogs> dialogs;
1908 0 : nsCOMPtr<nsIInterfaceRequestor> ctx;
1909 :
1910 0 : if (!GetNSSDialogs(dialogs, ctx)) {
1911 0 : return false; // Should this allow true for unimplemented?
1912 : }
1913 :
1914 : bool result;
1915 :
1916 0 : nsresult rv = dialogs->ConfirmPostToInsecure(ctx, &result);
1917 0 : if (NS_FAILED(rv)) return false;
1918 :
1919 0 : return result;
1920 : }
1921 :
1922 : /**
1923 : * ConfirmPostToInsecureFromSecure - returns true if
1924 : * the user approves the submit (or doesn't care).
1925 : * returns false on errors.
1926 : */
1927 0 : bool nsSecureBrowserUIImpl::
1928 : ConfirmPostToInsecureFromSecure()
1929 : {
1930 0 : nsCOMPtr<nsISecurityWarningDialogs> dialogs;
1931 0 : nsCOMPtr<nsIInterfaceRequestor> ctx;
1932 :
1933 0 : if (!GetNSSDialogs(dialogs, ctx)) {
1934 0 : return false; // Should this allow true for unimplemented?
1935 : }
1936 :
1937 : bool result;
1938 :
1939 0 : nsresult rv = dialogs->ConfirmPostToInsecureFromSecure(ctx, &result);
1940 0 : if (NS_FAILED(rv)) return false;
1941 :
1942 0 : return result;
1943 : }
|