Bug 458256. Use LoadLibraryW instead of LoadLibrary (patch by DougT). r+sr=vlad
[wine-gecko.git] / netwerk / protocol / http / src / nsHttpHandler.cpp
blobfa9b5e1f1bab6465c7e0e55c284603758c9873b3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:set ts=4 sw=4 sts=4 et cin: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications.
20 * Portions created by the Initial Developer are Copyright (C) 2001
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Darin Fisher <darin@netscape.com> (original author)
25 * Gagan Saksena <gagan@netscape.com>
26 * Pierre Phaneuf <pp@ludusdesign.com>
27 * Christopher Blizzard <blizzard@mozilla.org>
28 * Adrian Havill <havill@redhat.com>
29 * Gervase Markham <gerv@gerv.net>
30 * Bradley Baetz <bbaetz@netscape.com>
31 * Benjamin Smedberg <bsmedberg@covad.net>
32 * Josh Aas <josh@mozilla.com>
34 * Alternatively, the contents of this file may be used under the terms of
35 * either the GNU General Public License Version 2 or later (the "GPL"), or
36 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
37 * in which case the provisions of the GPL or the LGPL are applicable instead
38 * of those above. If you wish to allow use of your version of this file only
39 * under the terms of either the GPL or the LGPL, and not to allow others to
40 * use your version of this file under the terms of the MPL, indicate your
41 * decision by deleting the provisions above and replace them with the notice
42 * and other provisions required by the GPL or the LGPL. If you do not delete
43 * the provisions above, a recipient may use your version of this file under
44 * the terms of any one of the MPL, the GPL or the LGPL.
46 * ***** END LICENSE BLOCK ***** */
48 #include "nsHttp.h"
49 #include "nsHttpHandler.h"
50 #include "nsHttpChannel.h"
51 #include "nsHttpConnection.h"
52 #include "nsHttpResponseHead.h"
53 #include "nsHttpTransaction.h"
54 #include "nsHttpAuthCache.h"
55 #include "nsStandardURL.h"
56 #include "nsIHttpChannel.h"
57 #include "nsIURL.h"
58 #include "nsIStandardURL.h"
59 #include "nsICacheService.h"
60 #include "nsICategoryManager.h"
61 #include "nsCategoryManagerUtils.h"
62 #include "nsICacheService.h"
63 #include "nsIPrefService.h"
64 #include "nsIPrefBranch2.h"
65 #include "nsIPrefLocalizedString.h"
66 #include "nsISocketProviderService.h"
67 #include "nsISocketProvider.h"
68 #include "nsPrintfCString.h"
69 #include "nsCOMPtr.h"
70 #include "nsNetCID.h"
71 #include "nsAutoLock.h"
72 #include "prprf.h"
73 #include "nsReadableUtils.h"
74 #include "nsQuickSort.h"
75 #include "nsNetUtil.h"
76 #include "nsIOService.h"
78 #include "nsIXULAppInfo.h"
80 #if defined(XP_UNIX) || defined(XP_BEOS)
81 #include <sys/utsname.h>
82 #endif
84 #if defined(XP_WIN)
85 #include <windows.h>
86 #endif
88 #if defined(XP_MACOSX)
89 #include <Carbon/Carbon.h>
90 #endif
92 #if defined(XP_OS2)
93 #define INCL_DOSMISC
94 #include <os2.h>
95 #endif
97 #ifdef DEBUG
98 // defined by the socket transport service while active
99 extern PRThread *gSocketThread;
100 #endif
102 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
103 static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
104 static NS_DEFINE_CID(kCookieServiceCID, NS_COOKIESERVICE_CID);
105 static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
106 static NS_DEFINE_CID(kSocketProviderServiceCID, NS_SOCKETPROVIDERSERVICE_CID);
108 #define UA_PREF_PREFIX "general.useragent."
109 #define UA_APPNAME "Mozilla"
110 #define UA_APPVERSION "5.0"
111 #define UA_APPSECURITY_FALLBACK "N"
113 #define HTTP_PREF_PREFIX "network.http."
114 #define INTL_ACCEPT_LANGUAGES "intl.accept_languages"
115 #define INTL_ACCEPT_CHARSET "intl.charset.default"
116 #define NETWORK_ENABLEIDN "network.enableIDN"
117 #define BROWSER_PREF_PREFIX "browser.cache."
119 #define UA_PREF(_pref) UA_PREF_PREFIX _pref
120 #define HTTP_PREF(_pref) HTTP_PREF_PREFIX _pref
121 #define BROWSER_PREF(_pref) BROWSER_PREF_PREFIX _pref
123 //-----------------------------------------------------------------------------
125 static nsresult
126 NewURI(const nsACString &aSpec,
127 const char *aCharset,
128 nsIURI *aBaseURI,
129 PRInt32 aDefaultPort,
130 nsIURI **aURI)
132 nsStandardURL *url = new nsStandardURL();
133 if (!url)
134 return NS_ERROR_OUT_OF_MEMORY;
135 NS_ADDREF(url);
137 nsresult rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY,
138 aDefaultPort, aSpec, aCharset, aBaseURI);
139 if (NS_FAILED(rv)) {
140 NS_RELEASE(url);
141 return rv;
144 *aURI = url; // no QI needed
145 return NS_OK;
148 //-----------------------------------------------------------------------------
149 // nsHttpHandler <public>
150 //-----------------------------------------------------------------------------
152 nsHttpHandler *gHttpHandler = nsnull;
154 nsHttpHandler::nsHttpHandler()
155 : mConnMgr(nsnull)
156 , mHttpVersion(NS_HTTP_VERSION_1_1)
157 , mProxyHttpVersion(NS_HTTP_VERSION_1_1)
158 , mCapabilities(NS_HTTP_ALLOW_KEEPALIVE)
159 , mProxyCapabilities(NS_HTTP_ALLOW_KEEPALIVE)
160 , mReferrerLevel(0xff) // by default we always send a referrer
161 , mIdleTimeout(10)
162 , mMaxRequestAttempts(10)
163 , mMaxRequestDelay(10)
164 , mMaxConnections(24)
165 , mMaxConnectionsPerServer(8)
166 , mMaxPersistentConnectionsPerServer(2)
167 , mMaxPersistentConnectionsPerProxy(4)
168 , mMaxPipelinedRequests(2)
169 , mRedirectionLimit(10)
170 , mPhishyUserPassLength(1)
171 , mPipeliningOverSSL(PR_FALSE)
172 , mLastUniqueID(NowInSeconds())
173 , mSessionStartTime(0)
174 , mProduct("Gecko")
175 , mUserAgentIsDirty(PR_TRUE)
176 , mUseCache(PR_TRUE)
177 , mSendSecureXSiteReferrer(PR_TRUE)
178 , mEnablePersistentHttpsCaching(PR_FALSE)
180 #if defined(PR_LOGGING)
181 gHttpLog = PR_NewLogModule("nsHttp");
182 #endif
184 LOG(("Creating nsHttpHandler [this=%x].\n", this));
186 NS_ASSERTION(!gHttpHandler, "HTTP handler already created!");
187 gHttpHandler = this;
190 nsHttpHandler::~nsHttpHandler()
192 // We do not deal with the timer cancellation in the destructor since
193 // it is taken care of in xpcom shutdown event in the Observe method.
195 LOG(("Deleting nsHttpHandler [this=%x]\n", this));
197 // make sure the connection manager is shutdown
198 if (mConnMgr) {
199 mConnMgr->Shutdown();
200 NS_RELEASE(mConnMgr);
203 nsHttp::DestroyAtomTable();
205 gHttpHandler = nsnull;
208 nsresult
209 nsHttpHandler::Init()
211 nsresult rv;
213 LOG(("nsHttpHandler::Init\n"));
215 rv = nsHttp::CreateAtomTable();
216 if (NS_FAILED(rv))
217 return rv;
219 mIOService = do_GetService(kIOServiceCID, &rv);
220 if (NS_FAILED(rv)) {
221 NS_WARNING("unable to continue without io service");
222 return rv;
225 InitUserAgentComponents();
227 // monitor some preference changes
228 nsCOMPtr<nsIPrefBranch2> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
229 if (prefBranch) {
230 prefBranch->AddObserver(HTTP_PREF_PREFIX, this, PR_TRUE);
231 prefBranch->AddObserver(UA_PREF_PREFIX, this, PR_TRUE);
232 prefBranch->AddObserver(INTL_ACCEPT_LANGUAGES, this, PR_TRUE);
233 prefBranch->AddObserver(INTL_ACCEPT_CHARSET, this, PR_TRUE);
234 prefBranch->AddObserver(NETWORK_ENABLEIDN, this, PR_TRUE);
235 prefBranch->AddObserver(BROWSER_PREF("disk_cache_ssl"), this, PR_TRUE);
237 PrefsChanged(prefBranch, nsnull);
240 mMisc.AssignLiteral("rv:" MOZILLA_VERSION);
242 #if DEBUG
243 // dump user agent prefs
244 LOG(("> app-name = %s\n", mAppName.get()));
245 LOG(("> app-version = %s\n", mAppVersion.get()));
246 LOG(("> platform = %s\n", mPlatform.get()));
247 LOG(("> oscpu = %s\n", mOscpu.get()));
248 LOG(("> security = %s\n", mSecurity.get()));
249 LOG(("> language = %s\n", mLanguage.get()));
250 LOG(("> misc = %s\n", mMisc.get()));
251 LOG(("> vendor = %s\n", mVendor.get()));
252 LOG(("> vendor-sub = %s\n", mVendorSub.get()));
253 LOG(("> vendor-comment = %s\n", mVendorComment.get()));
254 LOG(("> extra = %s\n", mExtraUA.get()));
255 LOG(("> product = %s\n", mProduct.get()));
256 LOG(("> product-sub = %s\n", mProductSub.get()));
257 LOG(("> product-comment = %s\n", mProductComment.get()));
258 LOG(("> user-agent = %s\n", UserAgent().get()));
259 #endif
261 mSessionStartTime = NowInSeconds();
263 rv = mAuthCache.Init();
264 if (NS_FAILED(rv)) return rv;
266 rv = InitConnectionMgr();
267 if (NS_FAILED(rv)) return rv;
269 nsCOMPtr<nsIXULAppInfo> appInfo =
270 do_GetService("@mozilla.org/xre/app-info;1");
271 if (appInfo)
272 appInfo->GetPlatformBuildID(mProductSub);
273 if (mProductSub.Length() > 8)
274 mProductSub.SetLength(8);
276 // Startup the http category
277 // Bring alive the objects in the http-protocol-startup category
278 NS_CreateServicesFromCategory(NS_HTTP_STARTUP_CATEGORY,
279 static_cast<nsISupports*>(static_cast<void*>(this)),
280 NS_HTTP_STARTUP_TOPIC);
282 mObserverService = do_GetService("@mozilla.org/observer-service;1");
283 if (mObserverService) {
284 mObserverService->AddObserver(this, "profile-change-net-teardown", PR_TRUE);
285 mObserverService->AddObserver(this, "profile-change-net-restore", PR_TRUE);
286 mObserverService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
289 StartPruneDeadConnectionsTimer();
290 return NS_OK;
293 nsresult
294 nsHttpHandler::InitConnectionMgr()
296 nsresult rv;
298 if (!mConnMgr) {
299 mConnMgr = new nsHttpConnectionMgr();
300 if (!mConnMgr)
301 return NS_ERROR_OUT_OF_MEMORY;
302 NS_ADDREF(mConnMgr);
305 rv = mConnMgr->Init(mMaxConnections,
306 mMaxConnectionsPerServer,
307 mMaxConnectionsPerServer,
308 mMaxPersistentConnectionsPerServer,
309 mMaxPersistentConnectionsPerProxy,
310 mMaxRequestDelay,
311 mMaxPipelinedRequests);
312 return rv;
315 void
316 nsHttpHandler::StartPruneDeadConnectionsTimer()
318 LOG(("nsHttpHandler::StartPruneDeadConnectionsTimer\n"));
320 mTimer = do_CreateInstance("@mozilla.org/timer;1");
321 NS_ASSERTION(mTimer, "no timer");
322 // failure to create a timer is not a fatal error, but idle connections
323 // will not be cleaned up until we try to use them.
324 if (mTimer)
325 mTimer->Init(this, 15*1000, // every 15 seconds
326 nsITimer::TYPE_REPEATING_SLACK);
329 void
330 nsHttpHandler::StopPruneDeadConnectionsTimer()
332 LOG(("nsHttpHandler::StopPruneDeadConnectionsTimer\n"));
334 if (mTimer) {
335 mTimer->Cancel();
336 mTimer = 0;
340 nsresult
341 nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request,
342 PRUint8 caps,
343 PRBool useProxy)
345 nsresult rv;
347 // Add the "User-Agent" header
348 rv = request->SetHeader(nsHttp::User_Agent, UserAgent());
349 if (NS_FAILED(rv)) return rv;
351 // MIME based content negotiation lives!
352 // Add the "Accept" header
353 rv = request->SetHeader(nsHttp::Accept, mAccept);
354 if (NS_FAILED(rv)) return rv;
356 // Add the "Accept-Language" header
357 if (!mAcceptLanguages.IsEmpty()) {
358 // Add the "Accept-Language" header
359 rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages);
360 if (NS_FAILED(rv)) return rv;
363 // Add the "Accept-Encoding" header
364 rv = request->SetHeader(nsHttp::Accept_Encoding, mAcceptEncodings);
365 if (NS_FAILED(rv)) return rv;
367 // Add the "Accept-Charset" header
368 rv = request->SetHeader(nsHttp::Accept_Charset, mAcceptCharsets);
369 if (NS_FAILED(rv)) return rv;
371 // RFC2616 section 19.6.2 states that the "Connection: keep-alive"
372 // and "Keep-alive" request headers should not be sent by HTTP/1.1
373 // user-agents. Otherwise, problems with proxy servers (especially
374 // transparent proxies) can result.
376 // However, we need to send something so that we can use keepalive
377 // with HTTP/1.0 servers/proxies. We use "Proxy-Connection:" when
378 // we're talking to an http proxy, and "Connection:" otherwise
380 NS_NAMED_LITERAL_CSTRING(close, "close");
381 NS_NAMED_LITERAL_CSTRING(keepAlive, "keep-alive");
383 const nsACString *connectionType = &close;
384 if (caps & NS_HTTP_ALLOW_KEEPALIVE) {
385 rv = request->SetHeader(nsHttp::Keep_Alive, nsPrintfCString("%u", mIdleTimeout));
386 if (NS_FAILED(rv)) return rv;
387 connectionType = &keepAlive;
388 } else if (useProxy) {
389 // Bug 92006
390 request->SetHeader(nsHttp::Connection, close);
393 const nsHttpAtom &header = useProxy ? nsHttp::Proxy_Connection
394 : nsHttp::Connection;
395 return request->SetHeader(header, *connectionType);
398 PRBool
399 nsHttpHandler::IsAcceptableEncoding(const char *enc)
401 if (!enc)
402 return PR_FALSE;
404 // HTTP 1.1 allows servers to send x-gzip and x-compress instead
405 // of gzip and compress, for example. So, we'll always strip off
406 // an "x-" prefix before matching the encoding to one we claim
407 // to accept.
408 if (!PL_strncasecmp(enc, "x-", 2))
409 enc += 2;
411 return nsHttp::FindToken(mAcceptEncodings.get(), enc, HTTP_LWS ",") != nsnull;
414 nsresult
415 nsHttpHandler::GetCacheSession(nsCacheStoragePolicy storagePolicy,
416 nsICacheSession **result)
418 nsresult rv;
420 // Skip cache if disabled in preferences
421 if (!mUseCache)
422 return NS_ERROR_NOT_AVAILABLE;
424 // We want to get the pointer to the cache service each time we're called,
425 // because it's possible for some add-ons (such as Google Gears) to swap
426 // in new cache services on the fly, and we want to pick them up as
427 // appropriate.
428 nsCOMPtr<nsICacheService> serv = do_GetService(NS_CACHESERVICE_CONTRACTID,
429 &rv);
430 if (NS_FAILED(rv)) return rv;
432 const char *sessionName = "HTTP";
433 switch (storagePolicy) {
434 case nsICache::STORE_IN_MEMORY:
435 sessionName = "HTTP-memory-only";
436 break;
437 case nsICache::STORE_OFFLINE:
438 sessionName = "HTTP-offline";
439 break;
440 default:
441 break;
444 nsCOMPtr<nsICacheSession> cacheSession;
445 rv = serv->CreateSession(sessionName,
446 storagePolicy,
447 nsICache::STREAM_BASED,
448 getter_AddRefs(cacheSession));
449 if (NS_FAILED(rv)) return rv;
451 rv = cacheSession->SetDoomEntriesIfExpired(PR_FALSE);
452 if (NS_FAILED(rv)) return rv;
454 NS_ADDREF(*result = cacheSession);
456 return NS_OK;
459 nsresult
460 nsHttpHandler::GetStreamConverterService(nsIStreamConverterService **result)
462 if (!mStreamConvSvc) {
463 nsresult rv;
464 mStreamConvSvc = do_GetService(kStreamConverterServiceCID, &rv);
465 if (NS_FAILED(rv)) return rv;
467 *result = mStreamConvSvc;
468 NS_ADDREF(*result);
469 return NS_OK;
472 nsICookieService *
473 nsHttpHandler::GetCookieService()
475 if (!mCookieService)
476 mCookieService = do_GetService(kCookieServiceCID);
477 return mCookieService;
480 nsresult
481 nsHttpHandler::GetIOService(nsIIOService** result)
483 NS_ADDREF(*result = mIOService);
484 return NS_OK;
488 void
489 nsHttpHandler::NotifyObservers(nsIHttpChannel *chan, const char *event)
491 LOG(("nsHttpHandler::NotifyObservers [chan=%x event=\"%s\"]\n", chan, event));
492 if (mObserverService)
493 mObserverService->NotifyObservers(chan, event, nsnull);
496 nsresult
497 nsHttpHandler::OnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
498 PRUint32 flags)
500 // First, the global observer
501 NS_ASSERTION(gIOService, "Must have an IO service at this point");
502 nsresult rv = gIOService->OnChannelRedirect(oldChan, newChan, flags);
503 if (NS_FAILED(rv))
504 return rv;
506 // Now, the per-channel observers
507 nsCOMPtr<nsIChannelEventSink> sink;
508 NS_QueryNotificationCallbacks(oldChan, sink);
509 if (sink)
510 rv = sink->OnChannelRedirect(oldChan, newChan, flags);
512 return rv;
515 //-----------------------------------------------------------------------------
516 // nsHttpHandler <private>
517 //-----------------------------------------------------------------------------
519 const nsAFlatCString &
520 nsHttpHandler::UserAgent()
522 if (mUserAgentOverride) {
523 LOG(("using general.useragent.override : %s\n", mUserAgentOverride.get()));
524 return mUserAgentOverride;
527 if (mUserAgentIsDirty) {
528 BuildUserAgent();
529 mUserAgentIsDirty = PR_FALSE;
532 return mUserAgent;
535 void
536 nsHttpHandler::BuildUserAgent()
538 LOG(("nsHttpHandler::BuildUserAgent\n"));
540 NS_ASSERTION(!mAppName.IsEmpty() &&
541 !mAppVersion.IsEmpty() &&
542 !mPlatform.IsEmpty() &&
543 !mSecurity.IsEmpty() &&
544 !mOscpu.IsEmpty(),
545 "HTTP cannot send practical requests without this much");
547 // preallocate to worst-case size, which should always be better
548 // than if we didn't preallocate at all.
549 mUserAgent.SetCapacity(mAppName.Length() +
550 mAppVersion.Length() +
551 mPlatform.Length() +
552 mSecurity.Length() +
553 mOscpu.Length() +
554 mLanguage.Length() +
555 mMisc.Length() +
556 mProduct.Length() +
557 mProductSub.Length() +
558 mProductComment.Length() +
559 mVendor.Length() +
560 mVendorSub.Length() +
561 mVendorComment.Length() +
562 mExtraUA.Length() +
563 22);
565 // Application portion
566 mUserAgent.Assign(mAppName);
567 mUserAgent += '/';
568 mUserAgent += mAppVersion;
569 mUserAgent += ' ';
571 // Application comment
572 mUserAgent += '(';
573 mUserAgent += mPlatform;
574 mUserAgent.AppendLiteral("; ");
575 mUserAgent += mSecurity;
576 mUserAgent.AppendLiteral("; ");
577 mUserAgent += mOscpu;
578 if (!mLanguage.IsEmpty()) {
579 mUserAgent.AppendLiteral("; ");
580 mUserAgent += mLanguage;
582 if (!mMisc.IsEmpty()) {
583 mUserAgent.AppendLiteral("; ");
584 mUserAgent += mMisc;
586 mUserAgent += ')';
588 // Product portion
589 if (!mProduct.IsEmpty()) {
590 mUserAgent += ' ';
591 mUserAgent += mProduct;
592 if (!mProductSub.IsEmpty()) {
593 mUserAgent += '/';
594 mUserAgent += mProductSub;
596 if (!mProductComment.IsEmpty()) {
597 mUserAgent.AppendLiteral(" (");
598 mUserAgent += mProductComment;
599 mUserAgent += ')';
603 // Vendor portion
604 if (!mVendor.IsEmpty()) {
605 mUserAgent += ' ';
606 mUserAgent += mVendor;
607 if (!mVendorSub.IsEmpty()) {
608 mUserAgent += '/';
609 mUserAgent += mVendorSub;
611 if (!mVendorComment.IsEmpty()) {
612 mUserAgent.AppendLiteral(" (");
613 mUserAgent += mVendorComment;
614 mUserAgent += ')';
618 if (!mExtraUA.IsEmpty())
619 mUserAgent += mExtraUA;
622 void
623 nsHttpHandler::InitUserAgentComponents()
626 // Gather platform.
627 mPlatform.AssignLiteral(
628 #if defined(MOZ_WIDGET_PHOTON)
629 "Photon"
630 #elif defined(XP_OS2)
631 "OS/2"
632 #elif defined(XP_WIN)
633 "Windows"
634 #elif defined(XP_MACOSX)
635 "Macintosh"
636 #elif defined(XP_BEOS)
637 "BeOS"
638 #elif !defined(MOZ_X11)
640 #else
641 "X11"
642 #endif
645 // Gather OS/CPU.
646 #if defined(XP_OS2)
647 ULONG os2ver = 0;
648 DosQuerySysInfo(QSV_VERSION_MINOR, QSV_VERSION_MINOR,
649 &os2ver, sizeof(os2ver));
650 if (os2ver == 11)
651 mOscpu.AssignLiteral("2.11");
652 else if (os2ver == 30)
653 mOscpu.AssignLiteral("Warp 3");
654 else if (os2ver == 40)
655 mOscpu.AssignLiteral("Warp 4");
656 else if (os2ver == 45)
657 mOscpu.AssignLiteral("Warp 4.5");
659 #elif defined(WINCE)
660 OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
661 if (GetVersionEx(&info)) {
662 char *buf = PR_smprintf("Windows CE %ld.%ld",
663 info.dwMajorVersion,
664 info.dwMinorVersion);
665 if (buf) {
666 mOscpu = buf;
667 PR_smprintf_free(buf);
670 #elif defined(XP_WIN)
671 OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
672 if (GetVersionEx(&info)) {
673 if (info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
674 if (info.dwMajorVersion == 3)
675 mOscpu.AssignLiteral("WinNT3.51");
676 else if (info.dwMajorVersion == 4)
677 mOscpu.AssignLiteral("WinNT4.0");
678 else {
679 char *buf = PR_smprintf("Windows NT %ld.%ld",
680 info.dwMajorVersion,
681 info.dwMinorVersion);
682 if (buf) {
683 mOscpu = buf;
684 PR_smprintf_free(buf);
687 } else {
688 char *buf = PR_smprintf("Windows %ld.%ld",
689 info.dwMajorVersion,
690 info.dwMinorVersion);
691 if (buf) {
692 mOscpu = buf;
693 PR_smprintf_free(buf);
697 #elif defined (XP_MACOSX)
698 #if defined(__ppc__)
699 mOscpu.AssignLiteral("PPC Mac OS X");
700 #elif defined(__i386__)
701 mOscpu.AssignLiteral("Intel Mac OS X");
702 #endif
703 long majorVersion, minorVersion;
704 if ((::Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
705 (::Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
706 mOscpu += nsPrintfCString(" %ld.%ld", majorVersion, minorVersion);
708 #elif defined (XP_UNIX) || defined (XP_BEOS)
709 struct utsname name;
711 int ret = uname(&name);
712 if (ret >= 0) {
713 nsCAutoString buf;
714 buf = (char*)name.sysname;
716 if (strcmp(name.machine, "x86_64") == 0 &&
717 sizeof(void *) == sizeof(PRInt32)) {
718 // We're running 32-bit code on x86_64. Make this browser
719 // look like it's running on i686 hardware, but append "
720 // (x86_64)" to the end of the oscpu identifier to be able
721 // to differentiate this from someone running 64-bit code
722 // on x86_64..
724 buf += " i686 (x86_64)";
725 } else {
726 buf += ' ';
728 #ifdef AIX
729 // AIX uname returns machine specific info in the uname.machine
730 // field and does not return the cpu type like other platforms.
731 // We use the AIX version and release numbers instead.
732 buf += (char*)name.version;
733 buf += '.';
734 buf += (char*)name.release;
735 #else
736 buf += (char*)name.machine;
737 #endif
740 mOscpu.Assign(buf);
742 #endif
744 mUserAgentIsDirty = PR_TRUE;
747 static int StringCompare(const void* s1, const void* s2, void*)
749 return nsCRT::strcmp(*static_cast<const char *const *>(s1),
750 *static_cast<const char *const *>(s2));
753 void
754 nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
756 nsresult rv = NS_OK;
757 PRInt32 val;
759 LOG(("nsHttpHandler::PrefsChanged [pref=%s]\n", pref));
761 #define PREF_CHANGED(p) ((pref == nsnull) || !PL_strcmp(pref, p))
762 #define MULTI_PREF_CHANGED(p) \
763 ((pref == nsnull) || !PL_strncmp(pref, p, sizeof(p) - 1))
766 // UA components
769 // Gather application values.
770 if (PREF_CHANGED(UA_PREF("appName"))) {
771 prefs->GetCharPref(UA_PREF("appName"),
772 getter_Copies(mAppName));
773 if (mAppName.IsEmpty())
774 mAppName.AssignLiteral(UA_APPNAME);
775 mUserAgentIsDirty = PR_TRUE;
777 if (PREF_CHANGED(UA_PREF("appVersion"))) {
778 prefs->GetCharPref(UA_PREF("appVersion"),
779 getter_Copies(mAppVersion));
780 if (mAppVersion.IsEmpty())
781 mAppVersion.AssignLiteral(UA_APPVERSION);
782 mUserAgentIsDirty = PR_TRUE;
785 // Gather vendor values.
786 if (PREF_CHANGED(UA_PREF("vendor"))) {
787 prefs->GetCharPref(UA_PREF("vendor"),
788 getter_Copies(mVendor));
789 mUserAgentIsDirty = PR_TRUE;
791 if (PREF_CHANGED(UA_PREF("vendorSub"))) {
792 prefs->GetCharPref(UA_PREF("vendorSub"),
793 getter_Copies(mVendorSub));
794 mUserAgentIsDirty = PR_TRUE;
796 if (PREF_CHANGED(UA_PREF("vendorComment"))) {
797 prefs->GetCharPref(UA_PREF("vendorComment"),
798 getter_Copies(mVendorComment));
799 mUserAgentIsDirty = PR_TRUE;
802 if (MULTI_PREF_CHANGED(UA_PREF("extra."))) {
803 mExtraUA.Truncate();
805 // Unfortunately, we can't do this using the pref branch.
806 nsCOMPtr<nsIPrefService> service =
807 do_GetService(NS_PREFSERVICE_CONTRACTID);
808 nsCOMPtr<nsIPrefBranch> branch;
809 service->GetBranch(UA_PREF("extra."), getter_AddRefs(branch));
810 if (branch) {
811 PRUint32 extraCount;
812 char **extraItems;
813 rv = branch->GetChildList("", &extraCount, &extraItems);
814 if (NS_SUCCEEDED(rv) && extraItems) {
815 NS_QuickSort(extraItems, extraCount, sizeof(extraItems[0]),
816 StringCompare, nsnull);
817 for (char **item = extraItems,
818 **item_end = extraItems + extraCount;
819 item < item_end; ++item) {
820 nsXPIDLCString valStr;
821 branch->GetCharPref(*item, getter_Copies(valStr));
822 if (!valStr.IsEmpty())
823 mExtraUA += NS_LITERAL_CSTRING(" ") + valStr;
825 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(extraCount, extraItems);
829 mUserAgentIsDirty = PR_TRUE;
832 // Gather product values.
833 if (PREF_CHANGED(UA_PREF("productComment"))) {
834 prefs->GetCharPref(UA_PREF("productComment"),
835 getter_Copies(mProductComment));
836 mUserAgentIsDirty = PR_TRUE;
839 // Get Security level supported
840 if (PREF_CHANGED(UA_PREF("security"))) {
841 prefs->GetCharPref(UA_PREF("security"), getter_Copies(mSecurity));
842 if (!mSecurity)
843 mSecurity.AssignLiteral(UA_APPSECURITY_FALLBACK);
844 mUserAgentIsDirty = PR_TRUE;
847 // Gather locale.
848 if (PREF_CHANGED(UA_PREF("locale"))) {
849 nsCOMPtr<nsIPrefLocalizedString> pls;
850 prefs->GetComplexValue(UA_PREF("locale"),
851 NS_GET_IID(nsIPrefLocalizedString),
852 getter_AddRefs(pls));
853 if (pls) {
854 nsXPIDLString uval;
855 pls->ToString(getter_Copies(uval));
856 if (uval)
857 CopyUTF16toUTF8(uval, mLanguage);
859 else {
860 nsXPIDLCString cval;
861 rv = prefs->GetCharPref(UA_PREF("locale"), getter_Copies(cval));
862 if (cval)
863 mLanguage.Assign(cval);
866 mUserAgentIsDirty = PR_TRUE;
869 // general.useragent.override
870 if (PREF_CHANGED(UA_PREF("override"))) {
871 prefs->GetCharPref(UA_PREF("override"),
872 getter_Copies(mUserAgentOverride));
873 mUserAgentIsDirty = PR_TRUE;
877 // HTTP options
880 if (PREF_CHANGED(HTTP_PREF("keep-alive.timeout"))) {
881 rv = prefs->GetIntPref(HTTP_PREF("keep-alive.timeout"), &val);
882 if (NS_SUCCEEDED(rv))
883 mIdleTimeout = (PRUint16) CLAMP(val, 1, 0xffff);
886 if (PREF_CHANGED(HTTP_PREF("request.max-attempts"))) {
887 rv = prefs->GetIntPref(HTTP_PREF("request.max-attempts"), &val);
888 if (NS_SUCCEEDED(rv))
889 mMaxRequestAttempts = (PRUint16) CLAMP(val, 1, 0xffff);
892 if (PREF_CHANGED(HTTP_PREF("request.max-start-delay"))) {
893 rv = prefs->GetIntPref(HTTP_PREF("request.max-start-delay"), &val);
894 if (NS_SUCCEEDED(rv)) {
895 mMaxRequestDelay = (PRUint16) CLAMP(val, 0, 0xffff);
896 if (mConnMgr)
897 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_REQUEST_DELAY,
898 mMaxRequestDelay);
902 if (PREF_CHANGED(HTTP_PREF("max-connections"))) {
903 rv = prefs->GetIntPref(HTTP_PREF("max-connections"), &val);
904 if (NS_SUCCEEDED(rv)) {
905 mMaxConnections = (PRUint16) CLAMP(val, 1, 0xffff);
906 if (mConnMgr)
907 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS,
908 mMaxConnections);
912 if (PREF_CHANGED(HTTP_PREF("max-connections-per-server"))) {
913 rv = prefs->GetIntPref(HTTP_PREF("max-connections-per-server"), &val);
914 if (NS_SUCCEEDED(rv)) {
915 mMaxConnectionsPerServer = (PRUint8) CLAMP(val, 1, 0xff);
916 if (mConnMgr) {
917 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS_PER_HOST,
918 mMaxConnectionsPerServer);
919 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS_PER_PROXY,
920 mMaxConnectionsPerServer);
925 if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-server"))) {
926 rv = prefs->GetIntPref(HTTP_PREF("max-persistent-connections-per-server"), &val);
927 if (NS_SUCCEEDED(rv)) {
928 mMaxPersistentConnectionsPerServer = (PRUint8) CLAMP(val, 1, 0xff);
929 if (mConnMgr)
930 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_HOST,
931 mMaxPersistentConnectionsPerServer);
935 if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-proxy"))) {
936 rv = prefs->GetIntPref(HTTP_PREF("max-persistent-connections-per-proxy"), &val);
937 if (NS_SUCCEEDED(rv)) {
938 mMaxPersistentConnectionsPerProxy = (PRUint8) CLAMP(val, 1, 0xff);
939 if (mConnMgr)
940 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
941 mMaxPersistentConnectionsPerProxy);
945 if (PREF_CHANGED(HTTP_PREF("sendRefererHeader"))) {
946 rv = prefs->GetIntPref(HTTP_PREF("sendRefererHeader"), &val);
947 if (NS_SUCCEEDED(rv))
948 mReferrerLevel = (PRUint8) CLAMP(val, 0, 0xff);
951 if (PREF_CHANGED(HTTP_PREF("redirection-limit"))) {
952 rv = prefs->GetIntPref(HTTP_PREF("redirection-limit"), &val);
953 if (NS_SUCCEEDED(rv))
954 mRedirectionLimit = (PRUint8) CLAMP(val, 0, 0xff);
957 if (PREF_CHANGED(HTTP_PREF("version"))) {
958 nsXPIDLCString httpVersion;
959 prefs->GetCharPref(HTTP_PREF("version"), getter_Copies(httpVersion));
960 if (httpVersion) {
961 if (!PL_strcmp(httpVersion, "1.1"))
962 mHttpVersion = NS_HTTP_VERSION_1_1;
963 else if (!PL_strcmp(httpVersion, "0.9"))
964 mHttpVersion = NS_HTTP_VERSION_0_9;
965 else
966 mHttpVersion = NS_HTTP_VERSION_1_0;
970 if (PREF_CHANGED(HTTP_PREF("proxy.version"))) {
971 nsXPIDLCString httpVersion;
972 prefs->GetCharPref(HTTP_PREF("proxy.version"), getter_Copies(httpVersion));
973 if (httpVersion) {
974 if (!PL_strcmp(httpVersion, "1.1"))
975 mProxyHttpVersion = NS_HTTP_VERSION_1_1;
976 else
977 mProxyHttpVersion = NS_HTTP_VERSION_1_0;
978 // it does not make sense to issue a HTTP/0.9 request to a proxy server
982 PRBool cVar = PR_FALSE;
984 if (PREF_CHANGED(HTTP_PREF("keep-alive"))) {
985 rv = prefs->GetBoolPref(HTTP_PREF("keep-alive"), &cVar);
986 if (NS_SUCCEEDED(rv)) {
987 if (cVar)
988 mCapabilities |= NS_HTTP_ALLOW_KEEPALIVE;
989 else
990 mCapabilities &= ~NS_HTTP_ALLOW_KEEPALIVE;
994 if (PREF_CHANGED(HTTP_PREF("proxy.keep-alive"))) {
995 rv = prefs->GetBoolPref(HTTP_PREF("proxy.keep-alive"), &cVar);
996 if (NS_SUCCEEDED(rv)) {
997 if (cVar)
998 mProxyCapabilities |= NS_HTTP_ALLOW_KEEPALIVE;
999 else
1000 mProxyCapabilities &= ~NS_HTTP_ALLOW_KEEPALIVE;
1004 if (PREF_CHANGED(HTTP_PREF("pipelining"))) {
1005 rv = prefs->GetBoolPref(HTTP_PREF("pipelining"), &cVar);
1006 if (NS_SUCCEEDED(rv)) {
1007 if (cVar)
1008 mCapabilities |= NS_HTTP_ALLOW_PIPELINING;
1009 else
1010 mCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
1014 if (PREF_CHANGED(HTTP_PREF("pipelining.maxrequests"))) {
1015 rv = prefs->GetIntPref(HTTP_PREF("pipelining.maxrequests"), &val);
1016 if (NS_SUCCEEDED(rv)) {
1017 mMaxPipelinedRequests = CLAMP(val, 1, NS_HTTP_MAX_PIPELINED_REQUESTS);
1018 if (mConnMgr)
1019 mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PIPELINED_REQUESTS,
1020 mMaxPipelinedRequests);
1024 if (PREF_CHANGED(HTTP_PREF("pipelining.ssl"))) {
1025 rv = prefs->GetBoolPref(HTTP_PREF("pipelining.ssl"), &cVar);
1026 if (NS_SUCCEEDED(rv))
1027 mPipeliningOverSSL = cVar;
1030 if (PREF_CHANGED(HTTP_PREF("proxy.pipelining"))) {
1031 rv = prefs->GetBoolPref(HTTP_PREF("proxy.pipelining"), &cVar);
1032 if (NS_SUCCEEDED(rv)) {
1033 if (cVar)
1034 mProxyCapabilities |= NS_HTTP_ALLOW_PIPELINING;
1035 else
1036 mProxyCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
1040 if (PREF_CHANGED(HTTP_PREF("sendSecureXSiteReferrer"))) {
1041 rv = prefs->GetBoolPref(HTTP_PREF("sendSecureXSiteReferrer"), &cVar);
1042 if (NS_SUCCEEDED(rv))
1043 mSendSecureXSiteReferrer = cVar;
1046 if (PREF_CHANGED(HTTP_PREF("accept.default"))) {
1047 nsXPIDLCString accept;
1048 rv = prefs->GetCharPref(HTTP_PREF("accept.default"),
1049 getter_Copies(accept));
1050 if (NS_SUCCEEDED(rv))
1051 SetAccept(accept);
1054 if (PREF_CHANGED(HTTP_PREF("accept-encoding"))) {
1055 nsXPIDLCString acceptEncodings;
1056 rv = prefs->GetCharPref(HTTP_PREF("accept-encoding"),
1057 getter_Copies(acceptEncodings));
1058 if (NS_SUCCEEDED(rv))
1059 SetAcceptEncodings(acceptEncodings);
1062 if (PREF_CHANGED(HTTP_PREF("use-cache"))) {
1063 rv = prefs->GetBoolPref(HTTP_PREF("use-cache"), &cVar);
1064 if (NS_SUCCEEDED(rv)) {
1065 mUseCache = cVar;
1069 if (PREF_CHANGED(HTTP_PREF("default-socket-type"))) {
1070 nsXPIDLCString sval;
1071 rv = prefs->GetCharPref(HTTP_PREF("default-socket-type"),
1072 getter_Copies(sval));
1073 if (NS_SUCCEEDED(rv)) {
1074 if (sval.IsEmpty())
1075 mDefaultSocketType.Adopt(0);
1076 else {
1077 // verify that this socket type is actually valid
1078 nsCOMPtr<nsISocketProviderService> sps(
1079 do_GetService(kSocketProviderServiceCID));
1080 if (sps) {
1081 nsCOMPtr<nsISocketProvider> sp;
1082 rv = sps->GetSocketProvider(sval, getter_AddRefs(sp));
1083 if (NS_SUCCEEDED(rv)) {
1084 // OK, this looks like a valid socket provider.
1085 mDefaultSocketType.Assign(sval);
1092 // enable Persistent caching for HTTPS - bug#205921
1093 if (PREF_CHANGED(BROWSER_PREF("disk_cache_ssl"))) {
1094 cVar = PR_FALSE;
1095 rv = prefs->GetBoolPref(BROWSER_PREF("disk_cache_ssl"), &cVar);
1096 if (NS_SUCCEEDED(rv))
1097 mEnablePersistentHttpsCaching = cVar;
1100 if (PREF_CHANGED(HTTP_PREF("phishy-userpass-length"))) {
1101 rv = prefs->GetIntPref(HTTP_PREF("phishy-userpass-length"), &val);
1102 if (NS_SUCCEEDED(rv))
1103 mPhishyUserPassLength = (PRUint8) CLAMP(val, 0, 0xff);
1107 // INTL options
1110 if (PREF_CHANGED(INTL_ACCEPT_LANGUAGES)) {
1111 nsCOMPtr<nsIPrefLocalizedString> pls;
1112 prefs->GetComplexValue(INTL_ACCEPT_LANGUAGES,
1113 NS_GET_IID(nsIPrefLocalizedString),
1114 getter_AddRefs(pls));
1115 if (pls) {
1116 nsXPIDLString uval;
1117 pls->ToString(getter_Copies(uval));
1118 if (uval)
1119 SetAcceptLanguages(NS_ConvertUTF16toUTF8(uval).get());
1123 if (PREF_CHANGED(INTL_ACCEPT_CHARSET)) {
1124 nsCOMPtr<nsIPrefLocalizedString> pls;
1125 prefs->GetComplexValue(INTL_ACCEPT_CHARSET,
1126 NS_GET_IID(nsIPrefLocalizedString),
1127 getter_AddRefs(pls));
1128 if (pls) {
1129 nsXPIDLString uval;
1130 pls->ToString(getter_Copies(uval));
1131 if (uval)
1132 SetAcceptCharsets(NS_ConvertUTF16toUTF8(uval).get());
1137 // IDN options
1140 if (PREF_CHANGED(NETWORK_ENABLEIDN)) {
1141 PRBool enableIDN = PR_FALSE;
1142 prefs->GetBoolPref(NETWORK_ENABLEIDN, &enableIDN);
1143 // No locking is required here since this method runs in the main
1144 // UI thread, and so do all the methods in nsHttpChannel.cpp
1145 // (mIDNConverter is used by nsHttpChannel)
1146 if (enableIDN && !mIDNConverter) {
1147 mIDNConverter = do_GetService(NS_IDNSERVICE_CONTRACTID);
1148 NS_ASSERTION(mIDNConverter, "idnSDK not installed");
1150 else if (!enableIDN && mIDNConverter)
1151 mIDNConverter = nsnull;
1154 #undef PREF_CHANGED
1155 #undef MULTI_PREF_CHANGED
1159 * Allocates a C string into that contains a ISO 639 language list
1160 * notated with HTTP "q" values for output with a HTTP Accept-Language
1161 * header. Previous q values will be stripped because the order of
1162 * the langs imply the q value. The q values are calculated by dividing
1163 * 1.0 amongst the number of languages present.
1165 * Ex: passing: "en, ja"
1166 * returns: "en,ja;q=0.5"
1168 * passing: "en, ja, fr_CA"
1169 * returns: "en,ja;q=0.7,fr_CA;q=0.3"
1171 static nsresult
1172 PrepareAcceptLanguages(const char *i_AcceptLanguages, nsACString &o_AcceptLanguages)
1174 if (!i_AcceptLanguages)
1175 return NS_OK;
1177 PRUint32 n, size, wrote;
1178 double q, dec;
1179 char *p, *p2, *token, *q_Accept, *o_Accept;
1180 const char *comma;
1181 PRInt32 available;
1183 o_Accept = nsCRT::strdup(i_AcceptLanguages);
1184 if (!o_Accept)
1185 return NS_ERROR_OUT_OF_MEMORY;
1186 for (p = o_Accept, n = size = 0; '\0' != *p; p++) {
1187 if (*p == ',') n++;
1188 size++;
1191 available = size + ++n * 11 + 1;
1192 q_Accept = new char[available];
1193 if (!q_Accept) {
1194 nsCRT::free(o_Accept);
1195 return NS_ERROR_OUT_OF_MEMORY;
1197 *q_Accept = '\0';
1198 q = 1.0;
1199 dec = q / (double) n;
1200 n = 0;
1201 p2 = q_Accept;
1202 for (token = nsCRT::strtok(o_Accept, ",", &p);
1203 token != (char *) 0;
1204 token = nsCRT::strtok(p, ",", &p))
1206 token = net_FindCharNotInSet(token, HTTP_LWS);
1207 char* trim;
1208 trim = net_FindCharInSet(token, ";" HTTP_LWS);
1209 if (trim != (char*)0) // remove "; q=..." if present
1210 *trim = '\0';
1212 if (*token != '\0') {
1213 comma = n++ != 0 ? "," : ""; // delimiter if not first item
1214 PRUint32 u = QVAL_TO_UINT(q);
1215 if (u < 10)
1216 wrote = PR_snprintf(p2, available, "%s%s;q=0.%u", comma, token, u);
1217 else
1218 wrote = PR_snprintf(p2, available, "%s%s", comma, token);
1219 q -= dec;
1220 p2 += wrote;
1221 available -= wrote;
1222 NS_ASSERTION(available > 0, "allocated string not long enough");
1225 nsCRT::free(o_Accept);
1227 o_AcceptLanguages.Assign((const char *) q_Accept);
1228 delete [] q_Accept;
1230 return NS_OK;
1233 nsresult
1234 nsHttpHandler::SetAcceptLanguages(const char *aAcceptLanguages)
1236 nsCAutoString buf;
1237 nsresult rv = PrepareAcceptLanguages(aAcceptLanguages, buf);
1238 if (NS_SUCCEEDED(rv))
1239 mAcceptLanguages.Assign(buf);
1240 return rv;
1244 * Allocates a C string into that contains a character set/encoding list
1245 * notated with HTTP "q" values for output with a HTTP Accept-Charset
1246 * header. If the UTF-8 character set is not present, it will be added.
1247 * If a wildcard catch-all is not present, it will be added. If more than
1248 * one charset is set (as of 2001-02-07, only one is used), they will be
1249 * comma delimited and with q values set for each charset in decending order.
1251 * Ex: passing: "euc-jp"
1252 * returns: "euc-jp,utf-8;q=0.6,*;q=0.6"
1254 * passing: "UTF-8"
1255 * returns: "UTF-8, *"
1257 static nsresult
1258 PrepareAcceptCharsets(const char *i_AcceptCharset, nsACString &o_AcceptCharset)
1260 PRUint32 n, size, wrote, u;
1261 PRInt32 available;
1262 double q, dec;
1263 char *p, *p2, *token, *q_Accept, *o_Accept;
1264 const char *acceptable, *comma;
1265 PRBool add_utf = PR_FALSE;
1266 PRBool add_asterisk = PR_FALSE;
1268 if (!i_AcceptCharset)
1269 acceptable = "";
1270 else
1271 acceptable = i_AcceptCharset;
1272 o_Accept = nsCRT::strdup(acceptable);
1273 if (nsnull == o_Accept)
1274 return NS_ERROR_OUT_OF_MEMORY;
1275 for (p = o_Accept, n = size = 0; '\0' != *p; p++) {
1276 if (*p == ',') n++;
1277 size++;
1280 // only add "utf-8" and "*" to the list if they aren't
1281 // already specified.
1283 if (PL_strcasestr(acceptable, "utf-8") == NULL) {
1284 n++;
1285 add_utf = PR_TRUE;
1287 if (PL_strstr(acceptable, "*") == NULL) {
1288 n++;
1289 add_asterisk = PR_TRUE;
1292 available = size + ++n * 11 + 1;
1293 q_Accept = new char[available];
1294 if ((char *) 0 == q_Accept)
1295 return NS_ERROR_OUT_OF_MEMORY;
1296 *q_Accept = '\0';
1297 q = 1.0;
1298 dec = q / (double) n;
1299 n = 0;
1300 p2 = q_Accept;
1301 for (token = nsCRT::strtok(o_Accept, ",", &p);
1302 token != (char *) 0;
1303 token = nsCRT::strtok(p, ",", &p)) {
1304 token = net_FindCharNotInSet(token, HTTP_LWS);
1305 char* trim;
1306 trim = net_FindCharInSet(token, ";" HTTP_LWS);
1307 if (trim != (char*)0) // remove "; q=..." if present
1308 *trim = '\0';
1310 if (*token != '\0') {
1311 comma = n++ != 0 ? "," : ""; // delimiter if not first item
1312 u = QVAL_TO_UINT(q);
1313 if (u < 10)
1314 wrote = PR_snprintf(p2, available, "%s%s;q=0.%u", comma, token, u);
1315 else
1316 wrote = PR_snprintf(p2, available, "%s%s", comma, token);
1317 q -= dec;
1318 p2 += wrote;
1319 available -= wrote;
1320 NS_ASSERTION(available > 0, "allocated string not long enough");
1323 if (add_utf) {
1324 comma = n++ != 0 ? "," : ""; // delimiter if not first item
1325 u = QVAL_TO_UINT(q);
1326 if (u < 10)
1327 wrote = PR_snprintf(p2, available, "%sutf-8;q=0.%u", comma, u);
1328 else
1329 wrote = PR_snprintf(p2, available, "%sutf-8", comma);
1330 q -= dec;
1331 p2 += wrote;
1332 available -= wrote;
1333 NS_ASSERTION(available > 0, "allocated string not long enough");
1335 if (add_asterisk) {
1336 comma = n++ != 0 ? "," : ""; // delimiter if not first item
1338 // keep q of "*" equal to the lowest q value
1339 // in the event of a tie between the q of "*" and a non-wildcard
1340 // the non-wildcard always receives preference.
1342 q += dec;
1343 u = QVAL_TO_UINT(q);
1344 if (u < 10)
1345 wrote = PR_snprintf(p2, available, "%s*;q=0.%u", comma, u);
1346 else
1347 wrote = PR_snprintf(p2, available, "%s*", comma);
1348 available -= wrote;
1349 p2 += wrote;
1350 NS_ASSERTION(available > 0, "allocated string not long enough");
1352 nsCRT::free(o_Accept);
1354 // change alloc from C++ new/delete to nsCRT::strdup's way
1355 o_AcceptCharset.Assign(q_Accept);
1356 #if defined DEBUG_havill
1357 printf("Accept-Charset: %s\n", q_Accept);
1358 #endif
1359 delete [] q_Accept;
1360 return NS_OK;
1363 nsresult
1364 nsHttpHandler::SetAcceptCharsets(const char *aAcceptCharsets)
1366 nsCString buf;
1367 nsresult rv = PrepareAcceptCharsets(aAcceptCharsets, buf);
1368 if (NS_SUCCEEDED(rv))
1369 mAcceptCharsets.Assign(buf);
1370 return rv;
1373 nsresult
1374 nsHttpHandler::SetAccept(const char *aAccept)
1376 mAccept = aAccept;
1377 return NS_OK;
1380 nsresult
1381 nsHttpHandler::SetAcceptEncodings(const char *aAcceptEncodings)
1383 mAcceptEncodings = aAcceptEncodings;
1384 return NS_OK;
1387 //-----------------------------------------------------------------------------
1388 // nsHttpHandler::nsISupports
1389 //-----------------------------------------------------------------------------
1391 NS_IMPL_THREADSAFE_ISUPPORTS5(nsHttpHandler,
1392 nsIHttpProtocolHandler,
1393 nsIProxiedProtocolHandler,
1394 nsIProtocolHandler,
1395 nsIObserver,
1396 nsISupportsWeakReference)
1398 //-----------------------------------------------------------------------------
1399 // nsHttpHandler::nsIProtocolHandler
1400 //-----------------------------------------------------------------------------
1402 NS_IMETHODIMP
1403 nsHttpHandler::GetScheme(nsACString &aScheme)
1405 aScheme.AssignLiteral("http");
1406 return NS_OK;
1409 NS_IMETHODIMP
1410 nsHttpHandler::GetDefaultPort(PRInt32 *result)
1412 *result = NS_HTTP_DEFAULT_PORT;
1413 return NS_OK;
1416 NS_IMETHODIMP
1417 nsHttpHandler::GetProtocolFlags(PRUint32 *result)
1419 *result = URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP |
1420 URI_LOADABLE_BY_ANYONE;
1421 return NS_OK;
1424 NS_IMETHODIMP
1425 nsHttpHandler::NewURI(const nsACString &aSpec,
1426 const char *aCharset,
1427 nsIURI *aBaseURI,
1428 nsIURI **aURI)
1430 LOG(("nsHttpHandler::NewURI\n"));
1431 return ::NewURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT, aURI);
1434 NS_IMETHODIMP
1435 nsHttpHandler::NewChannel(nsIURI *uri, nsIChannel **result)
1437 LOG(("nsHttpHandler::NewChannel\n"));
1439 NS_ENSURE_ARG_POINTER(uri);
1440 NS_ENSURE_ARG_POINTER(result);
1442 PRBool isHttp = PR_FALSE, isHttps = PR_FALSE;
1444 // Verify that we have been given a valid scheme
1445 nsresult rv = uri->SchemeIs("http", &isHttp);
1446 if (NS_FAILED(rv)) return rv;
1447 if (!isHttp) {
1448 rv = uri->SchemeIs("https", &isHttps);
1449 if (NS_FAILED(rv)) return rv;
1450 if (!isHttps) {
1451 NS_WARNING("Invalid URI scheme");
1452 return NS_ERROR_UNEXPECTED;
1456 return NewProxiedChannel(uri, nsnull, result);
1459 NS_IMETHODIMP
1460 nsHttpHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
1462 // don't override anything.
1463 *_retval = PR_FALSE;
1464 return NS_OK;
1467 //-----------------------------------------------------------------------------
1468 // nsHttpHandler::nsIProxiedProtocolHandler
1469 //-----------------------------------------------------------------------------
1471 NS_IMETHODIMP
1472 nsHttpHandler::NewProxiedChannel(nsIURI *uri,
1473 nsIProxyInfo* givenProxyInfo,
1474 nsIChannel **result)
1476 nsHttpChannel *httpChannel = nsnull;
1478 LOG(("nsHttpHandler::NewProxiedChannel [proxyInfo=%p]\n",
1479 givenProxyInfo));
1481 nsCOMPtr<nsProxyInfo> proxyInfo;
1482 if (givenProxyInfo) {
1483 proxyInfo = do_QueryInterface(givenProxyInfo);
1484 NS_ENSURE_ARG(proxyInfo);
1487 PRBool https;
1488 nsresult rv = uri->SchemeIs("https", &https);
1489 if (NS_FAILED(rv))
1490 return rv;
1492 NS_NEWXPCOM(httpChannel, nsHttpChannel);
1493 if (!httpChannel)
1494 return NS_ERROR_OUT_OF_MEMORY;
1495 NS_ADDREF(httpChannel);
1497 // select proxy caps if using a non-transparent proxy. SSL tunneling
1498 // should not use proxy settings.
1499 PRInt8 caps;
1500 if (proxyInfo && !nsCRT::strcmp(proxyInfo->Type(), "http") && !https)
1501 caps = mProxyCapabilities;
1502 else
1503 caps = mCapabilities;
1505 if (https) {
1506 // enable pipelining over SSL if requested
1507 if (mPipeliningOverSSL)
1508 caps |= NS_HTTP_ALLOW_PIPELINING;
1510 // HACK: make sure PSM gets initialized on the main thread.
1511 nsCOMPtr<nsISocketProviderService> spserv =
1512 do_GetService(kSocketProviderServiceCID);
1513 if (spserv) {
1514 nsCOMPtr<nsISocketProvider> provider;
1515 spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
1519 rv = httpChannel->Init(uri, caps, proxyInfo);
1521 if (NS_FAILED(rv)) {
1522 NS_RELEASE(httpChannel);
1523 return rv;
1526 *result = httpChannel;
1527 return NS_OK;
1530 //-----------------------------------------------------------------------------
1531 // nsHttpHandler::nsIHttpProtocolHandler
1532 //-----------------------------------------------------------------------------
1534 NS_IMETHODIMP
1535 nsHttpHandler::GetUserAgent(nsACString &value)
1537 value = UserAgent();
1538 return NS_OK;
1541 NS_IMETHODIMP
1542 nsHttpHandler::GetAppName(nsACString &value)
1544 value = mAppName;
1545 return NS_OK;
1548 NS_IMETHODIMP
1549 nsHttpHandler::GetAppVersion(nsACString &value)
1551 value = mAppVersion;
1552 return NS_OK;
1555 NS_IMETHODIMP
1556 nsHttpHandler::GetVendor(nsACString &value)
1558 value = mVendor;
1559 return NS_OK;
1561 NS_IMETHODIMP
1562 nsHttpHandler::SetVendor(const nsACString &value)
1564 mVendor = value;
1565 mUserAgentIsDirty = PR_TRUE;
1566 return NS_OK;
1569 NS_IMETHODIMP
1570 nsHttpHandler::GetVendorSub(nsACString &value)
1572 value = mVendorSub;
1573 return NS_OK;
1575 NS_IMETHODIMP
1576 nsHttpHandler::SetVendorSub(const nsACString &value)
1578 mVendorSub = value;
1579 mUserAgentIsDirty = PR_TRUE;
1580 return NS_OK;
1583 NS_IMETHODIMP
1584 nsHttpHandler::GetVendorComment(nsACString &value)
1586 value = mVendorComment;
1587 return NS_OK;
1589 NS_IMETHODIMP
1590 nsHttpHandler::SetVendorComment(const nsACString &value)
1592 mVendorComment = value;
1593 mUserAgentIsDirty = PR_TRUE;
1594 return NS_OK;
1597 NS_IMETHODIMP
1598 nsHttpHandler::GetProduct(nsACString &value)
1600 value = mProduct;
1601 return NS_OK;
1603 NS_IMETHODIMP
1604 nsHttpHandler::SetProduct(const nsACString &value)
1606 mProduct = value;
1607 mUserAgentIsDirty = PR_TRUE;
1608 return NS_OK;
1611 NS_IMETHODIMP
1612 nsHttpHandler::GetProductSub(nsACString &value)
1614 value = mProductSub;
1615 return NS_OK;
1617 NS_IMETHODIMP
1618 nsHttpHandler::SetProductSub(const nsACString &value)
1620 mProductSub = value;
1621 mUserAgentIsDirty = PR_TRUE;
1622 return NS_OK;
1625 NS_IMETHODIMP
1626 nsHttpHandler::GetProductComment(nsACString &value)
1628 value = mProductComment;
1629 return NS_OK;
1631 NS_IMETHODIMP
1632 nsHttpHandler::SetProductComment(const nsACString &value)
1634 mProductComment = value;
1635 mUserAgentIsDirty = PR_TRUE;
1636 return NS_OK;
1639 NS_IMETHODIMP
1640 nsHttpHandler::GetPlatform(nsACString &value)
1642 value = mPlatform;
1643 return NS_OK;
1646 NS_IMETHODIMP
1647 nsHttpHandler::GetOscpu(nsACString &value)
1649 value = mOscpu;
1650 return NS_OK;
1653 NS_IMETHODIMP
1654 nsHttpHandler::GetLanguage(nsACString &value)
1656 value = mLanguage;
1657 return NS_OK;
1659 NS_IMETHODIMP
1660 nsHttpHandler::SetLanguage(const nsACString &value)
1662 mLanguage = value;
1663 mUserAgentIsDirty = PR_TRUE;
1664 return NS_OK;
1667 NS_IMETHODIMP
1668 nsHttpHandler::GetMisc(nsACString &value)
1670 value = mMisc;
1671 return NS_OK;
1673 NS_IMETHODIMP
1674 nsHttpHandler::SetMisc(const nsACString &value)
1676 mMisc = value;
1677 mUserAgentIsDirty = PR_TRUE;
1678 return NS_OK;
1681 //-----------------------------------------------------------------------------
1682 // nsHttpHandler::nsIObserver
1683 //-----------------------------------------------------------------------------
1685 NS_IMETHODIMP
1686 nsHttpHandler::Observe(nsISupports *subject,
1687 const char *topic,
1688 const PRUnichar *data)
1690 LOG(("nsHttpHandler::Observe [topic=\"%s\"]\n", topic));
1692 if (strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
1693 nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(subject);
1694 if (prefBranch)
1695 PrefsChanged(prefBranch, NS_ConvertUTF16toUTF8(data).get());
1697 else if (strcmp(topic, "profile-change-net-teardown") == 0 ||
1698 strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
1700 // kill off the "prune dead connections" timer
1701 StopPruneDeadConnectionsTimer();
1703 // clear cache of all authentication credentials.
1704 mAuthCache.ClearAll();
1706 // ensure connection manager is shutdown
1707 if (mConnMgr)
1708 mConnMgr->Shutdown();
1710 // need to reset the session start time since cache validation may
1711 // depend on this value.
1712 mSessionStartTime = NowInSeconds();
1714 else if (strcmp(topic, "profile-change-net-restore") == 0) {
1715 // initialize connection manager
1716 InitConnectionMgr();
1718 // restart the "prune dead connections" timer
1719 StartPruneDeadConnectionsTimer();
1721 else if (strcmp(topic, "timer-callback") == 0) {
1722 // prune dead connections
1723 #ifdef DEBUG
1724 nsCOMPtr<nsITimer> timer = do_QueryInterface(subject);
1725 NS_ASSERTION(timer == mTimer, "unexpected timer-callback");
1726 #endif
1727 if (mConnMgr)
1728 mConnMgr->PruneDeadConnections();
1731 return NS_OK;
1734 //-----------------------------------------------------------------------------
1735 // nsHttpsHandler implementation
1736 //-----------------------------------------------------------------------------
1738 NS_IMPL_THREADSAFE_ISUPPORTS4(nsHttpsHandler,
1739 nsIHttpProtocolHandler,
1740 nsIProxiedProtocolHandler,
1741 nsIProtocolHandler,
1742 nsISupportsWeakReference)
1744 nsresult
1745 nsHttpsHandler::Init()
1747 nsCOMPtr<nsIProtocolHandler> httpHandler(
1748 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http"));
1749 NS_ASSERTION(httpHandler.get() != nsnull, "no http handler?");
1750 return NS_OK;
1753 NS_IMETHODIMP
1754 nsHttpsHandler::GetScheme(nsACString &aScheme)
1756 aScheme.AssignLiteral("https");
1757 return NS_OK;
1760 NS_IMETHODIMP
1761 nsHttpsHandler::GetDefaultPort(PRInt32 *aPort)
1763 *aPort = NS_HTTPS_DEFAULT_PORT;
1764 return NS_OK;
1767 NS_IMETHODIMP
1768 nsHttpsHandler::GetProtocolFlags(PRUint32 *aProtocolFlags)
1770 return gHttpHandler->GetProtocolFlags(aProtocolFlags);
1773 NS_IMETHODIMP
1774 nsHttpsHandler::NewURI(const nsACString &aSpec,
1775 const char *aOriginCharset,
1776 nsIURI *aBaseURI,
1777 nsIURI **_retval)
1779 return ::NewURI(aSpec, aOriginCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT, _retval);
1782 NS_IMETHODIMP
1783 nsHttpsHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
1785 return gHttpHandler->NewChannel(aURI, _retval);
1788 NS_IMETHODIMP
1789 nsHttpsHandler::AllowPort(PRInt32 aPort, const char *aScheme, PRBool *_retval)
1791 // don't override anything.
1792 *_retval = PR_FALSE;
1793 return NS_OK;