Single patch for 3 overlapping fixes. Bug 420187, hang in nsNSSHttpRequestSession::internal_send_receive_attempt r=rrelyea Bug 383369, fixing a regression from 335801 r=rrelyea Bug 358438, fix proposed by and portions contributed by Honza Bambas r=honzab, r=rrelyea approval1.9 for combined patch = beltzner

This commit is contained in:
kaie@kuix.de 2008-04-11 21:47:22 -07:00
Родитель b18b0867f6
Коммит 3b89434010
11 изменённых файлов: 422 добавлений и 126 удалений

Просмотреть файл

@ -166,6 +166,10 @@ nsSecureBrowserUIImpl::nsSecureBrowserUIImpl()
mNewToplevelIsEV = PR_FALSE;
mNewToplevelSecurityStateKnown = PR_TRUE;
ResetStateTracking();
mSubRequestsHighSecurity = 0;
mSubRequestsLowSecurity = 0;
mSubRequestsBrokenSecurity = 0;
mSubRequestsNoSecurity = 0;
#if defined(PR_LOGGING)
if (!gSecureDocLog)
@ -359,31 +363,28 @@ static nsresult IsChildOfDomWindow(nsIDOMWindow *parent, nsIDOMWindow *child,
return NS_OK;
}
static PRUint32 GetSecurityStateFromChannel(nsIChannel* aChannel)
static PRUint32 GetSecurityStateFromSecurityInfo(nsISupports *info)
{
nsresult res;
PRUint32 securityState;
// qi for the psm information about this channel load.
nsCOMPtr<nsISupports> info;
aChannel->GetSecurityInfo(getter_AddRefs(info));
nsCOMPtr<nsITransportSecurityInfo> psmInfo(do_QueryInterface(info));
if (!psmInfo) {
PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState:%p - no nsITransportSecurityInfo for %p\n",
aChannel, (nsISupports *)info));
PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - no nsITransportSecurityInfo for %p\n",
(nsISupports *)info));
return nsIWebProgressListener::STATE_IS_INSECURE;
}
PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState:%p - info is %p\n", aChannel,
PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - info is %p\n",
(nsISupports *)info));
res = psmInfo->GetSecurityState(&securityState);
if (NS_FAILED(res)) {
PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState:%p - GetSecurityState failed: %d\n",
aChannel, res));
PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - GetSecurityState failed: %d\n",
res));
securityState = nsIWebProgressListener::STATE_IS_BROKEN;
}
PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState:%p - Returning %d\n", aChannel,
PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - Returning %d\n",
securityState));
return securityState;
}
@ -471,10 +472,6 @@ void nsSecureBrowserUIImpl::ResetStateTracking()
mInfoTooltip.Truncate();
mDocumentRequestsInProgress = 0;
mSubRequestsHighSecurity = 0;
mSubRequestsLowSecurity = 0;
mSubRequestsBrokenSecurity = 0;
mSubRequestsNoSecurity = 0;
if (mTransferringRequests.ops) {
PL_DHashTableFinish(&mTransferringRequests);
mTransferringRequests.ops = nsnull;
@ -484,10 +481,8 @@ void nsSecureBrowserUIImpl::ResetStateTracking()
}
nsresult
nsSecureBrowserUIImpl::EvaluateAndUpdateSecurityState(nsIRequest *aRequest)
nsSecureBrowserUIImpl::EvaluateAndUpdateSecurityState(nsIRequest* aRequest, nsISupports *info)
{
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
/* I explicitly ignore the camelCase variable naming style here,
I want to make it clear these are temp variables that relate to the
member variables with the same suffix.*/
@ -501,16 +496,12 @@ nsSecureBrowserUIImpl::EvaluateAndUpdateSecurityState(nsIRequest *aRequest)
PRBool updateTooltip = PR_FALSE;
nsXPIDLString temp_InfoTooltip;
if (channel) {
temp_NewToplevelSecurityState = GetSecurityStateFromChannel(channel);
temp_NewToplevelSecurityState = GetSecurityStateFromSecurityInfo(info);
PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
("SecureUI:%p: OnStateChange: remember mNewToplevelSecurityState => %x\n", this,
temp_NewToplevelSecurityState));
// Get SSL Status information if possible
nsCOMPtr<nsISupports> info;
channel->GetSecurityInfo(getter_AddRefs(info));
nsCOMPtr<nsISSLStatusProvider> sp = do_QueryInterface(info);
if (sp) {
// Ignore result
@ -533,7 +524,6 @@ nsSecureBrowserUIImpl::EvaluateAndUpdateSecurityState(nsIRequest *aRequest)
}
}
}
}
// assume temp_NewToplevelSecurityState was set in this scope!
// see code that is directly above
@ -549,22 +539,21 @@ nsSecureBrowserUIImpl::EvaluateAndUpdateSecurityState(nsIRequest *aRequest)
if (updateTooltip) {
mInfoTooltip = temp_InfoTooltip;
}
PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
("SecureUI:%p: remember securityInfo %p\n", this,
info));
mCurrentToplevelSecurityInfo = info;
}
return UpdateSecurityState(aRequest);
}
void
nsSecureBrowserUIImpl::UpdateSubrequestMembers(nsIRequest *aRequest)
nsSecureBrowserUIImpl::UpdateSubrequestMembers(nsISupports *securityInfo)
{
// For wyciwyg channels in subdocuments we only update our
// subrequest state members.
PRUint32 reqState = nsIWebProgressListener::STATE_IS_INSECURE;
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
if (channel) {
reqState = GetSecurityStateFromChannel(channel);
}
PRUint32 reqState = GetSecurityStateFromSecurityInfo(securityInfo);
// the code above this line should run without a lock
nsAutoMonitor lock(mMonitor);
@ -749,10 +738,13 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
}
#endif
nsCOMPtr<nsISupports> securityInfo;
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
if (channel)
{
channel->GetSecurityInfo(getter_AddRefs(securityInfo));
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
if (uri)
@ -914,6 +906,11 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
f -= nsIWebProgressListener::STATE_SECURE_LOW;
info.Append("SECURE_LOW ");
}
if (f & nsIWebProgressListener::STATE_RESTORING)
{
f -= nsIWebProgressListener::STATE_RESTORING;
info.Append("STATE_RESTORING ");
}
if (f > 0)
{
@ -930,7 +927,7 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
{
PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
("SecureUI:%p: OnStateChange: seeing STOP with security state: %d\n", this,
GetSecurityStateFromChannel(channel)
GetSecurityStateFromSecurityInfo(securityInfo)
));
}
#endif
@ -964,12 +961,13 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
}
}
PRBool allowSecurityStateChange = PR_TRUE;
if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
{
// The original consumer (this) is no longer the target of the load.
// Ignore any events with this flag, do not allow them to update
// our secure UI state.
return NS_OK;
allowSecurityStateChange = PR_FALSE;
}
if (aProgressStateFlags & STATE_START
@ -980,27 +978,99 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
&&
loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
{
nsAutoMonitor lock(mMonitor);
if (!mDocumentRequestsInProgress)
PRBool inProgress;
PRInt32 saveSubHigh;
PRInt32 saveSubLow;
PRInt32 saveSubBroken;
PRInt32 saveSubNo;
nsCOMPtr<nsIAssociatedContentSecurity> prevContentSecurity;
PRInt32 newSubHigh = 0;
PRInt32 newSubLow = 0;
PRInt32 newSubBroken = 0;
PRInt32 newSubNo = 0;
{
nsAutoMonitor lock(mMonitor);
inProgress = (mDocumentRequestsInProgress!=0);
if (allowSecurityStateChange && !inProgress)
{
saveSubHigh = mSubRequestsHighSecurity;
saveSubLow = mSubRequestsLowSecurity;
saveSubBroken = mSubRequestsBrokenSecurity;
saveSubNo = mSubRequestsNoSecurity;
prevContentSecurity = do_QueryInterface(mCurrentToplevelSecurityInfo);
}
}
if (allowSecurityStateChange && !inProgress)
{
PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
("SecureUI:%p: OnStateChange: start for toplevel document\n", this
));
ResetStateTracking();
mNewToplevelSecurityStateKnown = PR_FALSE;
if (prevContentSecurity)
{
PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
("SecureUI:%p: OnStateChange: start, saving current sub state\n", this
));
// before resetting our state, let's save information about
// sub element loads, so we can restore it later
prevContentSecurity->SetCountSubRequestsHighSecurity(saveSubHigh);
prevContentSecurity->SetCountSubRequestsLowSecurity(saveSubLow);
prevContentSecurity->SetCountSubRequestsBrokenSecurity(saveSubBroken);
prevContentSecurity->SetCountSubRequestsNoSecurity(saveSubNo);
}
if (securityInfo &&
(aProgressStateFlags & nsIWebProgressListener::STATE_RESTORING) != 0)
{
// When restoring from bfcache, we will not get events for the
// page's sub elements, so let's load the state of sub elements
// from the cache.
nsCOMPtr<nsIAssociatedContentSecurity>
newContentSecurity(do_QueryInterface(securityInfo));
if (newContentSecurity)
{
PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
("SecureUI:%p: OnStateChange: start, loading old sub state\n", this
));
newContentSecurity->GetCountSubRequestsHighSecurity(&newSubHigh);
newContentSecurity->GetCountSubRequestsLowSecurity(&newSubLow);
newContentSecurity->GetCountSubRequestsBrokenSecurity(&newSubBroken);
newContentSecurity->GetCountSubRequestsNoSecurity(&newSubNo);
}
}
}
// By using a counter, this code also works when the toplevel
// document get's redirected, but the STOP request for the
// previous toplevel document has not yet have been received.
{
nsAutoMonitor lock(mMonitor);
PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
("SecureUI:%p: OnStateChange: ++mDocumentRequestsInProgress\n", this
));
if (allowSecurityStateChange && !inProgress)
{
ResetStateTracking();
mSubRequestsHighSecurity = newSubHigh;
mSubRequestsLowSecurity = newSubLow;
mSubRequestsBrokenSecurity = newSubBroken;
mSubRequestsNoSecurity = newSubNo;
mNewToplevelSecurityStateKnown = PR_FALSE;
}
// By using a counter, this code also works when the toplevel
// document get's redirected, but the STOP request for the
// previous toplevel document has not yet have been received.
PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
("SecureUI:%p: OnStateChange: ++mDocumentRequestsInProgress\n", this
));
++mDocumentRequestsInProgress;
}
++mDocumentRequestsInProgress;
return NS_OK;
}
@ -1018,7 +1088,10 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
{
nsAutoMonitor lock(mMonitor);
temp_DocumentRequestsInProgress = mDocumentRequestsInProgress;
temp_ToplevelEventSink = mToplevelEventSink;
if (allowSecurityStateChange)
{
temp_ToplevelEventSink = mToplevelEventSink;
}
}
if (temp_DocumentRequestsInProgress <= 0)
@ -1034,20 +1107,26 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
if (!temp_ToplevelEventSink && channel)
{
ObtainEventSink(channel, temp_ToplevelEventSink);
if (allowSecurityStateChange)
{
ObtainEventSink(channel, temp_ToplevelEventSink);
}
}
{
nsAutoMonitor lock(mMonitor);
mToplevelEventSink = temp_ToplevelEventSink;
if (allowSecurityStateChange)
{
mToplevelEventSink = temp_ToplevelEventSink;
}
--mDocumentRequestsInProgress;
}
if (requestHasTransferedData) {
if (allowSecurityStateChange && requestHasTransferedData) {
// Data has been transferred for the single toplevel
// request. Evaluate the security state.
return EvaluateAndUpdateSecurityState(aRequest);
return EvaluateAndUpdateSecurityState(aRequest, securityInfo);
}
return NS_OK;
@ -1064,9 +1143,9 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
// We only care for the security state of sub requests which have actually transfered data.
if (requestHasTransferedData)
if (allowSecurityStateChange && requestHasTransferedData)
{
UpdateSubrequestMembers(aRequest);
UpdateSubrequestMembers(securityInfo);
// Care for the following scenario:
// A new top level document load might have already started,
@ -1251,8 +1330,8 @@ void nsSecureBrowserUIImpl::UpdateMyFlags(PRBool &showWarning, lockIconState &wa
mNotifiedToplevelIsEV = mNewToplevelIsEV;
}
nsresult nsSecureBrowserUIImpl::TellTheWorld(PRBool &showWarning,
lockIconState &warnSecurityState,
nsresult nsSecureBrowserUIImpl::TellTheWorld(PRBool showWarning,
lockIconState warnSecurityState,
nsIRequest* aRequest)
{
nsCOMPtr<nsISecurityEventSink> temp_ToplevelEventSink;
@ -1322,6 +1401,9 @@ nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress,
NS_ASSERTION(mOnStateLocationChangeReentranceDetection == 1,
"unexpected parallel nsIWebProgress OnStateChange and/or OnLocationChange notification");
PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
("SecureUI:%p: OnLocationChange\n", this));
PRBool updateIsViewSource = PR_FALSE;
PRBool temp_IsViewSource = PR_FALSE;
nsCOMPtr<nsIDOMWindow> window;
@ -1368,13 +1450,18 @@ nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress,
nsCOMPtr<nsIDOMWindow> windowForProgress;
aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress));
nsCOMPtr<nsISupports> securityInfo;
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
if (channel)
channel->GetSecurityInfo(getter_AddRefs(securityInfo));
if (windowForProgress.get() == window.get()) {
// For toplevel channels, update the security state right away.
return EvaluateAndUpdateSecurityState(aRequest);
return EvaluateAndUpdateSecurityState(aRequest, securityInfo);
}
// For channels in subdocuments we only update our subrequest state members.
UpdateSubrequestMembers(aRequest);
UpdateSubrequestMembers(securityInfo);
// Care for the following scenario:

Просмотреть файл

@ -58,6 +58,7 @@
#include "nsISecurityEventSink.h"
#include "nsWeakReference.h"
#include "nsISSLStatusProvider.h"
#include "nsIAssociatedContentSecurity.h"
#include "pldhash.h"
#include "prmon.h"
@ -120,7 +121,6 @@ protected:
nsXPIDLString mInfoTooltip;
PRInt32 mDocumentRequestsInProgress;
PRInt32 mSubRequestsInProgress;
PRInt32 mSubRequestsHighSecurity;
PRInt32 mSubRequestsLowSecurity;
PRInt32 mSubRequestsBrokenSecurity;
@ -129,17 +129,18 @@ protected:
static nsresult MapInternalToExternalState(PRUint32* aState, lockIconState lock, PRBool ev);
nsresult UpdateSecurityState(nsIRequest* aRequest);
void UpdateMyFlags(PRBool &showWarning, lockIconState &warnSecurityState);
nsresult TellTheWorld(PRBool &showWarning,
lockIconState &warnSecurityState,
nsresult TellTheWorld(PRBool showWarning,
lockIconState warnSecurityState,
nsIRequest* aRequest);
nsresult EvaluateAndUpdateSecurityState(nsIRequest *aRequest);
void UpdateSubrequestMembers(nsIRequest *aRequest);
nsresult EvaluateAndUpdateSecurityState(nsIRequest* aRequest, nsISupports *info);
void UpdateSubrequestMembers(nsISupports *securityInfo);
void ObtainEventSink(nsIChannel *channel,
nsCOMPtr<nsISecurityEventSink> &sink);
nsCOMPtr<nsISupports> mSSLStatus;
nsCOMPtr<nsISupports> mCurrentToplevelSecurityInfo;
void GetBundleString(const PRUnichar* name, nsAString &outString);

Просмотреть файл

@ -62,6 +62,7 @@ XPIDLSRCS = \
nsIBadCertListener2.idl \
nsISSLErrorListener.idl \
nsIIdentityInfo.idl \
nsIAssociatedContentSecurity.idl \
nsICertOverrideService.idl \
nsIRecentBadCertsService.idl \
nsIFormSigningDialog.idl \

Просмотреть файл

@ -0,0 +1,56 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Google Inc.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Honza Bambas <honzab@allpeers.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* This interface is used to cache associated (sub) content security
* state. That is determined asynchronously based on callback notification
* while loading the content and its sub content particles.
*
* Some optimizations like bfcaching removes these callback notifications
* and therefor the subcontent state could not be determined. In such
* a case it is loaded from this object stored in nsIChannel.securityInfo.
*/
#include "nsISupports.idl"
[scriptable, uuid(8DB92DDE-799F-4d33-80F7-459CAC800DC9)]
interface nsIAssociatedContentSecurity : nsISupports
{
attribute long countSubRequestsHighSecurity;
attribute long countSubRequestsLowSecurity;
attribute long countSubRequestsBrokenSecurity;
attribute long countSubRequestsNoSecurity;
};

Просмотреть файл

@ -80,12 +80,13 @@ NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
extern PRLogModuleInfo* gPIPNSSLog;
#endif
struct nsHTTPDownloadEvent : nsRunnable {
class nsHTTPDownloadEvent : public nsRunnable {
public:
nsHTTPDownloadEvent();
~nsHTTPDownloadEvent();
NS_IMETHOD Run();
nsNSSHttpRequestSession *mRequestSession; // no ownership
nsCOMPtr<nsHTTPListener> mListener;
@ -120,9 +121,8 @@ nsHTTPDownloadEvent::Run()
// Create a loadgroup for this new channel. This way if the channel
// is redirected, we'll have a way to cancel the resulting channel.
nsCOMPtr<nsILoadGroup> loadGroup =
do_CreateInstance(NS_LOADGROUP_CONTRACTID);
chan->SetLoadGroup(loadGroup);
nsCOMPtr<nsILoadGroup> lg = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
chan->SetLoadGroup(lg);
if (mRequestSession->mHasPostData)
{
@ -148,11 +148,13 @@ nsHTTPDownloadEvent::Run()
rv = hchan->SetRequestMethod(mRequestSession->mRequestMethod);
NS_ENSURE_SUCCESS(rv, rv);
nsSSLThread::rememberPendingHTTPRequest(loadGroup);
mResponsibleForDoneSignal = PR_FALSE;
mListener->mResponsibleForDoneSignal = PR_TRUE;
mListener->mLoadGroup = lg.get();
NS_ADDREF(mListener->mLoadGroup);
mListener->mLoadGroupOwnerThread = PR_GetCurrentThread();
rv = NS_NewStreamLoader(getter_AddRefs(mListener->mLoader),
mListener);
@ -162,16 +164,21 @@ nsHTTPDownloadEvent::Run()
if (NS_FAILED(rv)) {
mListener->mResponsibleForDoneSignal = PR_FALSE;
mResponsibleForDoneSignal = PR_TRUE;
nsSSLThread::rememberPendingHTTPRequest(nsnull);
NS_RELEASE(mListener->mLoadGroup);
mListener->mLoadGroup = nsnull;
mListener->mLoadGroupOwnerThread = nsnull;
}
return NS_OK;
}
struct nsCancelHTTPDownloadEvent : nsRunnable {
nsCOMPtr<nsHTTPListener> mListener;
NS_IMETHOD Run() {
nsSSLThread::cancelPendingHTTPRequest();
mListener->FreeLoadGroup(PR_TRUE);
mListener = nsnull;
return NS_OK;
}
};
@ -367,7 +374,6 @@ nsNSSHttpRequestSession::internal_send_receive_attempt(PRBool &retryable_error,
}
PRBool request_canceled = PR_FALSE;
PRBool aborted_wait = PR_FALSE;
{
nsAutoLock locker(waitLock);
@ -410,30 +416,26 @@ nsNSSHttpRequestSession::internal_send_receive_attempt(PRBool &retryable_error,
if (!request_canceled)
{
if ((PRIntervalTime)(PR_IntervalNow() - start_time) > mTimeoutInterval)
PRBool wantExit = nsSSLThread::exitRequested();
PRBool timeout =
(PRIntervalTime)(PR_IntervalNow() - start_time) > mTimeoutInterval;
if (wantExit || timeout)
{
request_canceled = PR_TRUE;
// but we'll to continue to wait for waitFlag
nsCOMPtr<nsIRunnable> cancelevent = new nsCancelHTTPDownloadEvent;
nsRefPtr<nsCancelHTTPDownloadEvent> cancelevent = new nsCancelHTTPDownloadEvent;
cancelevent->mListener = mListener;
rv = NS_DispatchToMainThread(cancelevent);
if (NS_FAILED(rv))
{
if (NS_FAILED(rv)) {
NS_WARNING("cannot post cancel event");
aborted_wait = PR_TRUE;
break;
}
break;
}
}
}
}
if (aborted_wait)
{
// we couldn't cancel it, let's no longer reference it
nsSSLThread::rememberPendingHTTPRequest(nsnull);
}
if (request_canceled)
return SECFailure;
@ -535,7 +537,9 @@ nsHTTPListener::nsHTTPListener()
mLock(nsnull),
mCondition(nsnull),
mWaitFlag(PR_TRUE),
mResponsibleForDoneSignal(PR_FALSE)
mResponsibleForDoneSignal(PR_FALSE),
mLoadGroup(nsnull),
mLoadGroupOwnerThread(nsnull)
{
}
@ -575,6 +579,34 @@ nsHTTPListener::~nsHTTPListener()
NS_IMPL_THREADSAFE_ISUPPORTS1(nsHTTPListener, nsIStreamLoaderObserver)
void
nsHTTPListener::FreeLoadGroup(PRBool aCancelLoad)
{
nsILoadGroup *lg = nsnull;
if (mLock) {
nsAutoLock locker(mLock);
if (mLoadGroup) {
if (mLoadGroupOwnerThread != PR_GetCurrentThread()) {
NS_ASSERTION(PR_FALSE,
"attempt to access nsHTTPDownloadEvent::mLoadGroup on multiple threads, leaking it!");
}
else {
lg = mLoadGroup;
mLoadGroup = nsnull;
}
}
}
if (lg) {
if (aCancelLoad) {
lg->Cancel(NS_ERROR_ABORT);
}
NS_RELEASE(lg);
}
}
NS_IMETHODIMP
nsHTTPListener::OnStreamComplete(nsIStreamLoader* aLoader,
nsISupports* aContext,
@ -584,6 +616,8 @@ nsHTTPListener::OnStreamComplete(nsIStreamLoader* aLoader,
{
mResultCode = aStatus;
FreeLoadGroup(PR_FALSE);
nsCOMPtr<nsIRequest> req;
nsCOMPtr<nsIHttpChannel> hchan;
@ -628,8 +662,6 @@ nsHTTPListener::OnStreamComplete(nsIStreamLoader* aLoader,
void nsHTTPListener::send_done_signal()
{
nsSSLThread::rememberPendingHTTPRequest(nsnull);
mResponsibleForDoneSignal = PR_FALSE;
{

Просмотреть файл

@ -86,6 +86,14 @@ public:
PRBool mResponsibleForDoneSignal;
void send_done_signal();
// no nsCOMPtr. When I use it, I get assertions about
// loadgroup not being thread safe.
// So, let's use a raw pointer and ensure we only create and destroy
// it on the network thread ourselves.
nsILoadGroup *mLoadGroup;
PRThread *mLoadGroupOwnerThread;
void FreeLoadGroup(PRBool aCancelLoad);
};
class nsNSSHttpServerSession

Просмотреть файл

@ -1722,6 +1722,19 @@ nsNSSComponent::Init()
return rv;
}
// Access our string bundles now, this prevents assertions from I/O
// - nsStandardURL not thread-safe
// - wrong thread: 'NS_IsMainThread()' in nsIOService.cpp
// when loading error strings on the SSL threads.
{
NS_NAMED_LITERAL_STRING(dummy_name, "dummy");
nsXPIDLString result;
mPIPNSSBundle->GetStringFromName(dummy_name.get(),
getter_Copies(result));
mNSSErrorsBundle->GetStringFromName(dummy_name.get(),
getter_Copies(result));
}
if (!mPrefBranch) {
mPrefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ASSERTION(mPrefBranch, "Unable to get pref service");

Просмотреть файл

@ -204,6 +204,11 @@ nsNSSSocketInfo::nsNSSSocketInfo()
: mFd(nsnull),
mBlockingState(blocking_state_unknown),
mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
mSubRequestsHighSecurity(0),
mSubRequestsLowSecurity(0),
mSubRequestsBrokenSecurity(0),
mSubRequestsNoSecurity(0),
mDocShellDependentStuffKnown(PR_FALSE),
mExternalErrorReporting(PR_FALSE),
mForSTARTTLS(PR_FALSE),
mHandshakePending(PR_TRUE),
@ -232,12 +237,13 @@ void nsNSSSocketInfo::virtualDestroyNSSReference()
{
}
NS_IMPL_THREADSAFE_ISUPPORTS7(nsNSSSocketInfo,
NS_IMPL_THREADSAFE_ISUPPORTS8(nsNSSSocketInfo,
nsITransportSecurityInfo,
nsISSLSocketControl,
nsIInterfaceRequestor,
nsISSLStatusProvider,
nsIIdentityInfo,
nsIAssociatedContentSecurity,
nsISerializable,
nsIClassInfo)
@ -319,15 +325,30 @@ nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
return NS_OK;
}
mCallbacks = aCallbacks;
mDocShellDependentStuffKnown = PR_FALSE;
return NS_OK;
}
nsresult
nsNSSSocketInfo::EnsureDocShellDependentStuffKnown()
{
if (mDocShellDependentStuffKnown)
return NS_OK;
if (!mCallbacks || nsSSLThread::exitRequested())
return NS_ERROR_FAILURE;
mDocShellDependentStuffKnown = PR_TRUE;
nsCOMPtr<nsIInterfaceRequestor> proxiedCallbacks;
NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIInterfaceRequestor),
static_cast<nsIInterfaceRequestor*>(aCallbacks),
static_cast<nsIInterfaceRequestor*>(mCallbacks),
NS_PROXY_SYNC,
getter_AddRefs(proxiedCallbacks));
mCallbacks = proxiedCallbacks;
// Are we running within a context that wants external SSL error reporting?
// We'll look at the presence of a security UI object inside docshell.
// If the docshell wants the lock icon, you'll get the ssl error pages, too.
@ -339,7 +360,7 @@ nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
nsCOMPtr<nsIDocShell> docshell;
nsCOMPtr<nsIDocShellTreeItem> item(do_GetInterface(mCallbacks));
nsCOMPtr<nsIDocShellTreeItem> item(do_GetInterface(proxiedCallbacks));
if (item)
{
nsCOMPtr<nsIDocShellTreeItem> proxiedItem;
@ -395,6 +416,8 @@ nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
nsresult
nsNSSSocketInfo::GetExternalErrorReporting(PRBool* state)
{
nsresult rv = EnsureDocShellDependentStuffKnown();
NS_ENSURE_SUCCESS(rv, rv);
*state = mExternalErrorReporting;
return NS_OK;
}
@ -420,6 +443,54 @@ nsNSSSocketInfo::SetSecurityState(PRUint32 aState)
return NS_OK;
}
/* attribute unsigned long countSubRequestsHighSecurity; */
NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsHighSecurity(PRInt32 *aSubRequestsHighSecurity)
{
*aSubRequestsHighSecurity = mSubRequestsHighSecurity;
return NS_OK;
}
NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsHighSecurity(PRInt32 aSubRequestsHighSecurity)
{
mSubRequestsHighSecurity = aSubRequestsHighSecurity;
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute unsigned long countSubRequestsLowSecurity; */
NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsLowSecurity(PRInt32 *aSubRequestsLowSecurity)
{
*aSubRequestsLowSecurity = mSubRequestsLowSecurity;
return NS_OK;
}
NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsLowSecurity(PRInt32 aSubRequestsLowSecurity)
{
mSubRequestsLowSecurity = aSubRequestsLowSecurity;
return NS_OK;
}
/* attribute unsigned long countSubRequestsBrokenSecurity; */
NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsBrokenSecurity(PRInt32 *aSubRequestsBrokenSecurity)
{
*aSubRequestsBrokenSecurity = mSubRequestsBrokenSecurity;
return NS_OK;
}
NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsBrokenSecurity(PRInt32 aSubRequestsBrokenSecurity)
{
mSubRequestsBrokenSecurity = aSubRequestsBrokenSecurity;
return NS_OK;
}
/* attribute unsigned long countSubRequestsNoSecurity; */
NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsNoSecurity(PRInt32 *aSubRequestsNoSecurity)
{
*aSubRequestsNoSecurity = mSubRequestsNoSecurity;
return NS_OK;
}
NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsNoSecurity(PRInt32 aSubRequestsNoSecurity)
{
mSubRequestsNoSecurity = aSubRequestsNoSecurity;
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::GetShortSecurityDescription(PRUnichar** aText) {
if (mShortDesc.IsEmpty())
@ -465,10 +536,17 @@ NS_IMETHODIMP nsNSSSocketInfo::GetInterface(const nsIID & uuid, void * *result)
rv = ir->GetInterface(uuid, result);
} else {
// Proxy of the channel callbacks should probably go here, rather
// than in the password callback code
if (nsSSLThread::exitRequested())
return NS_ERROR_FAILURE;
rv = mCallbacks->GetInterface(uuid, result);
nsCOMPtr<nsIInterfaceRequestor> proxiedCallbacks;
NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIInterfaceRequestor),
mCallbacks,
NS_PROXY_SYNC,
getter_AddRefs(proxiedCallbacks));
rv = proxiedCallbacks->GetInterface(uuid, result);
}
return rv;
}
@ -619,6 +697,8 @@ nsresult nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr)
nsresult nsNSSSocketInfo::GetPreviousCert(nsIX509Cert** _result)
{
NS_ENSURE_ARG_POINTER(_result);
nsresult rv = EnsureDocShellDependentStuffKnown();
NS_ENSURE_SUCCESS(rv, rv);
*_result = mPreviousCert;
NS_IF_ADDREF(*_result);
@ -1142,6 +1222,9 @@ displayAlert(nsAFlatString &formattedString, nsNSSSocketInfo *infoObject)
// The interface requestor object may not be safe, so proxy the call to get
// the nsIPrompt.
if (nsSSLThread::exitRequested())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIInterfaceRequestor> proxiedCallbacks;
NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIInterfaceRequestor),
@ -1176,6 +1259,10 @@ nsHandleSSLError(nsNSSSocketInfo *socketInfo, PRInt32 err)
return NS_OK;
}
if (nsSSLThread::exitRequested()) {
return NS_ERROR_FAILURE;
}
nsresult rv;
NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
@ -1190,9 +1277,16 @@ nsHandleSSLError(nsNSSSocketInfo *socketInfo, PRInt32 err)
socketInfo->GetPort(&port);
// Try to get a nsISSLErrorListener implementation from the socket consumer.
nsCOMPtr<nsIInterfaceRequestor> callbacks;
socketInfo->GetNotificationCallbacks(getter_AddRefs(callbacks));
if (callbacks) {
nsCOMPtr<nsIInterfaceRequestor> cb;
socketInfo->GetNotificationCallbacks(getter_AddRefs(cb));
if (cb) {
nsCOMPtr<nsIInterfaceRequestor> callbacks;
NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIInterfaceRequestor),
cb,
NS_PROXY_SYNC,
getter_AddRefs(callbacks));
nsCOMPtr<nsISSLErrorListener> sel = do_GetInterface(callbacks);
if (sel) {
nsISSLErrorListener *proxy_sel = nsnull;
@ -2746,6 +2840,9 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
if (!infoObject)
return SECFailure;
if (nsSSLThread::exitRequested())
return cancel_and_failure(infoObject);
CERTCertificate *peerCert = nsnull;
CERTCertificateCleaner peerCertCleaner(peerCert);
peerCert = SSL_PeerCertificate(sslSocket);
@ -2915,9 +3012,16 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
nsresult rv;
// Try to get a nsIBadCertListener2 implementation from the socket consumer.
nsCOMPtr<nsIInterfaceRequestor> callbacks;
infoObject->GetNotificationCallbacks(getter_AddRefs(callbacks));
if (callbacks) {
nsCOMPtr<nsIInterfaceRequestor> cb;
infoObject->GetNotificationCallbacks(getter_AddRefs(cb));
if (cb) {
nsCOMPtr<nsIInterfaceRequestor> callbacks;
NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIInterfaceRequestor),
cb,
NS_PROXY_SYNC,
getter_AddRefs(callbacks));
nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(callbacks);
if (bcl) {
nsIBadCertListener2 *proxy_bcl = nsnull;

Просмотреть файл

@ -52,6 +52,7 @@
#include "nsSSLStatus.h"
#include "nsISSLStatusProvider.h"
#include "nsIIdentityInfo.h"
#include "nsIAssociatedContentSecurity.h"
#include "nsXPIDLString.h"
#include "nsNSSShutDown.h"
#include "nsAutoPtr.h"
@ -128,6 +129,7 @@ class nsNSSSocketInfo : public nsITransportSecurityInfo,
public nsIInterfaceRequestor,
public nsISSLStatusProvider,
public nsIIdentityInfo,
public nsIAssociatedContentSecurity,
public nsISerializable,
public nsIClassInfo,
public nsNSSShutDownObject,
@ -143,6 +145,7 @@ public:
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSISSLSTATUSPROVIDER
NS_DECL_NSIIDENTITYINFO
NS_DECL_NSIASSOCIATEDCONTENTSECURITY
NS_DECL_NSISERIALIZABLE
NS_DECL_NSICLASSINFO
@ -198,14 +201,19 @@ protected:
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
PRFileDesc* mFd;
nsCOMPtr<nsIX509Cert> mCert;
nsCOMPtr<nsIX509Cert> mPreviousCert;
nsCOMPtr<nsIX509Cert> mPreviousCert; // DocShellDependent
enum {
blocking_state_unknown, is_nonblocking_socket, is_blocking_socket
} mBlockingState;
PRUint32 mSecurityState;
PRInt32 mSubRequestsHighSecurity;
PRInt32 mSubRequestsLowSecurity;
PRInt32 mSubRequestsBrokenSecurity;
PRInt32 mSubRequestsNoSecurity;
nsString mShortDesc;
nsString mErrorMessage;
PRPackedBool mExternalErrorReporting;
PRPackedBool mDocShellDependentStuffKnown;
PRPackedBool mExternalErrorReporting; // DocShellDependent
PRPackedBool mForSTARTTLS;
PRPackedBool mHandshakePending;
PRPackedBool mCanceled;
@ -223,6 +231,8 @@ protected:
nsSSLSocketThreadData *mThreadData;
nsresult EnsureDocShellDependentStuffKnown();
private:
virtual void virtualDestroyNSSReference();
void destructorSafeDestroyNSSReference();

Просмотреть файл

@ -1120,28 +1120,14 @@ void nsSSLThread::Run(void)
}
}
void nsSSLThread::rememberPendingHTTPRequest(nsIRequest *aRequest)
PRBool nsSSLThread::exitRequested()
{
if (!ssl_thread_singleton)
return;
return PR_FALSE;
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
// no lock
ssl_thread_singleton->mPendingHTTPRequest = aRequest;
}
void nsSSLThread::cancelPendingHTTPRequest()
{
if (!ssl_thread_singleton)
return;
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
if (ssl_thread_singleton->mPendingHTTPRequest)
{
ssl_thread_singleton->mPendingHTTPRequest->Cancel(NS_ERROR_ABORT);
ssl_thread_singleton->mPendingHTTPRequest = nsnull;
}
return ssl_thread_singleton->mExitRequested;
}
nsSSLThread *nsSSLThread::ssl_thread_singleton = nsnull;

Просмотреть файл

@ -152,9 +152,7 @@ public:
static nsresult requestActivateSSL(nsNSSSocketInfo *si);
// Called from either Necko or SSL thread.
static void rememberPendingHTTPRequest(nsIRequest *aRequest);
static void cancelPendingHTTPRequest();
static PRBool exitRequested();
};
#endif //_NSSSLTHREAD_H_