forked from mirrors/gecko-dev
		
	 a5855be7e1
			
		
	
	
		a5855be7e1
		
	
	
	
	
		
			
			--HG-- rename : netwerk/test/unit/test_redirect_caching.js => netwerk/test/unit/test_redirect-caching_passing.js
		
			
				
	
	
		
			1856 lines
		
	
	
	
		
			56 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1856 lines
		
	
	
	
		
			56 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 | |
| /* vim:set ts=4 sw=4 sts=4 et cin: */
 | |
| /* ***** 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.
 | |
|  *
 | |
|  * The Initial Developer of the Original Code is
 | |
|  * Netscape Communications.
 | |
|  * Portions created by the Initial Developer are Copyright (C) 2001
 | |
|  * the Initial Developer. All Rights Reserved.
 | |
|  *
 | |
|  * Contributor(s):
 | |
|  *   Darin Fisher <darin@netscape.com> (original author)
 | |
|  *   Gagan Saksena <gagan@netscape.com>
 | |
|  *   Pierre Phaneuf <pp@ludusdesign.com>
 | |
|  *   Christopher Blizzard <blizzard@mozilla.org>
 | |
|  *   Adrian Havill <havill@redhat.com>
 | |
|  *   Gervase Markham <gerv@gerv.net>
 | |
|  *   Bradley Baetz <bbaetz@netscape.com>
 | |
|  *   Benjamin Smedberg <bsmedberg@covad.net>
 | |
|  *   Josh Aas <josh@mozilla.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 ***** */
 | |
| 
 | |
| #include "nsHttp.h"
 | |
| #include "nsHttpHandler.h"
 | |
| #include "nsHttpChannel.h"
 | |
| #include "nsHttpConnection.h"
 | |
| #include "nsHttpResponseHead.h"
 | |
| #include "nsHttpTransaction.h"
 | |
| #include "nsHttpAuthCache.h"
 | |
| #include "nsStandardURL.h"
 | |
| #include "nsIHttpChannel.h"
 | |
| #include "nsIURL.h"
 | |
| #include "nsIStandardURL.h"
 | |
| #include "nsICacheService.h"
 | |
| #include "nsICategoryManager.h"
 | |
| #include "nsCategoryManagerUtils.h"
 | |
| #include "nsICacheService.h"
 | |
| #include "nsIPrefService.h"
 | |
| #include "nsIPrefBranch2.h"
 | |
| #include "nsIPrefLocalizedString.h"
 | |
| #include "nsISocketProviderService.h"
 | |
| #include "nsISocketProvider.h"
 | |
| #include "nsPrintfCString.h"
 | |
| #include "nsCOMPtr.h"
 | |
| #include "nsNetCID.h"
 | |
| #include "nsAutoLock.h"
 | |
| #include "prprf.h"
 | |
| #include "nsReadableUtils.h"
 | |
| #include "nsQuickSort.h"
 | |
| #include "nsNetUtil.h"
 | |
| #include "nsIOService.h"
 | |
| #include "nsAsyncRedirectVerifyHelper.h"
 | |
| 
 | |
| #include "nsIXULAppInfo.h"
 | |
| 
 | |
| #ifdef MOZ_IPC
 | |
| #include "mozilla/net/NeckoChild.h"
 | |
| #endif 
 | |
| 
 | |
| #if defined(XP_UNIX) || defined(XP_BEOS)
 | |
| #include <sys/utsname.h>
 | |
| #endif
 | |
| 
 | |
| #if defined(XP_WIN)
 | |
| #include <windows.h>
 | |
| #endif
 | |
| 
 | |
| #if defined(XP_MACOSX)
 | |
| #include <CoreServices/CoreServices.h>
 | |
| #endif
 | |
| 
 | |
| #if defined(XP_OS2)
 | |
| #define INCL_DOSMISC
 | |
| #include <os2.h>
 | |
| #endif
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| using namespace mozilla::net;
 | |
| #ifdef MOZ_IPC
 | |
| #include "mozilla/net/HttpChannelChild.h"
 | |
| #endif 
 | |
| 
 | |
| #include "mozilla/FunctionTimer.h"
 | |
| 
 | |
| #ifdef DEBUG
 | |
| // defined by the socket transport service while active
 | |
| extern PRThread *gSocketThread;
 | |
| #endif
 | |
| 
 | |
| static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
 | |
| static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
 | |
| static NS_DEFINE_CID(kCookieServiceCID, NS_COOKIESERVICE_CID);
 | |
| static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
 | |
| static NS_DEFINE_CID(kSocketProviderServiceCID, NS_SOCKETPROVIDERSERVICE_CID);
 | |
| 
 | |
| #define UA_PREF_PREFIX          "general.useragent."
 | |
| #define UA_APPNAME              "Mozilla"
 | |
| #define UA_APPVERSION           "5.0"
 | |
| 
 | |
| #define HTTP_PREF_PREFIX        "network.http."
 | |
| #define INTL_ACCEPT_LANGUAGES   "intl.accept_languages"
 | |
| #define INTL_ACCEPT_CHARSET     "intl.charset.default"
 | |
| #define NETWORK_ENABLEIDN       "network.enableIDN"
 | |
| #define BROWSER_PREF_PREFIX     "browser.cache."
 | |
| 
 | |
| #define UA_PREF(_pref) UA_PREF_PREFIX _pref
 | |
| #define HTTP_PREF(_pref) HTTP_PREF_PREFIX _pref
 | |
| #define BROWSER_PREF(_pref) BROWSER_PREF_PREFIX _pref
 | |
| 
 | |
| #define NS_HTTP_PROTOCOL_FLAGS (URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP | URI_LOADABLE_BY_ANYONE)
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| static nsresult
 | |
| NewURI(const nsACString &aSpec,
 | |
|        const char *aCharset,
 | |
|        nsIURI *aBaseURI,
 | |
|        PRInt32 aDefaultPort,
 | |
|        nsIURI **aURI)
 | |
| {
 | |
|     nsStandardURL *url = new nsStandardURL();
 | |
|     if (!url)
 | |
|         return NS_ERROR_OUT_OF_MEMORY;
 | |
|     NS_ADDREF(url);
 | |
| 
 | |
|     nsresult rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY,
 | |
|                             aDefaultPort, aSpec, aCharset, aBaseURI);
 | |
|     if (NS_FAILED(rv)) {
 | |
|         NS_RELEASE(url);
 | |
|         return rv;
 | |
|     }
 | |
| 
 | |
|     *aURI = url; // no QI needed
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // nsHttpHandler <public>
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| nsHttpHandler *gHttpHandler = nsnull;
 | |
| 
 | |
| nsHttpHandler::nsHttpHandler()
 | |
|     : mConnMgr(nsnull)
 | |
|     , mHttpVersion(NS_HTTP_VERSION_1_1)
 | |
|     , mProxyHttpVersion(NS_HTTP_VERSION_1_1)
 | |
|     , mCapabilities(NS_HTTP_ALLOW_KEEPALIVE)
 | |
|     , mProxyCapabilities(NS_HTTP_ALLOW_KEEPALIVE)
 | |
|     , mReferrerLevel(0xff) // by default we always send a referrer
 | |
|     , mIdleTimeout(10)
 | |
|     , mMaxRequestAttempts(10)
 | |
|     , mMaxRequestDelay(10)
 | |
|     , mMaxConnections(24)
 | |
|     , mMaxConnectionsPerServer(8)
 | |
|     , mMaxPersistentConnectionsPerServer(2)
 | |
|     , mMaxPersistentConnectionsPerProxy(4)
 | |
|     , mMaxPipelinedRequests(2)
 | |
|     , mRedirectionLimit(10)
 | |
|     , mPhishyUserPassLength(1)
 | |
|     , mQoSBits(0x00)
 | |
|     , mPipeliningOverSSL(PR_FALSE)
 | |
|     , mLastUniqueID(NowInSeconds())
 | |
|     , mSessionStartTime(0)
 | |
|     , mProduct("Gecko")
 | |
|     , mUserAgentIsDirty(PR_TRUE)
 | |
|     , mUseCache(PR_TRUE)
 | |
|     , mPromptTempRedirect(PR_TRUE)
 | |
|     , mSendSecureXSiteReferrer(PR_TRUE)
 | |
|     , mEnablePersistentHttpsCaching(PR_FALSE)
 | |
| {
 | |
| #if defined(PR_LOGGING)
 | |
|     gHttpLog = PR_NewLogModule("nsHttp");
 | |
| #endif
 | |
| 
 | |
|     LOG(("Creating nsHttpHandler [this=%x].\n", this));
 | |
| 
 | |
|     NS_ASSERTION(!gHttpHandler, "HTTP handler already created!");
 | |
|     gHttpHandler = this;
 | |
| }
 | |
| 
 | |
| nsHttpHandler::~nsHttpHandler()
 | |
| {
 | |
|     // We do not deal with the timer cancellation in the destructor since
 | |
|     // it is taken care of in xpcom shutdown event in the Observe method.
 | |
| 
 | |
|     LOG(("Deleting nsHttpHandler [this=%x]\n", this));
 | |
| 
 | |
|     // make sure the connection manager is shutdown
 | |
|     if (mConnMgr) {
 | |
|         mConnMgr->Shutdown();
 | |
|         NS_RELEASE(mConnMgr);
 | |
|     }
 | |
| 
 | |
|     // Note: don't call NeckoChild::DestroyNeckoChild() here, as it's too late
 | |
|     // and it'll segfault.  NeckoChild will get cleaned up by process exit.
 | |
| 
 | |
|     nsHttp::DestroyAtomTable();
 | |
| 
 | |
|     gHttpHandler = nsnull;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsHttpHandler::Init()
 | |
| {
 | |
|     NS_TIME_FUNCTION;
 | |
| 
 | |
|     nsresult rv;
 | |
| 
 | |
|     LOG(("nsHttpHandler::Init\n"));
 | |
| 
 | |
|     rv = nsHttp::CreateAtomTable();
 | |
|     if (NS_FAILED(rv))
 | |
|         return rv;
 | |
| 
 | |
|     mIOService = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
 | |
|     if (NS_FAILED(rv)) {
 | |
|         NS_WARNING("unable to continue without io service");
 | |
|         return rv;
 | |
|     }
 | |
| 
 | |
| #ifdef MOZ_IPC
 | |
|     if (IsNeckoChild())
 | |
|         NeckoChild::InitNeckoChild();
 | |
| #endif // MOZ_IPC
 | |
| 
 | |
|     InitUserAgentComponents();
 | |
| 
 | |
|     // monitor some preference changes
 | |
|     nsCOMPtr<nsIPrefBranch2> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
 | |
|     if (prefBranch) {
 | |
|         prefBranch->AddObserver(HTTP_PREF_PREFIX, this, PR_TRUE);
 | |
|         prefBranch->AddObserver(UA_PREF_PREFIX, this, PR_TRUE);
 | |
|         prefBranch->AddObserver(INTL_ACCEPT_LANGUAGES, this, PR_TRUE); 
 | |
|         prefBranch->AddObserver(INTL_ACCEPT_CHARSET, this, PR_TRUE);
 | |
|         prefBranch->AddObserver(NETWORK_ENABLEIDN, this, PR_TRUE);
 | |
|         prefBranch->AddObserver(BROWSER_PREF("disk_cache_ssl"), this, PR_TRUE);
 | |
| 
 | |
|         PrefsChanged(prefBranch, nsnull);
 | |
|     }
 | |
| 
 | |
|     mMisc.AssignLiteral("rv:" MOZILLA_VERSION);
 | |
| 
 | |
| #if DEBUG
 | |
|     // dump user agent prefs
 | |
|     LOG(("> app-name = %s\n", mAppName.get()));
 | |
|     LOG(("> app-version = %s\n", mAppVersion.get()));
 | |
|     LOG(("> platform = %s\n", mPlatform.get()));
 | |
|     LOG(("> oscpu = %s\n", mOscpu.get()));
 | |
|     LOG(("> language = %s\n", mLanguage.get()));
 | |
|     LOG(("> misc = %s\n", mMisc.get()));
 | |
|     LOG(("> vendor = %s\n", mVendor.get()));
 | |
|     LOG(("> vendor-sub = %s\n", mVendorSub.get()));
 | |
|     LOG(("> vendor-comment = %s\n", mVendorComment.get()));
 | |
|     LOG(("> extra = %s\n", mExtraUA.get()));
 | |
|     LOG(("> product = %s\n", mProduct.get()));
 | |
|     LOG(("> product-sub = %s\n", mProductSub.get()));
 | |
|     LOG(("> product-comment = %s\n", mProductComment.get()));
 | |
|     LOG(("> user-agent = %s\n", UserAgent().get()));
 | |
| #endif
 | |
| 
 | |
|     mSessionStartTime = NowInSeconds();
 | |
| 
 | |
|     rv = mAuthCache.Init();
 | |
|     if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|     rv = InitConnectionMgr();
 | |
|     if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|     rv = NS_NewThread(getter_AddRefs(mCacheWriteThread));
 | |
|     if (NS_FAILED(rv)) {
 | |
|         mCacheWriteThread = nsnull;
 | |
|         LOG(("Failed creating cache-write thread - writes will be synchronous"));
 | |
|     } else {
 | |
|         LOG(("Created cache-write thread = %p", mCacheWriteThread.get()));
 | |
|     }
 | |
| 
 | |
|     nsCOMPtr<nsIXULAppInfo> appInfo =
 | |
|         do_GetService("@mozilla.org/xre/app-info;1");
 | |
|     if (appInfo)
 | |
|         appInfo->GetPlatformBuildID(mProductSub);
 | |
|     if (mProductSub.Length() > 8)
 | |
|         mProductSub.SetLength(8);
 | |
| 
 | |
|     // Startup the http category
 | |
|     // Bring alive the objects in the http-protocol-startup category
 | |
|     NS_CreateServicesFromCategory(NS_HTTP_STARTUP_CATEGORY,
 | |
|                                   static_cast<nsISupports*>(static_cast<void*>(this)),
 | |
|                                   NS_HTTP_STARTUP_TOPIC);    
 | |
|     
 | |
|     mObserverService = mozilla::services::GetObserverService();
 | |
|     if (mObserverService) {
 | |
|         mObserverService->AddObserver(this, "profile-change-net-teardown", PR_TRUE);
 | |
|         mObserverService->AddObserver(this, "profile-change-net-restore", PR_TRUE);
 | |
|         mObserverService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
 | |
|         mObserverService->AddObserver(this, "net:clear-active-logins", PR_TRUE);
 | |
|         mObserverService->AddObserver(this, "xpcom-shutdown-threads", PR_TRUE);
 | |
|     }
 | |
|  
 | |
|     StartPruneDeadConnectionsTimer();
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsHttpHandler::InitConnectionMgr()
 | |
| {
 | |
|     NS_TIME_FUNCTION;
 | |
| 
 | |
|     nsresult rv;
 | |
| 
 | |
|     if (!mConnMgr) {
 | |
|         mConnMgr = new nsHttpConnectionMgr();
 | |
|         if (!mConnMgr)
 | |
|             return NS_ERROR_OUT_OF_MEMORY;
 | |
|         NS_ADDREF(mConnMgr);
 | |
|     }
 | |
| 
 | |
|     rv = mConnMgr->Init(mMaxConnections,
 | |
|                         mMaxConnectionsPerServer,
 | |
|                         mMaxConnectionsPerServer,
 | |
|                         mMaxPersistentConnectionsPerServer,
 | |
|                         mMaxPersistentConnectionsPerProxy,
 | |
|                         mMaxRequestDelay,
 | |
|                         mMaxPipelinedRequests);
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| void
 | |
| nsHttpHandler::StartPruneDeadConnectionsTimer()
 | |
| {
 | |
|     LOG(("nsHttpHandler::StartPruneDeadConnectionsTimer\n"));
 | |
| 
 | |
|     mTimer = do_CreateInstance("@mozilla.org/timer;1");
 | |
|     NS_ASSERTION(mTimer, "no timer");
 | |
|     // failure to create a timer is not a fatal error, but idle connections
 | |
|     // will not be cleaned up until we try to use them.
 | |
|     if (mTimer)
 | |
|         mTimer->Init(this, 15*1000, // every 15 seconds
 | |
|                      nsITimer::TYPE_REPEATING_SLACK);
 | |
| }
 | |
| 
 | |
| void
 | |
| nsHttpHandler::StopPruneDeadConnectionsTimer()
 | |
| {
 | |
|     LOG(("nsHttpHandler::StopPruneDeadConnectionsTimer\n"));
 | |
| 
 | |
|     if (mTimer) {
 | |
|         mTimer->Cancel();
 | |
|         mTimer = 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request,
 | |
|                                          PRUint8 caps,
 | |
|                                          PRBool useProxy)
 | |
| {
 | |
|     nsresult rv;
 | |
| 
 | |
|     // Add the "User-Agent" header
 | |
|     rv = request->SetHeader(nsHttp::User_Agent, UserAgent());
 | |
|     if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|     // MIME based content negotiation lives!
 | |
|     // Add the "Accept" header
 | |
|     rv = request->SetHeader(nsHttp::Accept, mAccept);
 | |
|     if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|     // Add the "Accept-Language" header
 | |
|     if (!mAcceptLanguages.IsEmpty()) {
 | |
|         // Add the "Accept-Language" header
 | |
|         rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages);
 | |
|         if (NS_FAILED(rv)) return rv;
 | |
|     }
 | |
| 
 | |
|     // Add the "Accept-Encoding" header
 | |
|     rv = request->SetHeader(nsHttp::Accept_Encoding, mAcceptEncodings);
 | |
|     if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|     // Add the "Accept-Charset" header
 | |
|     rv = request->SetHeader(nsHttp::Accept_Charset, mAcceptCharsets);
 | |
|     if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|     // RFC2616 section 19.6.2 states that the "Connection: keep-alive"
 | |
|     // and "Keep-alive" request headers should not be sent by HTTP/1.1
 | |
|     // user-agents.  Otherwise, problems with proxy servers (especially
 | |
|     // transparent proxies) can result.
 | |
|     //
 | |
|     // However, we need to send something so that we can use keepalive
 | |
|     // with HTTP/1.0 servers/proxies. We use "Proxy-Connection:" when 
 | |
|     // we're talking to an http proxy, and "Connection:" otherwise
 | |
|     
 | |
|     NS_NAMED_LITERAL_CSTRING(close, "close");
 | |
|     NS_NAMED_LITERAL_CSTRING(keepAlive, "keep-alive");
 | |
| 
 | |
|     const nsACString *connectionType = &close;
 | |
|     if (caps & NS_HTTP_ALLOW_KEEPALIVE) {
 | |
|         rv = request->SetHeader(nsHttp::Keep_Alive, nsPrintfCString("%u", mIdleTimeout));
 | |
|         if (NS_FAILED(rv)) return rv;
 | |
|         connectionType = &keepAlive;
 | |
|     } else if (useProxy) {
 | |
|         // Bug 92006
 | |
|         request->SetHeader(nsHttp::Connection, close);
 | |
|     }
 | |
| 
 | |
|     const nsHttpAtom &header = useProxy ? nsHttp::Proxy_Connection
 | |
|                                         : nsHttp::Connection;
 | |
|     return request->SetHeader(header, *connectionType);
 | |
| }
 | |
| 
 | |
| PRBool
 | |
| nsHttpHandler::IsAcceptableEncoding(const char *enc)
 | |
| {
 | |
|     if (!enc)
 | |
|         return PR_FALSE;
 | |
| 
 | |
|     // HTTP 1.1 allows servers to send x-gzip and x-compress instead
 | |
|     // of gzip and compress, for example.  So, we'll always strip off
 | |
|     // an "x-" prefix before matching the encoding to one we claim
 | |
|     // to accept.
 | |
|     if (!PL_strncasecmp(enc, "x-", 2))
 | |
|         enc += 2;
 | |
|     
 | |
|     return nsHttp::FindToken(mAcceptEncodings.get(), enc, HTTP_LWS ",") != nsnull;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsHttpHandler::GetCacheSession(nsCacheStoragePolicy storagePolicy,
 | |
|                                nsICacheSession **result)
 | |
| {
 | |
|     nsresult rv;
 | |
| 
 | |
|     // Skip cache if disabled in preferences
 | |
|     if (!mUseCache)
 | |
|         return NS_ERROR_NOT_AVAILABLE;
 | |
| 
 | |
|     // We want to get the pointer to the cache service each time we're called,
 | |
|     // because it's possible for some add-ons (such as Google Gears) to swap
 | |
|     // in new cache services on the fly, and we want to pick them up as
 | |
|     // appropriate.
 | |
|     nsCOMPtr<nsICacheService> serv = do_GetService(NS_CACHESERVICE_CONTRACTID,
 | |
|                                                    &rv);
 | |
|     if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|     const char *sessionName = "HTTP";
 | |
|     switch (storagePolicy) {
 | |
|     case nsICache::STORE_IN_MEMORY:
 | |
|         sessionName = "HTTP-memory-only";
 | |
|         break;
 | |
|     case nsICache::STORE_OFFLINE:
 | |
|         sessionName = "HTTP-offline";
 | |
|         break;
 | |
|     default:
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     nsCOMPtr<nsICacheSession> cacheSession;
 | |
|     rv = serv->CreateSession(sessionName,
 | |
|                              storagePolicy,
 | |
|                              nsICache::STREAM_BASED,
 | |
|                              getter_AddRefs(cacheSession));
 | |
|     if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|     rv = cacheSession->SetDoomEntriesIfExpired(PR_FALSE);
 | |
|     if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|     NS_ADDREF(*result = cacheSession);
 | |
| 
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsHttpHandler::GetStreamConverterService(nsIStreamConverterService **result)
 | |
| {
 | |
|     if (!mStreamConvSvc) {
 | |
|         nsresult rv;
 | |
|         mStreamConvSvc = do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
 | |
|         if (NS_FAILED(rv)) return rv;
 | |
|     }
 | |
|     *result = mStreamConvSvc;
 | |
|     NS_ADDREF(*result);
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| nsICookieService *
 | |
| nsHttpHandler::GetCookieService()
 | |
| {
 | |
|     if (!mCookieService)
 | |
|         mCookieService = do_GetService(NS_COOKIESERVICE_CONTRACTID);
 | |
|     return mCookieService;
 | |
| }
 | |
| 
 | |
| nsresult 
 | |
| nsHttpHandler::GetIOService(nsIIOService** result)
 | |
| {
 | |
|     NS_ADDREF(*result = mIOService);
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| nsHttpHandler::NotifyObservers(nsIHttpChannel *chan, const char *event)
 | |
| {
 | |
|     LOG(("nsHttpHandler::NotifyObservers [chan=%x event=\"%s\"]\n", chan, event));
 | |
|     if (mObserverService)
 | |
|         mObserverService->NotifyObservers(chan, event, nsnull);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsHttpHandler::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
 | |
|                                  PRUint32 flags)
 | |
| {
 | |
|     // TODO E10S This helper has to be initialized on the other process
 | |
|     nsRefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
 | |
|         new nsAsyncRedirectVerifyHelper();
 | |
| 
 | |
|     return redirectCallbackHelper->Init(oldChan, newChan, flags);
 | |
| }
 | |
| 
 | |
| /* static */ nsresult
 | |
| nsHttpHandler::GenerateHostPort(const nsCString& host, PRInt32 port,
 | |
|                                 nsCString& hostLine)
 | |
| {
 | |
|     if (strchr(host.get(), ':')) {
 | |
|         // host is an IPv6 address literal and must be encapsulated in []'s
 | |
|         hostLine.Assign('[');
 | |
|         // scope id is not needed for Host header.
 | |
|         int scopeIdPos = host.FindChar('%');
 | |
|         if (scopeIdPos == kNotFound)
 | |
|             hostLine.Append(host);
 | |
|         else if (scopeIdPos > 0)
 | |
|             hostLine.Append(Substring(host, 0, scopeIdPos));
 | |
|         else
 | |
|           return NS_ERROR_MALFORMED_URI;
 | |
|         hostLine.Append(']');
 | |
|     }
 | |
|     else
 | |
|         hostLine.Assign(host);
 | |
|     if (port != -1) {
 | |
|         hostLine.Append(':');
 | |
|         hostLine.AppendInt(port);
 | |
|     }
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // nsHttpHandler <private>
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| const nsAFlatCString &
 | |
| nsHttpHandler::UserAgent()
 | |
| {
 | |
|     if (mUserAgentOverride) {
 | |
|         LOG(("using general.useragent.override : %s\n", mUserAgentOverride.get()));
 | |
|         return mUserAgentOverride;
 | |
|     }
 | |
| 
 | |
|     if (mUserAgentIsDirty) {
 | |
|         BuildUserAgent();
 | |
|         mUserAgentIsDirty = PR_FALSE;
 | |
|     }
 | |
| 
 | |
|     return mUserAgent;
 | |
| }
 | |
| 
 | |
| void
 | |
| nsHttpHandler::BuildUserAgent()
 | |
| {
 | |
|     LOG(("nsHttpHandler::BuildUserAgent\n"));
 | |
| 
 | |
|     NS_ASSERTION(!mAppName.IsEmpty() &&
 | |
|                  !mAppVersion.IsEmpty() &&
 | |
|                  !mPlatform.IsEmpty() &&
 | |
|                  !mOscpu.IsEmpty(),
 | |
|                  "HTTP cannot send practical requests without this much");
 | |
| 
 | |
|     // preallocate to worst-case size, which should always be better
 | |
|     // than if we didn't preallocate at all.
 | |
|     mUserAgent.SetCapacity(mAppName.Length() + 
 | |
|                            mAppVersion.Length() + 
 | |
|                            mPlatform.Length() + 
 | |
|                            mOscpu.Length() +
 | |
|                            mMisc.Length() +
 | |
|                            mProduct.Length() +
 | |
|                            mProductSub.Length() +
 | |
|                            mProductComment.Length() +
 | |
|                            mVendor.Length() +
 | |
|                            mVendorSub.Length() +
 | |
|                            mVendorComment.Length() +
 | |
|                            mExtraUA.Length() +
 | |
|                            22);
 | |
| 
 | |
|     // Application portion
 | |
|     mUserAgent.Assign(mAppName);
 | |
|     mUserAgent += '/';
 | |
|     mUserAgent += mAppVersion;
 | |
|     mUserAgent += ' ';
 | |
| 
 | |
|     // Application comment
 | |
|     mUserAgent += '(';
 | |
|     mUserAgent += mPlatform;
 | |
|     mUserAgent.AppendLiteral("; ");
 | |
|     mUserAgent += mOscpu;
 | |
|     if (!mMisc.IsEmpty()) {
 | |
|         mUserAgent.AppendLiteral("; ");
 | |
|         mUserAgent += mMisc;
 | |
|     }
 | |
|     mUserAgent += ')';
 | |
| 
 | |
|     // Product portion
 | |
|     if (!mProduct.IsEmpty()) {
 | |
|         mUserAgent += ' ';
 | |
|         mUserAgent += mProduct;
 | |
|         if (!mProductSub.IsEmpty()) {
 | |
|             mUserAgent += '/';
 | |
|             mUserAgent += mProductSub;
 | |
|         }
 | |
|         if (!mProductComment.IsEmpty()) {
 | |
|             mUserAgent.AppendLiteral(" (");
 | |
|             mUserAgent += mProductComment;
 | |
|             mUserAgent += ')';
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Vendor portion
 | |
|     if (!mVendor.IsEmpty()) {
 | |
|         mUserAgent += ' ';
 | |
|         mUserAgent += mVendor;
 | |
|         if (!mVendorSub.IsEmpty()) {
 | |
|             mUserAgent += '/';
 | |
|             mUserAgent += mVendorSub;
 | |
|         }
 | |
|         if (!mVendorComment.IsEmpty()) {
 | |
|             mUserAgent.AppendLiteral(" (");
 | |
|             mUserAgent += mVendorComment;
 | |
|             mUserAgent += ')';
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (!mExtraUA.IsEmpty())
 | |
|         mUserAgent += mExtraUA;
 | |
| }
 | |
| 
 | |
| #ifdef XP_WIN
 | |
| typedef BOOL (WINAPI *IsWow64ProcessP) (HANDLE, PBOOL);
 | |
| 
 | |
| #define WNT_BASE "Windows NT %ld.%ld"
 | |
| #define W64_PREFIX "; Win64"
 | |
| #endif
 | |
| 
 | |
| void
 | |
| nsHttpHandler::InitUserAgentComponents()
 | |
| {
 | |
| 
 | |
|       // Gather platform.
 | |
|     mPlatform.AssignLiteral(
 | |
| #if defined(ANDROID)
 | |
|     "Android"
 | |
| #elif defined(XP_OS2)
 | |
|     "OS/2"
 | |
| #elif defined(XP_WIN)
 | |
|     "Windows"
 | |
| #elif defined(XP_MACOSX)
 | |
|     "Macintosh"
 | |
| #elif defined(XP_BEOS)
 | |
|     "BeOS"
 | |
| #elif defined(MOZ_X11)
 | |
|     "X11"
 | |
| #else
 | |
|     "?"
 | |
| #endif
 | |
|     );
 | |
| 
 | |
|     // Gather OS/CPU.
 | |
| #if defined(XP_OS2)
 | |
|     ULONG os2ver = 0;
 | |
|     DosQuerySysInfo(QSV_VERSION_MINOR, QSV_VERSION_MINOR,
 | |
|                     &os2ver, sizeof(os2ver));
 | |
|     if (os2ver == 11)
 | |
|         mOscpu.AssignLiteral("2.11");
 | |
|     else if (os2ver == 30)
 | |
|         mOscpu.AssignLiteral("Warp 3");
 | |
|     else if (os2ver == 40)
 | |
|         mOscpu.AssignLiteral("Warp 4");
 | |
|     else if (os2ver == 45)
 | |
|         mOscpu.AssignLiteral("Warp 4.5");
 | |
| 
 | |
| #elif defined(WINCE) || defined(XP_WIN)
 | |
|     OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
 | |
|     if (GetVersionEx(&info)) {
 | |
|         const char *format;
 | |
| #ifdef WINCE
 | |
|         format = "WindowsCE %ld.%ld";
 | |
| #elif defined _M_IA64
 | |
|         format = WNT_BASE W64_PREFIX "; IA64";
 | |
| #elif defined _M_X64 || defined _M_AMD64
 | |
|         format = WNT_BASE W64_PREFIX "; x64";
 | |
| #else
 | |
|         BOOL isWow64 = FALSE;
 | |
|         IsWow64ProcessP fnIsWow64Process = (IsWow64ProcessP)
 | |
|           GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process");
 | |
|         if (fnIsWow64Process &&
 | |
|             !fnIsWow64Process(GetCurrentProcess(), &isWow64)) {
 | |
|             isWow64 = FALSE;
 | |
|         }
 | |
|         format = isWow64
 | |
|           ? WNT_BASE "; WOW64"
 | |
|           : WNT_BASE;
 | |
| #endif
 | |
|         char *buf = PR_smprintf(format,
 | |
|                                 info.dwMajorVersion,
 | |
|                                 info.dwMinorVersion);
 | |
|         if (buf) {
 | |
|             mOscpu = buf;
 | |
|             PR_smprintf_free(buf);
 | |
|         }
 | |
|     }
 | |
| #elif defined (XP_MACOSX)
 | |
| #if defined(__ppc__)
 | |
|     mOscpu.AssignLiteral("PPC Mac OS X");
 | |
| #elif defined(__i386__) || defined(__x86_64__)
 | |
|     mOscpu.AssignLiteral("Intel Mac OS X");
 | |
| #endif
 | |
|     SInt32 majorVersion, minorVersion;
 | |
|     if ((::Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
 | |
|         (::Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
 | |
|         mOscpu += nsPrintfCString(" %d.%d", majorVersion, minorVersion);
 | |
|     }
 | |
| #elif defined (XP_UNIX) || defined (XP_BEOS)
 | |
|     struct utsname name;
 | |
|     
 | |
|     int ret = uname(&name);
 | |
|     if (ret >= 0) {
 | |
|         nsCAutoString buf;
 | |
|         buf =  (char*)name.sysname;
 | |
| 
 | |
|         if (strcmp(name.machine, "x86_64") == 0 &&
 | |
|             sizeof(void *) == sizeof(PRInt32)) {
 | |
|             // We're running 32-bit code on x86_64. Make this browser
 | |
|             // look like it's running on i686 hardware, but append "
 | |
|             // (x86_64)" to the end of the oscpu identifier to be able
 | |
|             // to differentiate this from someone running 64-bit code
 | |
|             // on x86_64..
 | |
| 
 | |
|             buf += " i686 (x86_64)";
 | |
|         } else {
 | |
|             buf += ' ';
 | |
| 
 | |
| #ifdef AIX
 | |
|             // AIX uname returns machine specific info in the uname.machine
 | |
|             // field and does not return the cpu type like other platforms.
 | |
|             // We use the AIX version and release numbers instead.
 | |
|             buf += (char*)name.version;
 | |
|             buf += '.';
 | |
|             buf += (char*)name.release;
 | |
| #else
 | |
|             buf += (char*)name.machine;
 | |
| #endif
 | |
|         }
 | |
| 
 | |
|         mOscpu.Assign(buf);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     mUserAgentIsDirty = PR_TRUE;
 | |
| }
 | |
| 
 | |
| static int StringCompare(const void* s1, const void* s2, void*)
 | |
| {
 | |
|     return nsCRT::strcmp(*static_cast<const char *const *>(s1),
 | |
|                          *static_cast<const char *const *>(s2));
 | |
| }
 | |
| 
 | |
| void
 | |
| nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
 | |
| {
 | |
|     nsresult rv = NS_OK;
 | |
|     PRInt32 val;
 | |
| 
 | |
|     LOG(("nsHttpHandler::PrefsChanged [pref=%s]\n", pref));
 | |
| 
 | |
| #define PREF_CHANGED(p) ((pref == nsnull) || !PL_strcmp(pref, p))
 | |
| #define MULTI_PREF_CHANGED(p) \
 | |
|   ((pref == nsnull) || !PL_strncmp(pref, p, sizeof(p) - 1))
 | |
| 
 | |
|     //
 | |
|     // UA components
 | |
|     //
 | |
| 
 | |
|     // Gather application values.
 | |
|     if (PREF_CHANGED(UA_PREF("appName"))) {
 | |
|         prefs->GetCharPref(UA_PREF("appName"),
 | |
|             getter_Copies(mAppName));
 | |
|         if (mAppName.IsEmpty())
 | |
|             mAppName.AssignLiteral(UA_APPNAME);
 | |
|         mUserAgentIsDirty = PR_TRUE;
 | |
|     }
 | |
|     if (PREF_CHANGED(UA_PREF("appVersion"))) {
 | |
|         prefs->GetCharPref(UA_PREF("appVersion"),
 | |
|             getter_Copies(mAppVersion));
 | |
|         if (mAppVersion.IsEmpty())
 | |
|             mAppVersion.AssignLiteral(UA_APPVERSION);
 | |
|         mUserAgentIsDirty = PR_TRUE;
 | |
|     }
 | |
| 
 | |
|     // Gather vendor values.
 | |
|     if (PREF_CHANGED(UA_PREF("vendor"))) {
 | |
|         prefs->GetCharPref(UA_PREF("vendor"),
 | |
|             getter_Copies(mVendor));
 | |
|         mUserAgentIsDirty = PR_TRUE;
 | |
|     }
 | |
|     if (PREF_CHANGED(UA_PREF("vendorSub"))) {
 | |
|         prefs->GetCharPref(UA_PREF("vendorSub"),
 | |
|             getter_Copies(mVendorSub));
 | |
|         mUserAgentIsDirty = PR_TRUE;
 | |
|     }
 | |
|     if (PREF_CHANGED(UA_PREF("vendorComment"))) {
 | |
|         prefs->GetCharPref(UA_PREF("vendorComment"),
 | |
|             getter_Copies(mVendorComment));
 | |
|         mUserAgentIsDirty = PR_TRUE;
 | |
|     }
 | |
| 
 | |
|     if (MULTI_PREF_CHANGED(UA_PREF("extra."))) {
 | |
|         mExtraUA.Truncate();
 | |
| 
 | |
|         // Unfortunately, we can't do this using the pref branch.
 | |
|         nsCOMPtr<nsIPrefService> service =
 | |
|             do_GetService(NS_PREFSERVICE_CONTRACTID);
 | |
|         nsCOMPtr<nsIPrefBranch> branch;
 | |
|         service->GetBranch(UA_PREF("extra."), getter_AddRefs(branch));
 | |
|         if (branch) {
 | |
|             PRUint32 extraCount;
 | |
|             char **extraItems;
 | |
|             rv = branch->GetChildList("", &extraCount, &extraItems);
 | |
|             if (NS_SUCCEEDED(rv) && extraItems) {
 | |
|                 NS_QuickSort(extraItems, extraCount, sizeof(extraItems[0]),
 | |
|                              StringCompare, nsnull);
 | |
|                 for (char **item = extraItems,
 | |
|                       **item_end = extraItems + extraCount;
 | |
|                      item < item_end; ++item) {
 | |
|                     nsXPIDLCString valStr;
 | |
|                     branch->GetCharPref(*item, getter_Copies(valStr));
 | |
|                     if (!valStr.IsEmpty())
 | |
|                         mExtraUA += NS_LITERAL_CSTRING(" ") + valStr;
 | |
|                 }
 | |
|                 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(extraCount, extraItems);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         mUserAgentIsDirty = PR_TRUE;
 | |
|     }
 | |
| 
 | |
|     // Gather product values.
 | |
|     if (PREF_CHANGED(UA_PREF("productComment"))) {
 | |
|         prefs->GetCharPref(UA_PREF("productComment"),
 | |
|             getter_Copies(mProductComment));
 | |
|         mUserAgentIsDirty = PR_TRUE;
 | |
|     }
 | |
| 
 | |
|     // Gather locale.
 | |
|     if (PREF_CHANGED(UA_PREF("locale"))) {
 | |
|         nsCOMPtr<nsIPrefLocalizedString> pls;
 | |
|         prefs->GetComplexValue(UA_PREF("locale"),
 | |
|                                NS_GET_IID(nsIPrefLocalizedString),
 | |
|                                getter_AddRefs(pls));
 | |
|         if (pls) {
 | |
|             nsXPIDLString uval;
 | |
|             pls->ToString(getter_Copies(uval));
 | |
|             if (uval)
 | |
|                 CopyUTF16toUTF8(uval, mLanguage);
 | |
|         }
 | |
|         else {
 | |
|             nsXPIDLCString cval;
 | |
|             rv = prefs->GetCharPref(UA_PREF("locale"), getter_Copies(cval));
 | |
|             if (cval)
 | |
|                 mLanguage.Assign(cval);
 | |
|         }
 | |
| 
 | |
|         mUserAgentIsDirty = PR_TRUE;
 | |
|     }
 | |
| 
 | |
|     // general.useragent.override
 | |
|     if (PREF_CHANGED(UA_PREF("override"))) {
 | |
|         prefs->GetCharPref(UA_PREF("override"),
 | |
|                             getter_Copies(mUserAgentOverride));
 | |
|         mUserAgentIsDirty = PR_TRUE;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // HTTP options
 | |
|     //
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("keep-alive.timeout"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("keep-alive.timeout"), &val);
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             mIdleTimeout = (PRUint16) NS_CLAMP(val, 1, 0xffff);
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("request.max-attempts"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("request.max-attempts"), &val);
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             mMaxRequestAttempts = (PRUint16) NS_CLAMP(val, 1, 0xffff);
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("request.max-start-delay"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("request.max-start-delay"), &val);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             mMaxRequestDelay = (PRUint16) NS_CLAMP(val, 0, 0xffff);
 | |
|             if (mConnMgr)
 | |
|                 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_REQUEST_DELAY,
 | |
|                                       mMaxRequestDelay);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("max-connections"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("max-connections"), &val);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             mMaxConnections = (PRUint16) NS_CLAMP(val, 1, 0xffff);
 | |
|             if (mConnMgr)
 | |
|                 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS,
 | |
|                                       mMaxConnections);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("max-connections-per-server"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("max-connections-per-server"), &val);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             mMaxConnectionsPerServer = (PRUint8) NS_CLAMP(val, 1, 0xff);
 | |
|             if (mConnMgr) {
 | |
|                 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS_PER_HOST,
 | |
|                                       mMaxConnectionsPerServer);
 | |
|                 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS_PER_PROXY,
 | |
|                                       mMaxConnectionsPerServer);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-server"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("max-persistent-connections-per-server"), &val);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             mMaxPersistentConnectionsPerServer = (PRUint8) NS_CLAMP(val, 1, 0xff);
 | |
|             if (mConnMgr)
 | |
|                 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_HOST,
 | |
|                                       mMaxPersistentConnectionsPerServer);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-proxy"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("max-persistent-connections-per-proxy"), &val);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             mMaxPersistentConnectionsPerProxy = (PRUint8) NS_CLAMP(val, 1, 0xff);
 | |
|             if (mConnMgr)
 | |
|                 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
 | |
|                                       mMaxPersistentConnectionsPerProxy);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("sendRefererHeader"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("sendRefererHeader"), &val);
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             mReferrerLevel = (PRUint8) NS_CLAMP(val, 0, 0xff);
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("redirection-limit"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("redirection-limit"), &val);
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             mRedirectionLimit = (PRUint8) NS_CLAMP(val, 0, 0xff);
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("version"))) {
 | |
|         nsXPIDLCString httpVersion;
 | |
|         prefs->GetCharPref(HTTP_PREF("version"), getter_Copies(httpVersion));
 | |
|         if (httpVersion) {
 | |
|             if (!PL_strcmp(httpVersion, "1.1"))
 | |
|                 mHttpVersion = NS_HTTP_VERSION_1_1;
 | |
|             else if (!PL_strcmp(httpVersion, "0.9"))
 | |
|                 mHttpVersion = NS_HTTP_VERSION_0_9;
 | |
|             else
 | |
|                 mHttpVersion = NS_HTTP_VERSION_1_0;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("proxy.version"))) {
 | |
|         nsXPIDLCString httpVersion;
 | |
|         prefs->GetCharPref(HTTP_PREF("proxy.version"), getter_Copies(httpVersion));
 | |
|         if (httpVersion) {
 | |
|             if (!PL_strcmp(httpVersion, "1.1"))
 | |
|                 mProxyHttpVersion = NS_HTTP_VERSION_1_1;
 | |
|             else
 | |
|                 mProxyHttpVersion = NS_HTTP_VERSION_1_0;
 | |
|             // it does not make sense to issue a HTTP/0.9 request to a proxy server
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     PRBool cVar = PR_FALSE;
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("keep-alive"))) {
 | |
|         rv = prefs->GetBoolPref(HTTP_PREF("keep-alive"), &cVar);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             if (cVar)
 | |
|                 mCapabilities |= NS_HTTP_ALLOW_KEEPALIVE;
 | |
|             else
 | |
|                 mCapabilities &= ~NS_HTTP_ALLOW_KEEPALIVE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("proxy.keep-alive"))) {
 | |
|         rv = prefs->GetBoolPref(HTTP_PREF("proxy.keep-alive"), &cVar);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             if (cVar)
 | |
|                 mProxyCapabilities |= NS_HTTP_ALLOW_KEEPALIVE;
 | |
|             else
 | |
|                 mProxyCapabilities &= ~NS_HTTP_ALLOW_KEEPALIVE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("pipelining"))) {
 | |
|         rv = prefs->GetBoolPref(HTTP_PREF("pipelining"), &cVar);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             if (cVar)
 | |
|                 mCapabilities |=  NS_HTTP_ALLOW_PIPELINING;
 | |
|             else
 | |
|                 mCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("pipelining.maxrequests"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("pipelining.maxrequests"), &val);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             mMaxPipelinedRequests = NS_CLAMP(val, 1, NS_HTTP_MAX_PIPELINED_REQUESTS);
 | |
|             if (mConnMgr)
 | |
|                 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PIPELINED_REQUESTS,
 | |
|                                       mMaxPipelinedRequests);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("pipelining.ssl"))) {
 | |
|         rv = prefs->GetBoolPref(HTTP_PREF("pipelining.ssl"), &cVar);
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             mPipeliningOverSSL = cVar;
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("proxy.pipelining"))) {
 | |
|         rv = prefs->GetBoolPref(HTTP_PREF("proxy.pipelining"), &cVar);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             if (cVar)
 | |
|                 mProxyCapabilities |=  NS_HTTP_ALLOW_PIPELINING;
 | |
|             else
 | |
|                 mProxyCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("qos"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("qos"), &val);
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             mQoSBits = (PRUint8) NS_CLAMP(val, 0, 0xff);
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("sendSecureXSiteReferrer"))) {
 | |
|         rv = prefs->GetBoolPref(HTTP_PREF("sendSecureXSiteReferrer"), &cVar);
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             mSendSecureXSiteReferrer = cVar;
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("accept.default"))) {
 | |
|         nsXPIDLCString accept;
 | |
|         rv = prefs->GetCharPref(HTTP_PREF("accept.default"),
 | |
|                                   getter_Copies(accept));
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             SetAccept(accept);
 | |
|     }
 | |
|     
 | |
|     if (PREF_CHANGED(HTTP_PREF("accept-encoding"))) {
 | |
|         nsXPIDLCString acceptEncodings;
 | |
|         rv = prefs->GetCharPref(HTTP_PREF("accept-encoding"),
 | |
|                                   getter_Copies(acceptEncodings));
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             SetAcceptEncodings(acceptEncodings);
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("use-cache"))) {
 | |
|         rv = prefs->GetBoolPref(HTTP_PREF("use-cache"), &cVar);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             mUseCache = cVar;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("default-socket-type"))) {
 | |
|         nsXPIDLCString sval;
 | |
|         rv = prefs->GetCharPref(HTTP_PREF("default-socket-type"),
 | |
|                                 getter_Copies(sval));
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             if (sval.IsEmpty())
 | |
|                 mDefaultSocketType.Adopt(0);
 | |
|             else {
 | |
|                 // verify that this socket type is actually valid
 | |
|                 nsCOMPtr<nsISocketProviderService> sps(
 | |
|                         do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID));
 | |
|                 if (sps) {
 | |
|                     nsCOMPtr<nsISocketProvider> sp;
 | |
|                     rv = sps->GetSocketProvider(sval, getter_AddRefs(sp));
 | |
|                     if (NS_SUCCEEDED(rv)) {
 | |
|                         // OK, this looks like a valid socket provider.
 | |
|                         mDefaultSocketType.Assign(sval);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("prompt-temp-redirect"))) {
 | |
|         rv = prefs->GetBoolPref(HTTP_PREF("prompt-temp-redirect"), &cVar);
 | |
|         if (NS_SUCCEEDED(rv)) {
 | |
|             mPromptTempRedirect = cVar;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // enable Persistent caching for HTTPS - bug#205921    
 | |
|     if (PREF_CHANGED(BROWSER_PREF("disk_cache_ssl"))) {
 | |
|         cVar = PR_FALSE;
 | |
|         rv = prefs->GetBoolPref(BROWSER_PREF("disk_cache_ssl"), &cVar);
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             mEnablePersistentHttpsCaching = cVar;
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(HTTP_PREF("phishy-userpass-length"))) {
 | |
|         rv = prefs->GetIntPref(HTTP_PREF("phishy-userpass-length"), &val);
 | |
|         if (NS_SUCCEEDED(rv))
 | |
|             mPhishyUserPassLength = (PRUint8) NS_CLAMP(val, 0, 0xff);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // INTL options
 | |
|     //
 | |
| 
 | |
|     if (PREF_CHANGED(INTL_ACCEPT_LANGUAGES)) {
 | |
|         nsCOMPtr<nsIPrefLocalizedString> pls;
 | |
|         prefs->GetComplexValue(INTL_ACCEPT_LANGUAGES,
 | |
|                                 NS_GET_IID(nsIPrefLocalizedString),
 | |
|                                 getter_AddRefs(pls));
 | |
|         if (pls) {
 | |
|             nsXPIDLString uval;
 | |
|             pls->ToString(getter_Copies(uval));
 | |
|             if (uval)
 | |
|                 SetAcceptLanguages(NS_ConvertUTF16toUTF8(uval).get());
 | |
|         } 
 | |
|     }
 | |
| 
 | |
|     if (PREF_CHANGED(INTL_ACCEPT_CHARSET)) {
 | |
|         nsCOMPtr<nsIPrefLocalizedString> pls;
 | |
|         prefs->GetComplexValue(INTL_ACCEPT_CHARSET,
 | |
|                                 NS_GET_IID(nsIPrefLocalizedString),
 | |
|                                 getter_AddRefs(pls));
 | |
|         if (pls) {
 | |
|             nsXPIDLString uval;
 | |
|             pls->ToString(getter_Copies(uval));
 | |
|             if (uval)
 | |
|                 SetAcceptCharsets(NS_ConvertUTF16toUTF8(uval).get());
 | |
|         } 
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // IDN options
 | |
|     //
 | |
| 
 | |
|     if (PREF_CHANGED(NETWORK_ENABLEIDN)) {
 | |
|         PRBool enableIDN = PR_FALSE;
 | |
|         prefs->GetBoolPref(NETWORK_ENABLEIDN, &enableIDN);
 | |
|         // No locking is required here since this method runs in the main
 | |
|         // UI thread, and so do all the methods in nsHttpChannel.cpp
 | |
|         // (mIDNConverter is used by nsHttpChannel)
 | |
|         if (enableIDN && !mIDNConverter) {
 | |
|             mIDNConverter = do_GetService(NS_IDNSERVICE_CONTRACTID);
 | |
|             NS_ASSERTION(mIDNConverter, "idnSDK not installed");
 | |
|         }
 | |
|         else if (!enableIDN && mIDNConverter)
 | |
|             mIDNConverter = nsnull;
 | |
|     }
 | |
| 
 | |
| #undef PREF_CHANGED
 | |
| #undef MULTI_PREF_CHANGED
 | |
| }
 | |
| 
 | |
| /**
 | |
|  *  Allocates a C string into that contains a ISO 639 language list
 | |
|  *  notated with HTTP "q" values for output with a HTTP Accept-Language
 | |
|  *  header. Previous q values will be stripped because the order of
 | |
|  *  the langs imply the q value. The q values are calculated by dividing
 | |
|  *  1.0 amongst the number of languages present.
 | |
|  *
 | |
|  *  Ex: passing: "en, ja"
 | |
|  *      returns: "en,ja;q=0.5"
 | |
|  *
 | |
|  *      passing: "en, ja, fr_CA"
 | |
|  *      returns: "en,ja;q=0.7,fr_CA;q=0.3"
 | |
|  */
 | |
| static nsresult
 | |
| PrepareAcceptLanguages(const char *i_AcceptLanguages, nsACString &o_AcceptLanguages)
 | |
| {
 | |
|     if (!i_AcceptLanguages)
 | |
|         return NS_OK;
 | |
| 
 | |
|     PRUint32 n, size, wrote;
 | |
|     double q, dec;
 | |
|     char *p, *p2, *token, *q_Accept, *o_Accept;
 | |
|     const char *comma;
 | |
|     PRInt32 available;
 | |
| 
 | |
|     o_Accept = nsCRT::strdup(i_AcceptLanguages);
 | |
|     if (!o_Accept)
 | |
|         return NS_ERROR_OUT_OF_MEMORY;
 | |
|     for (p = o_Accept, n = size = 0; '\0' != *p; p++) {
 | |
|         if (*p == ',') n++;
 | |
|             size++;
 | |
|     }
 | |
| 
 | |
|     available = size + ++n * 11 + 1;
 | |
|     q_Accept = new char[available];
 | |
|     if (!q_Accept) {
 | |
|         nsCRT::free(o_Accept);
 | |
|         return NS_ERROR_OUT_OF_MEMORY;
 | |
|     }
 | |
|     *q_Accept = '\0';
 | |
|     q = 1.0;
 | |
|     dec = q / (double) n;
 | |
|     n = 0;
 | |
|     p2 = q_Accept;
 | |
|     for (token = nsCRT::strtok(o_Accept, ",", &p);
 | |
|          token != (char *) 0;
 | |
|          token = nsCRT::strtok(p, ",", &p))
 | |
|     {
 | |
|         token = net_FindCharNotInSet(token, HTTP_LWS);
 | |
|         char* trim;
 | |
|         trim = net_FindCharInSet(token, ";" HTTP_LWS);
 | |
|         if (trim != (char*)0)  // remove "; q=..." if present
 | |
|             *trim = '\0';
 | |
| 
 | |
|         if (*token != '\0') {
 | |
|             comma = n++ != 0 ? "," : ""; // delimiter if not first item
 | |
|             PRUint32 u = QVAL_TO_UINT(q);
 | |
|             if (u < 10)
 | |
|                 wrote = PR_snprintf(p2, available, "%s%s;q=0.%u", comma, token, u);
 | |
|             else
 | |
|                 wrote = PR_snprintf(p2, available, "%s%s", comma, token);
 | |
|             q -= dec;
 | |
|             p2 += wrote;
 | |
|             available -= wrote;
 | |
|             NS_ASSERTION(available > 0, "allocated string not long enough");
 | |
|         }
 | |
|     }
 | |
|     nsCRT::free(o_Accept);
 | |
| 
 | |
|     o_AcceptLanguages.Assign((const char *) q_Accept);
 | |
|     delete [] q_Accept;
 | |
| 
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsHttpHandler::SetAcceptLanguages(const char *aAcceptLanguages) 
 | |
| {
 | |
|     nsCAutoString buf;
 | |
|     nsresult rv = PrepareAcceptLanguages(aAcceptLanguages, buf);
 | |
|     if (NS_SUCCEEDED(rv))
 | |
|         mAcceptLanguages.Assign(buf);
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  *  Allocates a C string into that contains a character set/encoding list
 | |
|  *  notated with HTTP "q" values for output with a HTTP Accept-Charset
 | |
|  *  header. If the UTF-8 character set is not present, it will be added.
 | |
|  *  If a wildcard catch-all is not present, it will be added. If more than
 | |
|  *  one charset is set (as of 2001-02-07, only one is used), they will be
 | |
|  *  comma delimited and with q values set for each charset in decending order.
 | |
|  *
 | |
|  *  Ex: passing: "euc-jp"
 | |
|  *      returns: "euc-jp,utf-8;q=0.6,*;q=0.6"
 | |
|  *
 | |
|  *      passing: "UTF-8"
 | |
|  *      returns: "UTF-8, *"
 | |
|  */
 | |
| static nsresult
 | |
| PrepareAcceptCharsets(const char *i_AcceptCharset, nsACString &o_AcceptCharset)
 | |
| {
 | |
|     PRUint32 n, size, wrote, u;
 | |
|     PRInt32 available;
 | |
|     double q, dec;
 | |
|     char *p, *p2, *token, *q_Accept, *o_Accept;
 | |
|     const char *acceptable, *comma;
 | |
|     PRBool add_utf = PR_FALSE;
 | |
|     PRBool add_asterisk = PR_FALSE;
 | |
| 
 | |
|     if (!i_AcceptCharset)
 | |
|         acceptable = "";
 | |
|     else
 | |
|         acceptable = i_AcceptCharset;
 | |
|     o_Accept = nsCRT::strdup(acceptable);
 | |
|     if (nsnull == o_Accept)
 | |
|         return NS_ERROR_OUT_OF_MEMORY;
 | |
|     for (p = o_Accept, n = size = 0; '\0' != *p; p++) {
 | |
|         if (*p == ',') n++;
 | |
|             size++;
 | |
|     }
 | |
| 
 | |
|     // only add "utf-8" and "*" to the list if they aren't
 | |
|     // already specified.
 | |
| 
 | |
|     if (PL_strcasestr(acceptable, "utf-8") == NULL) {
 | |
|         n++;
 | |
|         add_utf = PR_TRUE;
 | |
|     }
 | |
|     if (PL_strchr(acceptable, '*') == NULL) {
 | |
|         n++;
 | |
|         add_asterisk = PR_TRUE;
 | |
|     }
 | |
| 
 | |
|     available = size + ++n * 11 + 1;
 | |
|     q_Accept = new char[available];
 | |
|     if ((char *) 0 == q_Accept)
 | |
|         return NS_ERROR_OUT_OF_MEMORY;
 | |
|     *q_Accept = '\0';
 | |
|     q = 1.0;
 | |
|     dec = q / (double) n;
 | |
|     n = 0;
 | |
|     p2 = q_Accept;
 | |
|     for (token = nsCRT::strtok(o_Accept, ",", &p);
 | |
|          token != (char *) 0;
 | |
|          token = nsCRT::strtok(p, ",", &p)) {
 | |
|         token = net_FindCharNotInSet(token, HTTP_LWS);
 | |
|         char* trim;
 | |
|         trim = net_FindCharInSet(token, ";" HTTP_LWS);
 | |
|         if (trim != (char*)0)  // remove "; q=..." if present
 | |
|             *trim = '\0';
 | |
| 
 | |
|         if (*token != '\0') {
 | |
|             comma = n++ != 0 ? "," : ""; // delimiter if not first item
 | |
|             u = QVAL_TO_UINT(q);
 | |
|             if (u < 10)
 | |
|                 wrote = PR_snprintf(p2, available, "%s%s;q=0.%u", comma, token, u);
 | |
|             else
 | |
|                 wrote = PR_snprintf(p2, available, "%s%s", comma, token);
 | |
|             q -= dec;
 | |
|             p2 += wrote;
 | |
|             available -= wrote;
 | |
|             NS_ASSERTION(available > 0, "allocated string not long enough");
 | |
|         }
 | |
|     }
 | |
|     if (add_utf) {
 | |
|         comma = n++ != 0 ? "," : ""; // delimiter if not first item
 | |
|         u = QVAL_TO_UINT(q);
 | |
|         if (u < 10)
 | |
|             wrote = PR_snprintf(p2, available, "%sutf-8;q=0.%u", comma, u);
 | |
|         else
 | |
|             wrote = PR_snprintf(p2, available, "%sutf-8", comma);
 | |
|         q -= dec;
 | |
|         p2 += wrote;
 | |
|         available -= wrote;
 | |
|         NS_ASSERTION(available > 0, "allocated string not long enough");
 | |
|     }
 | |
|     if (add_asterisk) {
 | |
|         comma = n++ != 0 ? "," : ""; // delimiter if not first item
 | |
| 
 | |
|         // keep q of "*" equal to the lowest q value
 | |
|         // in the event of a tie between the q of "*" and a non-wildcard
 | |
|         // the non-wildcard always receives preference.
 | |
| 
 | |
|         q += dec;
 | |
|         u = QVAL_TO_UINT(q);
 | |
|         if (u < 10)
 | |
|             wrote = PR_snprintf(p2, available, "%s*;q=0.%u", comma, u);
 | |
|         else
 | |
|             wrote = PR_snprintf(p2, available, "%s*", comma);
 | |
|         available -= wrote;
 | |
|         p2 += wrote;
 | |
|         NS_ASSERTION(available > 0, "allocated string not long enough");
 | |
|     }
 | |
|     nsCRT::free(o_Accept);
 | |
| 
 | |
|     // change alloc from C++ new/delete to nsCRT::strdup's way
 | |
|     o_AcceptCharset.Assign(q_Accept);
 | |
| #if defined DEBUG_havill
 | |
|     printf("Accept-Charset: %s\n", q_Accept);
 | |
| #endif
 | |
|     delete [] q_Accept;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsHttpHandler::SetAcceptCharsets(const char *aAcceptCharsets) 
 | |
| {
 | |
|     nsCString buf;
 | |
|     nsresult rv = PrepareAcceptCharsets(aAcceptCharsets, buf);
 | |
|     if (NS_SUCCEEDED(rv))
 | |
|         mAcceptCharsets.Assign(buf);
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsHttpHandler::SetAccept(const char *aAccept) 
 | |
| {
 | |
|     mAccept = aAccept;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsHttpHandler::SetAcceptEncodings(const char *aAcceptEncodings) 
 | |
| {
 | |
|     mAcceptEncodings = aAcceptEncodings;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // nsHttpHandler::nsISupports
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| NS_IMPL_THREADSAFE_ISUPPORTS5(nsHttpHandler,
 | |
|                               nsIHttpProtocolHandler,
 | |
|                               nsIProxiedProtocolHandler,
 | |
|                               nsIProtocolHandler,
 | |
|                               nsIObserver,
 | |
|                               nsISupportsWeakReference)
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // nsHttpHandler::nsIProtocolHandler
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetScheme(nsACString &aScheme)
 | |
| {
 | |
|     aScheme.AssignLiteral("http");
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetDefaultPort(PRInt32 *result)
 | |
| {
 | |
|     *result = NS_HTTP_DEFAULT_PORT;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetProtocolFlags(PRUint32 *result)
 | |
| {
 | |
|     *result = NS_HTTP_PROTOCOL_FLAGS;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::NewURI(const nsACString &aSpec,
 | |
|                       const char *aCharset,
 | |
|                       nsIURI *aBaseURI,
 | |
|                       nsIURI **aURI)
 | |
| {
 | |
|     LOG(("nsHttpHandler::NewURI\n"));
 | |
|     return ::NewURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT, aURI);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::NewChannel(nsIURI *uri, nsIChannel **result)
 | |
| {
 | |
|     LOG(("nsHttpHandler::NewChannel\n"));
 | |
| 
 | |
|     NS_ENSURE_ARG_POINTER(uri);
 | |
|     NS_ENSURE_ARG_POINTER(result);
 | |
| 
 | |
|     PRBool isHttp = PR_FALSE, isHttps = PR_FALSE;
 | |
| 
 | |
|     // Verify that we have been given a valid scheme
 | |
|     nsresult rv = uri->SchemeIs("http", &isHttp);
 | |
|     if (NS_FAILED(rv)) return rv;
 | |
|     if (!isHttp) {
 | |
|         rv = uri->SchemeIs("https", &isHttps);
 | |
|         if (NS_FAILED(rv)) return rv;
 | |
|         if (!isHttps) {
 | |
|             NS_WARNING("Invalid URI scheme");
 | |
|             return NS_ERROR_UNEXPECTED;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     return NewProxiedChannel(uri, nsnull, result);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP 
 | |
| nsHttpHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
 | |
| {
 | |
|     // don't override anything.  
 | |
|     *_retval = PR_FALSE;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // nsHttpHandler::nsIProxiedProtocolHandler
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::NewProxiedChannel(nsIURI *uri,
 | |
|                                  nsIProxyInfo* givenProxyInfo,
 | |
|                                  nsIChannel **result)
 | |
| {
 | |
|     nsRefPtr<HttpBaseChannel> httpChannel;
 | |
| 
 | |
|     LOG(("nsHttpHandler::NewProxiedChannel [proxyInfo=%p]\n",
 | |
|         givenProxyInfo));
 | |
|     
 | |
|     nsCOMPtr<nsProxyInfo> proxyInfo;
 | |
|     if (givenProxyInfo) {
 | |
|         proxyInfo = do_QueryInterface(givenProxyInfo);
 | |
|         NS_ENSURE_ARG(proxyInfo);
 | |
|     }
 | |
| 
 | |
|     PRBool https;
 | |
|     nsresult rv = uri->SchemeIs("https", &https);
 | |
|     if (NS_FAILED(rv))
 | |
|         return rv;
 | |
| 
 | |
| #ifdef MOZ_IPC
 | |
|     if (IsNeckoChild()) {
 | |
|         httpChannel = new HttpChannelChild();
 | |
|     } else
 | |
| #endif
 | |
|     {
 | |
|         httpChannel = new nsHttpChannel();
 | |
|     }
 | |
| 
 | |
|     // select proxy caps if using a non-transparent proxy.  SSL tunneling
 | |
|     // should not use proxy settings.
 | |
|     PRInt8 caps;
 | |
|     if (proxyInfo && !nsCRT::strcmp(proxyInfo->Type(), "http") && !https)
 | |
|         caps = mProxyCapabilities;
 | |
|     else
 | |
|         caps = mCapabilities;
 | |
| 
 | |
|     if (https) {
 | |
|         // enable pipelining over SSL if requested
 | |
|         if (mPipeliningOverSSL)
 | |
|             caps |= NS_HTTP_ALLOW_PIPELINING;
 | |
| 
 | |
|         // HACK: make sure PSM gets initialized on the main thread.
 | |
|         nsCOMPtr<nsISocketProviderService> spserv =
 | |
|                 do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID);
 | |
|         if (spserv) {
 | |
|             nsCOMPtr<nsISocketProvider> provider;
 | |
|             spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     rv = httpChannel->Init(uri, caps, proxyInfo);
 | |
|     if (NS_FAILED(rv))
 | |
|         return rv;
 | |
| 
 | |
|     httpChannel.forget(result);
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // nsHttpHandler::nsIHttpProtocolHandler
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetUserAgent(nsACString &value)
 | |
| {
 | |
|     value = UserAgent();
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetAppName(nsACString &value)
 | |
| {
 | |
|     value = mAppName;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetAppVersion(nsACString &value)
 | |
| {
 | |
|     value = mAppVersion;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetVendor(nsACString &value)
 | |
| {
 | |
|     value = mVendor;
 | |
|     return NS_OK;
 | |
| }
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::SetVendor(const nsACString &value)
 | |
| {
 | |
|     mVendor = value;
 | |
|     mUserAgentIsDirty = PR_TRUE;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetVendorSub(nsACString &value)
 | |
| {
 | |
|     value = mVendorSub;
 | |
|     return NS_OK;
 | |
| }
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::SetVendorSub(const nsACString &value)
 | |
| {
 | |
|     mVendorSub = value;
 | |
|     mUserAgentIsDirty = PR_TRUE;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetVendorComment(nsACString &value)
 | |
| {
 | |
|     value = mVendorComment;
 | |
|     return NS_OK;
 | |
| }
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::SetVendorComment(const nsACString &value)
 | |
| {
 | |
|     mVendorComment = value;
 | |
|     mUserAgentIsDirty = PR_TRUE;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetProduct(nsACString &value)
 | |
| {
 | |
|     value = mProduct;
 | |
|     return NS_OK;
 | |
| }
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::SetProduct(const nsACString &value)
 | |
| {
 | |
|     mProduct = value;
 | |
|     mUserAgentIsDirty = PR_TRUE;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetProductSub(nsACString &value)
 | |
| {
 | |
|     value = mProductSub;
 | |
|     return NS_OK;
 | |
| }
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::SetProductSub(const nsACString &value)
 | |
| {
 | |
|     mProductSub = value;
 | |
|     mUserAgentIsDirty = PR_TRUE;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetProductComment(nsACString &value)
 | |
| {
 | |
|     value = mProductComment;
 | |
|     return NS_OK;
 | |
| }
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::SetProductComment(const nsACString &value)
 | |
| {
 | |
|     mProductComment = value;
 | |
|     mUserAgentIsDirty = PR_TRUE;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetPlatform(nsACString &value)
 | |
| {
 | |
|     value = mPlatform;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetOscpu(nsACString &value)
 | |
| {
 | |
|     value = mOscpu;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetLanguage(nsACString &value)
 | |
| {
 | |
|     value = mLanguage;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::GetMisc(nsACString &value)
 | |
| {
 | |
|     value = mMisc;
 | |
|     return NS_OK;
 | |
| }
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::SetMisc(const nsACString &value)
 | |
| {
 | |
|     mMisc = value;
 | |
|     mUserAgentIsDirty = PR_TRUE;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // nsHttpHandler::nsIObserver
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpHandler::Observe(nsISupports *subject,
 | |
|                        const char *topic,
 | |
|                        const PRUnichar *data)
 | |
| {
 | |
|     LOG(("nsHttpHandler::Observe [topic=\"%s\"]\n", topic));
 | |
| 
 | |
|     if (strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
 | |
|         nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(subject);
 | |
|         if (prefBranch)
 | |
|             PrefsChanged(prefBranch, NS_ConvertUTF16toUTF8(data).get());
 | |
|     }
 | |
|     else if (strcmp(topic, "profile-change-net-teardown")    == 0 ||
 | |
|              strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)    == 0) {
 | |
| 
 | |
|         // kill off the "prune dead connections" timer
 | |
|         StopPruneDeadConnectionsTimer();
 | |
| 
 | |
|         // clear cache of all authentication credentials.
 | |
|         mAuthCache.ClearAll();
 | |
| 
 | |
|         // ensure connection manager is shutdown
 | |
|         if (mConnMgr)
 | |
|             mConnMgr->Shutdown();
 | |
| 
 | |
|         // need to reset the session start time since cache validation may
 | |
|         // depend on this value.
 | |
|         mSessionStartTime = NowInSeconds();
 | |
|     }
 | |
|     else if (strcmp(topic, "profile-change-net-restore") == 0) {
 | |
|         // initialize connection manager
 | |
|         InitConnectionMgr();
 | |
| 
 | |
|         // restart the "prune dead connections" timer
 | |
|         StartPruneDeadConnectionsTimer();
 | |
|     }
 | |
|     else if (strcmp(topic, "timer-callback") == 0) {
 | |
|         // prune dead connections
 | |
| #ifdef DEBUG
 | |
|         nsCOMPtr<nsITimer> timer = do_QueryInterface(subject);
 | |
|         NS_ASSERTION(timer == mTimer, "unexpected timer-callback");
 | |
| #endif
 | |
|         if (mConnMgr)
 | |
|             mConnMgr->PruneDeadConnections();
 | |
|     }
 | |
|     else if (strcmp(topic, "net:clear-active-logins") == 0) {
 | |
|         mAuthCache.ClearAll();
 | |
|     }
 | |
|     else if (strcmp(topic, "xpcom-shutdown-threads") == 0) {
 | |
|         // Shutdown the cache write thread. This must be done after shutting down
 | |
|         // the cache service, because the (memory) cache entries' storage streams
 | |
|         // get released on the thread on which they were first written to, which
 | |
|         // is this thread.
 | |
|         if (mCacheWriteThread) {
 | |
|             LOG(("  shutting down cache-write thread...\n"));
 | |
|             mCacheWriteThread->Shutdown();
 | |
|             LOG(("  cache-write thread shutdown complete\n"));
 | |
|             mCacheWriteThread = nsnull;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // nsHttpsHandler implementation
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| NS_IMPL_THREADSAFE_ISUPPORTS4(nsHttpsHandler,
 | |
|                               nsIHttpProtocolHandler,
 | |
|                               nsIProxiedProtocolHandler,
 | |
|                               nsIProtocolHandler,
 | |
|                               nsISupportsWeakReference)
 | |
| 
 | |
| nsresult
 | |
| nsHttpsHandler::Init()
 | |
| {
 | |
|     nsCOMPtr<nsIProtocolHandler> httpHandler(
 | |
|             do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http"));
 | |
|     NS_ASSERTION(httpHandler.get() != nsnull, "no http handler?");
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpsHandler::GetScheme(nsACString &aScheme)
 | |
| {
 | |
|     aScheme.AssignLiteral("https");
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpsHandler::GetDefaultPort(PRInt32 *aPort)
 | |
| {
 | |
|     *aPort = NS_HTTPS_DEFAULT_PORT;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpsHandler::GetProtocolFlags(PRUint32 *aProtocolFlags)
 | |
| {
 | |
|     *aProtocolFlags = NS_HTTP_PROTOCOL_FLAGS;
 | |
|     return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpsHandler::NewURI(const nsACString &aSpec,
 | |
|                        const char *aOriginCharset,
 | |
|                        nsIURI *aBaseURI,
 | |
|                        nsIURI **_retval)
 | |
| {
 | |
|     return ::NewURI(aSpec, aOriginCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT, _retval);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpsHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
 | |
| {
 | |
|     NS_ABORT_IF_FALSE(gHttpHandler, "Should have a HTTP handler by now.");
 | |
|     if (!gHttpHandler)
 | |
|       return NS_ERROR_UNEXPECTED;
 | |
|     return gHttpHandler->NewChannel(aURI, _retval);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsHttpsHandler::AllowPort(PRInt32 aPort, const char *aScheme, PRBool *_retval)
 | |
| {
 | |
|     // don't override anything.  
 | |
|     *_retval = PR_FALSE;
 | |
|     return NS_OK;
 | |
| }
 |