Bug 466080 - Make more things honor the LOAD_ANONYMOUS flag r=sicking,MisterSSL, sr=sicking
☠☠ backed out by 4a49658eedc2 ☠ ☠
authorbjarne@runitsoft.com
Tue, 13 Jan 2009 23:06:39 -0800
changeset 23638 03bc3379822a8bf8811181582cefaa519cb0b1c3
parent 23637 d720aa40aae4be8eb1df33622d0b722cf68546f2
child 23639 39dc85bc5d99330529754ba28d7258b6a5271e99
child 23641 4a49658eedc297676c28692a7370490d14efc590
push id4652
push usersicking@mozilla.com
push dateWed, 14 Jan 2009 07:16:08 +0000
treeherdermozilla-central@03bc3379822a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking, MisterSSL, sicking
bugs466080
milestone1.9.2a1pre
Bug 466080 - Make more things honor the LOAD_ANONYMOUS flag r=sicking,MisterSSL, sr=sicking
netwerk/base/public/nsISocketTransport.idl
netwerk/base/src/nsSocketTransport2.cpp
netwerk/protocol/http/src/nsHttp.h
netwerk/protocol/http/src/nsHttpChannel.cpp
netwerk/protocol/http/src/nsHttpConnection.cpp
netwerk/socket/base/nsISocketProvider.idl
security/manager/ssl/src/nsNSSIOLayer.cpp
security/manager/ssl/src/nsNSSIOLayer.h
security/manager/ssl/src/nsSSLSocketProvider.cpp
security/manager/ssl/src/nsTLSSocketProvider.cpp
security/manager/ssl/tests/mochitest/Makefile.in
security/manager/ssl/tests/mochitest/bug466080.sjs
security/manager/ssl/tests/mochitest/test_bug466080.html
--- a/netwerk/base/public/nsISocketTransport.idl
+++ b/netwerk/base/public/nsISocketTransport.idl
@@ -145,16 +145,24 @@ interface nsISocketTransport : nsITransp
      * Values for the connectionFlags
      *
      * When making a new connection BYPASS_CACHE will force the Necko DNS 
      * cache entry to be refreshed with a new call to NSPR if it is set before
      * opening the new stream.
      */
     const unsigned long BYPASS_CACHE = (1 << 0);
 
+    /**
+     * When setting this flag, the socket will not apply any
+     * credentials when establishing a connection. For example,
+     * an SSL connection would not send any client-certificates
+     * if this flag is set.
+     */
+    const unsigned long ANONYMOUS_CONNECT = (1 << 1);
+
 };
 
 %{C++
 /**
  * #define's for compatibility
  */
 #define NS_NET_STATUS_RESOLVING_HOST nsISocketTransport::STATUS_RESOLVING
 #define NS_NET_STATUS_CONNECTED_TO   nsISocketTransport::STATUS_CONNECTED_TO
--- a/netwerk/base/src/nsSocketTransport2.cpp
+++ b/netwerk/base/src/nsSocketTransport2.cpp
@@ -997,16 +997,19 @@ nsSocketTransport::BuildSocket(PRFileDes
             LOG(("  pushing io layer [%u:%s]\n", i, mTypes[i]));
 
             rv = spserv->GetSocketProvider(mTypes[i], getter_AddRefs(provider));
             if (NS_FAILED(rv))
                 break;
 
             if (mProxyTransparentResolvesHost)
                 proxyFlags |= nsISocketProvider::PROXY_RESOLVES_HOST;
+            
+            if (mConnectionFlags & nsISocketTransport::ANONYMOUS_CONNECT)
+                proxyFlags |= nsISocketProvider::ANONYMOUS_CONNECT;
 
             nsCOMPtr<nsISupports> secinfo;
             if (i == 0) {
                 // if this is the first type, we'll want the 
                 // service to allocate a new socket
                 rv = provider->NewSocket(mNetAddr.raw.family,
                                          host, port, proxyHost, proxyPort,
                                          proxyFlags, &fd,
@@ -1021,17 +1024,17 @@ nsSocketTransport::BuildSocket(PRFileDes
                 // the socket has already been allocated, 
                 // so we just want the service to add itself
                 // to the stack (such as pushing an io layer)
                 rv = provider->AddToSocket(mNetAddr.raw.family,
                                            host, port, proxyHost, proxyPort,
                                            proxyFlags, fd,
                                            getter_AddRefs(secinfo));
             }
-            proxyFlags = 0;
+            // proxyFlags = 0; not used below this point...
             if (NS_FAILED(rv))
                 break;
 
             // if the service was ssl or starttls, we want to hold onto the socket info
             PRBool isSSL = (strcmp(mTypes[i], "ssl") == 0);
             if (isSSL || (strcmp(mTypes[i], "starttls") == 0)) {
                 // remember security info and give notification callbacks to PSM...
                 nsCOMPtr<nsIInterfaceRequestor> callbacks;
--- a/netwerk/protocol/http/src/nsHttp.h
+++ b/netwerk/protocol/http/src/nsHttp.h
@@ -103,16 +103,20 @@ typedef PRUint8 nsHttpVersion;
 // a transaction with this caps flag will continue to own the connection,
 // preventing it from being reclaimed, even after the transaction completes.
 #define NS_HTTP_STICKY_CONNECTION    (1<<2)
 
 // a transaction with this caps flag will, upon opening a new connection,
 // bypass the local DNS cache
 #define NS_HTTP_REFRESH_DNS          (1<<3)
 
+// a transaction with this caps flag will not pass SSL client-certificates
+// to the server (see bug #466080), but is may also be used for other things
+#define NS_HTTP_LOAD_ANONYMOUS       (1<<4)
+
 //-----------------------------------------------------------------------------
 // some default values
 //-----------------------------------------------------------------------------
 
 // hard upper limit on the number of requests that can be pipelined
 #define NS_HTTP_MAX_PIPELINED_REQUESTS 8 
 
 #define NS_HTTP_DEFAULT_PORT  80
--- a/netwerk/protocol/http/src/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/src/nsHttpChannel.cpp
@@ -652,16 +652,21 @@ nsHttpChannel::SetupTransaction()
         return NS_ERROR_OUT_OF_MEMORY;
 
     // create the transaction object
     mTransaction = new nsHttpTransaction();
     if (!mTransaction)
         return NS_ERROR_OUT_OF_MEMORY;
     NS_ADDREF(mTransaction);
 
+    // See bug #466080. Transfer LOAD_ANONYMOUS flag to socket-layer.
+    if (mLoadFlags & LOAD_ANONYMOUS) {
+        mCaps |= NS_HTTP_LOAD_ANONYMOUS;
+    }
+
     nsCOMPtr<nsIAsyncInputStream> responseStream;
     rv = mTransaction->Init(mCaps, mConnectionInfo, &mRequestHead,
                             mUploadStream, mUploadStreamHasHeaders,
                             NS_GetCurrentThread(), callbacks, this,
                             getter_AddRefs(responseStream));
     if (NS_FAILED(rv)) {
         NS_RELEASE(mTransaction);
         return rv;
--- a/netwerk/protocol/http/src/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/src/nsHttpConnection.cpp
@@ -447,18 +447,24 @@ nsHttpConnection::CreateTransport(PRUint
 
     rv = sts->CreateTransport(types, typeCount,
                               nsDependentCString(mConnInfo->Host()),
                               mConnInfo->Port(),
                               mConnInfo->ProxyInfo(),
                               getter_AddRefs(strans));
     if (NS_FAILED(rv)) return rv;
 
+    PRUint32 tmpFlags = 0;
     if (caps & NS_HTTP_REFRESH_DNS)
-        strans->SetConnectionFlags(nsISocketTransport::BYPASS_CACHE); 
+        tmpFlags = nsISocketTransport::BYPASS_CACHE;
+    
+    if (caps & NS_HTTP_LOAD_ANONYMOUS)
+        tmpFlags |= nsISocketTransport::ANONYMOUS_CONNECT;
+    
+    strans->SetConnectionFlags(tmpFlags); 
 
     // NOTE: these create cyclical references, which we break inside
     //       nsHttpConnection::Close
     rv = strans->SetEventSink(this, nsnull);
     if (NS_FAILED(rv)) return rv;
     rv = strans->SetSecurityCallbacks(this);
     if (NS_FAILED(rv)) return rv;
 
--- a/netwerk/socket/base/nsISocketProvider.idl
+++ b/netwerk/socket/base/nsISocketProvider.idl
@@ -101,16 +101,25 @@ interface nsISocketProvider : nsISupport
      * PROXY_RESOLVES_HOST
      *
      * This flag is set if the proxy is to perform hostname resolution instead
      * of the client.  When set, the hostname parameter passed when in this
      * interface will be used instead of the address structure passed for a
      * later connect et al. request.
      */
     const long PROXY_RESOLVES_HOST = 1 << 0;
+    
+    /**
+     * When setting this flag, the socket will not apply any
+     * credentials when establishing a connection. For example,
+     * an SSL connection would not send any client-certificates
+     * if this flag is set.
+     */
+    const long ANONYMOUS_CONNECT = 1 << 1;
+    
 };
 
 %{C++
 /**
  * nsISocketProvider implementations should be registered with XPCOM under a
  * contract ID of the form: "@mozilla.org/network/socket;2?type=foo"
  */
 #define NS_NETWORK_SOCKET_CONTRACTID_PREFIX \
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -1991,24 +1991,25 @@ PRBool nsSSLIOLayerHelpers::isKnownAsInt
 nsresult
 nsSSLIOLayerNewSocket(PRInt32 family,
                       const char *host,
                       PRInt32 port,
                       const char *proxyHost,
                       PRInt32 proxyPort,
                       PRFileDesc **fd,
                       nsISupports** info,
-                      PRBool forSTARTTLS)
+                      PRBool forSTARTTLS,
+                      PRBool anonymousLoad)
 {
 
   PRFileDesc* sock = PR_OpenTCPSocket(family);
   if (!sock) return NS_ERROR_OUT_OF_MEMORY;
 
   nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort,
-                                        sock, info, forSTARTTLS);
+                                        sock, info, forSTARTTLS, anonymousLoad);
   if (NS_FAILED(rv)) {
     PR_Close(sock);
     return rv;
   }
 
   *fd = sock;
   return NS_OK;
 }
@@ -3105,29 +3106,36 @@ nsNSSBadCertHandler(void *arg, PRFileDes
 
   PR_SetError(errorCodeToReport, 0);
   return cancel_and_failure(infoObject);
 }
 
 static PRFileDesc*
 nsSSLIOLayerImportFD(PRFileDesc *fd,
                      nsNSSSocketInfo *infoObject,
-                     const char *host)
+                     const char *host,
+                     PRBool anonymousLoad)
 {
   nsNSSShutDownPreventionLock locker;
   PRFileDesc* sslSock = SSL_ImportFD(nsnull, fd);
   if (!sslSock) {
     NS_ASSERTION(PR_FALSE, "NSS: Error importing socket");
     return nsnull;
   }
   SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*)infoObject);
   SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
-  SSL_GetClientAuthDataHook(sslSock, 
+
+  // Disable this hook if we connect anonymously. See bug 466080.
+  if (anonymousLoad) {
+      SSL_GetClientAuthDataHook(sslSock, NULL, infoObject);
+  } else {
+      SSL_GetClientAuthDataHook(sslSock, 
                             (SSLGetClientAuthData)nsNSS_SSLGetClientAuthData,
                             infoObject);
+  }
   SSL_AuthCertificateHook(sslSock, AuthCertificateCallback, 0);
 
   PRInt32 ret = SSL_SetURL(sslSock, host);
   if (ret == -1) {
     NS_ASSERTION(PR_FALSE, "NSS: Error setting server name");
     goto loser;
   }
   return sslSock;
@@ -3136,17 +3144,17 @@ loser:
     PR_Close(sslSock);
   }
   return nsnull;
 }
 
 static nsresult
 nsSSLIOLayerSetOptions(PRFileDesc *fd, PRBool forSTARTTLS, 
                        const char *proxyHost, const char *host, PRInt32 port,
-                       nsNSSSocketInfo *infoObject)
+                       PRBool anonymousLoad, nsNSSSocketInfo *infoObject)
 {
   nsNSSShutDownPreventionLock locker;
   if (forSTARTTLS || proxyHost) {
     if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, PR_FALSE)) {
       return NS_ERROR_FAILURE;
     }
     infoObject->SetHasCleartextPhase(PR_TRUE);
   }
@@ -3187,17 +3195,23 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, P
     return NS_ERROR_FAILURE;
   }
   if (SECSuccess != SSL_BadCertHook(fd, (SSLBadCertHandler) nsNSSBadCertHandler,
                                     infoObject)) {
     return NS_ERROR_FAILURE;
   }
 
   // Set the Peer ID so that SSL proxy connections work properly.
-  char *peerId = PR_smprintf("%s:%d", host, port);
+  char *peerId;
+  if (anonymousLoad) {  // See bug #466080. Separate the caches.
+      peerId = PR_smprintf("anon:%s:%d", host, port);
+  } else {
+      peerId = PR_smprintf("%s:%d", host, port);
+  }
+  
   if (SECSuccess != SSL_SetSockPeerID(fd, peerId)) {
     PR_smprintf_free(peerId);
     return NS_ERROR_FAILURE;
   }
 
   PR_smprintf_free(peerId);
   return NS_OK;
 }
@@ -3205,39 +3219,41 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, P
 nsresult
 nsSSLIOLayerAddToSocket(PRInt32 family,
                         const char* host,
                         PRInt32 port,
                         const char* proxyHost,
                         PRInt32 proxyPort,
                         PRFileDesc* fd,
                         nsISupports** info,
-                        PRBool forSTARTTLS)
+                        PRBool forSTARTTLS,
+                        PRBool anonymousLoad)
 {
   nsNSSShutDownPreventionLock locker;
   PRFileDesc* layer = nsnull;
   nsresult rv;
 
   nsNSSSocketInfo* infoObject = new nsNSSSocketInfo();
   if (!infoObject) return NS_ERROR_FAILURE;
   
   NS_ADDREF(infoObject);
   infoObject->SetForSTARTTLS(forSTARTTLS);
   infoObject->SetHostName(host);
   infoObject->SetPort(port);
 
-  PRFileDesc *sslSock = nsSSLIOLayerImportFD(fd, infoObject, host);
+  PRFileDesc *sslSock = nsSSLIOLayerImportFD(fd, infoObject, host, anonymousLoad);
   if (!sslSock) {
     NS_ASSERTION(PR_FALSE, "NSS: Error importing socket");
     goto loser;
   }
 
   infoObject->SetFileDescPtr(sslSock);
 
-  rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, proxyHost, host, port,
+  rv = nsSSLIOLayerSetOptions(sslSock,
+                              forSTARTTLS, proxyHost, host, port, anonymousLoad,
                               infoObject);
 
   if (NS_FAILED(rv))
     goto loser;
 
   /* Now, layer ourselves on top of the SSL socket... */
   layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
                                &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
--- a/security/manager/ssl/src/nsNSSIOLayer.h
+++ b/security/manager/ssl/src/nsNSSIOLayer.h
@@ -267,26 +267,28 @@ public:
 
 nsresult nsSSLIOLayerNewSocket(PRInt32 family,
                                const char *host,
                                PRInt32 port,
                                const char *proxyHost,
                                PRInt32 proxyPort,
                                PRFileDesc **fd,
                                nsISupports **securityInfo,
-                               PRBool forSTARTTLS);
+                               PRBool forSTARTTLS,
+                               PRBool anonymousLoad);
 
 nsresult nsSSLIOLayerAddToSocket(PRInt32 family,
                                  const char *host,
                                  PRInt32 port,
                                  const char *proxyHost,
                                  PRInt32 proxyPort,
                                  PRFileDesc *fd,
                                  nsISupports **securityInfo,
-                                 PRBool forSTARTTLS);
+                                 PRBool forSTARTTLS,
+                                 PRBool anonymousLoad);
 
 nsresult nsSSLIOLayerFreeTLSIntolerantSites();
 nsresult displayUnknownCertErrorAlert(nsNSSSocketInfo *infoObject, int error);
 
 // 16786594-0296-4471-8096-8f84497ca428
 #define NS_NSSSOCKETINFO_CID \
 { 0x16786594, 0x0296, 0x4471, \
     { 0x80, 0x96, 0x8f, 0x84, 0x49, 0x7c, 0xa4, 0x28 } }
--- a/security/manager/ssl/src/nsSSLSocketProvider.cpp
+++ b/security/manager/ssl/src/nsSSLSocketProvider.cpp
@@ -63,17 +63,18 @@ nsSSLSocketProvider::NewSocket(PRInt32 f
 {
   nsresult rv = nsSSLIOLayerNewSocket(family,
                                       host,
                                       port,
                                       proxyHost,
                                       proxyPort,
                                       _result,
                                       securityInfo,
-                                      PR_FALSE);
+                                      PR_FALSE,
+                                      flags & ANONYMOUS_CONNECT);
   return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
 }
 
 // Add the SSL IO layer to an existing socket
 NS_IMETHODIMP
 nsSSLSocketProvider::AddToSocket(PRInt32 family,
                                  const char *host,
                                  PRInt32 port,
@@ -85,12 +86,13 @@ nsSSLSocketProvider::AddToSocket(PRInt32
 {
   nsresult rv = nsSSLIOLayerAddToSocket(family,
                                         host,
                                         port,
                                         proxyHost,
                                         proxyPort,
                                         aSocket,
                                         securityInfo,
-                                        PR_FALSE);
+                                        PR_FALSE,
+                                        flags & ANONYMOUS_CONNECT);
   
   return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
 }
--- a/security/manager/ssl/src/nsTLSSocketProvider.cpp
+++ b/security/manager/ssl/src/nsTLSSocketProvider.cpp
@@ -63,17 +63,18 @@ nsTLSSocketProvider::NewSocket(PRInt32 f
 {
   nsresult rv = nsSSLIOLayerNewSocket(family,
                                       host,
                                       port,
                                       proxyHost,
                                       proxyPort,
                                       _result,
                                       securityInfo,
-                                      PR_TRUE);
+                                      PR_TRUE,
+                                      flags & ANONYMOUS_CONNECT);
   
   return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
 }
 
 // Add the SSL IO layer to an existing socket
 NS_IMETHODIMP
 nsTLSSocketProvider::AddToSocket(PRInt32 family,
                                  const char *host,
@@ -86,12 +87,13 @@ nsTLSSocketProvider::AddToSocket(PRInt32
 {
   nsresult rv = nsSSLIOLayerAddToSocket(family,
                                         host,
                                         port,
                                         proxyHost,
                                         proxyPort,
                                         aSocket,
                                         securityInfo,
-                                        PR_TRUE);
+                                        PR_TRUE,
+                                        flags & ANONYMOUS_CONNECT);
   
   return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
 }
--- a/security/manager/ssl/tests/mochitest/Makefile.in
+++ b/security/manager/ssl/tests/mochitest/Makefile.in
@@ -40,14 +40,16 @@ DEPTH		= ../../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir	= security/ssl
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
-# _CHROME_FILES	= \
-#		$(NULL)
+_CHROME_FILES	= \
+	test_bug466080.html \
+	bug466080.sjs \
+		$(NULL)
 #	test_bug413909.html \ # Leaks the world.
 
-# libs:: $(_CHROME_FILES)
-#	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
+libs:: $(_CHROME_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/bug466080.sjs
@@ -0,0 +1,17 @@
+
+function handleRequest(request, response)
+{
+    var body = "loaded";
+    var origin = "localhost";
+    try {
+        var origin = request.getHeader("Origin");
+     } catch(e) {}
+    
+    response.setHeader("Access-Control-Allow-Origin",
+                        origin,
+                        false);
+    response.setHeader("Access-Control-Allow-Credentials", "true", false);
+    response.setHeader("Connection", "Keep-alive", false);
+
+    response.bodyOutputStream.write(body, body.length);
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/test_bug466080.html
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test bug 466080</title>
+  <script type="text/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>        
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body onload="onWindowLoad()">
+<iframe id="frame1"
+        src="https://requireclientcert.example.com/chrome/security/ssl/bug466080.sjs"
+        onload="document.iframeWasLoaded = true">
+ 
+ This iframe should load the resource via the src-attribute from
+ a secure server which requires a client-cert. Doing this is
+ supposed to work, but further below in the test we try to load
+ the resource from the same url using a XHR, which should not work.
+ 
+ TODO : What if we change 'src' from JS? Would/should it load?
+
+</iframe>
+
+<script class="testbody" type="text/javascript">
+
+document.iframeWasLoaded = false;
+
+var alltests = [
+
+// load resource from a relative url - this should work
+  { url:"bug466080.sjs",
+    status_check:"==200",
+    error:"XHR from relative URL"},
+
+// TODO - load the resource from a relative url via https..?
+
+// load a non-existing resource - should get "404 Not Found"
+  { url:"bug466080-does-not.exist",
+    status_check:"==404",
+    error:"XHR loading non-existing resource"},
+
+// load resource from cross-site non-secure server
+  { url:"http://test1.example.com/chrome/security/ssl/bug466080.sjs",
+    status_check:"==200",
+    error:"XHR from cross-site plaintext server"},
+
+// load resource from cross-site secure server - should work since no credentials are needed
+  { url:"https://test1.example.com/chrome/security/ssl/bug466080.sjs",
+    status_check:"==200",
+    error:"XHR from cross-site secure server"},
+
+// load resource from cross-site secure server - should work since the server just requests certs
+  { url:"https://requestclientcert.example.com/chrome/security/ssl/bug466080.sjs",
+    status_check:"==200",
+    error:"XHR from cross-site secure server requesting certificate"},
+
+// load resource from cross-site secure server - should NOT work since the server requires cert
+// note that this is the url which is used in the iframe.src above
+  { url:"https://requireclientcert.example.com/chrome/security/ssl/bug466080.sjs",
+    status_check:"!=200",
+    error:"XHR from cross-site secure server requiring certificate"},
+
+// repeat previous,  - should NOT work
+  { url:"https://requireclientcert.example.com/chrome/security/ssl/bug466080.sjs",
+    status_check:"==200",
+    error:"XHR w/ credentials from cross-site secure server requiring certificate",
+    withCredentials:"true"},
+    
+// repeat previous, but with credentials - should work
+  { url:"https://requireclientcert.example.com/chrome/security/ssl/bug466080.sjs",
+    status_check:"==200",
+    error:"XHR w/ credentials from cross-site secure server requiring certificate",
+    withCredentials:"true"},
+
+// repeat previous, withCredentials but using a weird method to force preflight
+// should NOT work since our preflight is anonymous and will fail with our simple server
+  { url:"https://requireclientcert.example.com/chrome/security/ssl/bug466080.sjs",
+    status_check:"!=200",
+    error:"XHR PREFLIGHT from cross-site secure server requiring certificate",
+    withCredentials:"true",
+    method:"XMETHOD"},
+    
+];
+
+function onWindowLoad() {
+    // First, check that resource was loaded into the iframe
+    // This check in fact depends on bug #444165... :)
+    ok(document.iframeWasLoaded, "Loading resource via src-attribute");
+
+    for each (test in alltests) {
+
+        var xhr =  new XMLHttpRequest();
+        
+        var method = "GET";
+        if (test.method != null) { method = test.method; }
+        xhr.open(method, test.url, false);
+        
+        xhr.withCredentials = test.withCredentials;
+        xhr.setRequestHeader("Connection", "Keep-Alive", false);
+        try {
+            xhr.send();
+        } catch(e) {
+        }
+        var success = eval(xhr.status + test.status_check);
+        ok(success, test.error);
+    }
+    
+    SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>