1 /* vim:set ts=4 sw=4 sts=4 et cin: */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2002
20 * the Initial Developer. All Rights Reserved.
23 * Darin Fisher <darin@netscape.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsHttpConnectionMgr.h"
40 #include "nsHttpConnection.h"
41 #include "nsHttpPipeline.h"
42 #include "nsHttpHandler.h"
43 #include "nsAutoLock.h"
47 #include "nsIServiceManager.h"
49 // defined by the socket transport service while active
50 extern PRThread
*gSocketThread
;
52 static NS_DEFINE_CID(kSocketTransportServiceCID
, NS_SOCKETTRANSPORTSERVICE_CID
);
54 //-----------------------------------------------------------------------------
57 InsertTransactionSorted(nsVoidArray
&pendingQ
, nsHttpTransaction
*trans
)
59 // insert into queue with smallest valued number first. search in reverse
60 // order under the assumption that many of the existing transactions will
61 // have the same priority (usually 0).
63 for (PRInt32 i
=pendingQ
.Count()-1; i
>=0; --i
) {
64 nsHttpTransaction
*t
= (nsHttpTransaction
*) pendingQ
[i
];
65 if (trans
->Priority() >= t
->Priority()) {
66 pendingQ
.InsertElementAt(trans
, i
+1);
70 pendingQ
.InsertElementAt(trans
, 0);
73 //-----------------------------------------------------------------------------
75 nsHttpConnectionMgr::nsHttpConnectionMgr()
77 , mMonitor(nsAutoMonitor::NewMonitor("nsHttpConnectionMgr"))
80 , mMaxConnsPerProxy(0)
81 , mMaxPersistConnsPerHost(0)
82 , mMaxPersistConnsPerProxy(0)
86 LOG(("Creating nsHttpConnectionMgr @%x\n", this));
89 nsHttpConnectionMgr::~nsHttpConnectionMgr()
91 LOG(("Destroying nsHttpConnectionMgr @%x\n", this));
94 nsAutoMonitor::DestroyMonitor(mMonitor
);
98 nsHttpConnectionMgr::Init(PRUint16 maxConns
,
99 PRUint16 maxConnsPerHost
,
100 PRUint16 maxConnsPerProxy
,
101 PRUint16 maxPersistConnsPerHost
,
102 PRUint16 maxPersistConnsPerProxy
,
103 PRUint16 maxRequestDelay
,
104 PRUint16 maxPipelinedRequests
)
106 LOG(("nsHttpConnectionMgr::Init\n"));
109 nsCOMPtr
<nsIEventTarget
> sts
= do_GetService(kSocketTransportServiceCID
, &rv
);
110 if (NS_FAILED(rv
)) return rv
;
112 nsAutoMonitor
mon(mMonitor
);
114 // do nothing if already initialized
115 if (mSocketThreadTarget
)
118 // no need to do any special synchronization here since there cannot be
119 // any activity on the socket thread (because Shutdown is synchronous).
120 mMaxConns
= maxConns
;
121 mMaxConnsPerHost
= maxConnsPerHost
;
122 mMaxConnsPerProxy
= maxConnsPerProxy
;
123 mMaxPersistConnsPerHost
= maxPersistConnsPerHost
;
124 mMaxPersistConnsPerProxy
= maxPersistConnsPerProxy
;
125 mMaxRequestDelay
= maxRequestDelay
;
126 mMaxPipelinedRequests
= maxPipelinedRequests
;
128 mSocketThreadTarget
= sts
;
133 nsHttpConnectionMgr::Shutdown()
135 LOG(("nsHttpConnectionMgr::Shutdown\n"));
137 nsAutoMonitor
mon(mMonitor
);
139 // do nothing if already shutdown
140 if (!mSocketThreadTarget
)
143 nsresult rv
= PostEvent(&nsHttpConnectionMgr::OnMsgShutdown
);
145 // release our reference to the STS to prevent further events
146 // from being posted. this is how we indicate that we are
148 mSocketThreadTarget
= 0;
151 NS_WARNING("unable to post SHUTDOWN message\n");
155 // wait for shutdown event to complete
161 nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler
, PRInt32 iparam
, void *vparam
)
163 nsAutoMonitor
mon(mMonitor
);
166 if (!mSocketThreadTarget
) {
167 NS_WARNING("cannot post event if not initialized");
168 rv
= NS_ERROR_NOT_INITIALIZED
;
171 nsRefPtr
<nsIRunnable
> event
= new nsConnEvent(this, handler
, iparam
, vparam
);
173 rv
= NS_ERROR_OUT_OF_MEMORY
;
175 rv
= mSocketThreadTarget
->Dispatch(event
, NS_DISPATCH_NORMAL
);
180 //-----------------------------------------------------------------------------
183 nsHttpConnectionMgr::AddTransaction(nsHttpTransaction
*trans
, PRInt32 priority
)
185 LOG(("nsHttpConnectionMgr::AddTransaction [trans=%x %d]\n", trans
, priority
));
188 nsresult rv
= PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction
, priority
, trans
);
195 nsHttpConnectionMgr::RescheduleTransaction(nsHttpTransaction
*trans
, PRInt32 priority
)
197 LOG(("nsHttpConnectionMgr::RescheduleTransaction [trans=%x %d]\n", trans
, priority
));
200 nsresult rv
= PostEvent(&nsHttpConnectionMgr::OnMsgReschedTransaction
, priority
, trans
);
207 nsHttpConnectionMgr::CancelTransaction(nsHttpTransaction
*trans
, nsresult reason
)
209 LOG(("nsHttpConnectionMgr::CancelTransaction [trans=%x reason=%x]\n", trans
, reason
));
212 nsresult rv
= PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction
, reason
, trans
);
219 nsHttpConnectionMgr::PruneDeadConnections()
221 return PostEvent(&nsHttpConnectionMgr::OnMsgPruneDeadConnections
);
225 nsHttpConnectionMgr::GetSocketThreadTarget(nsIEventTarget
**target
)
227 nsAutoMonitor
mon(mMonitor
);
228 NS_IF_ADDREF(*target
= mSocketThreadTarget
);
233 nsHttpConnectionMgr::AddTransactionToPipeline(nsHttpPipeline
*pipeline
)
235 LOG(("nsHttpConnectionMgr::AddTransactionToPipeline [pipeline=%x]\n", pipeline
));
237 NS_ASSERTION(PR_GetCurrentThread() == gSocketThread
, "wrong thread");
239 nsRefPtr
<nsHttpConnectionInfo
> ci
;
240 pipeline
->GetConnectionInfo(getter_AddRefs(ci
));
242 nsCStringKey
key(ci
->HashKey());
243 nsConnectionEntry
*ent
= (nsConnectionEntry
*) mCT
.Get(&key
);
245 // search for another request to pipeline...
246 PRInt32 i
, count
= ent
->mPendingQ
.Count();
247 for (i
=0; i
<count
; ++i
) {
248 nsHttpTransaction
*trans
= (nsHttpTransaction
*) ent
->mPendingQ
[i
];
249 if (trans
->Caps() & NS_HTTP_ALLOW_PIPELINING
) {
250 pipeline
->AddTransaction(trans
);
252 // remove transaction from pending queue
253 ent
->mPendingQ
.RemoveElementAt(i
);
263 nsHttpConnectionMgr::ReclaimConnection(nsHttpConnection
*conn
)
265 LOG(("nsHttpConnectionMgr::ReclaimConnection [conn=%x]\n", conn
));
268 nsresult rv
= PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection
, 0, conn
);
275 nsHttpConnectionMgr::UpdateParam(nsParamName name
, PRUint16 value
)
277 PRUint32 param
= (PRUint32(name
) << 16) | PRUint32(value
);
278 return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateParam
, 0, (void *) param
);
282 nsHttpConnectionMgr::ProcessPendingQ(nsHttpConnectionInfo
*ci
)
284 LOG(("nsHttpConnectionMgr::ProcessPendingQ [ci=%s]\n", ci
->HashKey().get()));
287 nsresult rv
= PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ
, 0, ci
);
293 //-----------------------------------------------------------------------------
294 // enumeration callbacks
297 nsHttpConnectionMgr::ProcessOneTransactionCB(nsHashKey
*key
, void *data
, void *closure
)
299 nsHttpConnectionMgr
*self
= (nsHttpConnectionMgr
*) closure
;
300 nsConnectionEntry
*ent
= (nsConnectionEntry
*) data
;
302 if (self
->ProcessPendingQForEntry(ent
))
303 return kHashEnumerateStop
;
305 return kHashEnumerateNext
;
309 nsHttpConnectionMgr::PurgeOneIdleConnectionCB(nsHashKey
*key
, void *data
, void *closure
)
311 nsHttpConnectionMgr
*self
= (nsHttpConnectionMgr
*) closure
;
312 nsConnectionEntry
*ent
= (nsConnectionEntry
*) data
;
314 if (ent
->mIdleConns
.Count() > 0) {
315 nsHttpConnection
*conn
= (nsHttpConnection
*) ent
->mIdleConns
[0];
316 ent
->mIdleConns
.RemoveElementAt(0);
317 conn
->Close(NS_ERROR_ABORT
);
319 self
->mNumIdleConns
--;
320 return kHashEnumerateStop
;
323 return kHashEnumerateNext
;
327 nsHttpConnectionMgr::PruneDeadConnectionsCB(nsHashKey
*key
, void *data
, void *closure
)
329 nsHttpConnectionMgr
*self
= (nsHttpConnectionMgr
*) closure
;
330 nsConnectionEntry
*ent
= (nsConnectionEntry
*) data
;
332 LOG((" pruning [ci=%s]\n", ent
->mConnInfo
->HashKey().get()));
334 PRInt32 count
= ent
->mIdleConns
.Count();
336 for (PRInt32 i
=count
-1; i
>=0; --i
) {
337 nsHttpConnection
*conn
= (nsHttpConnection
*) ent
->mIdleConns
[i
];
338 if (!conn
->CanReuse()) {
339 ent
->mIdleConns
.RemoveElementAt(i
);
340 conn
->Close(NS_ERROR_ABORT
);
342 self
->mNumIdleConns
--;
348 count
= ent
->mActiveConns
.Count();
350 for (PRInt32 i
=count
-1; i
>=0; --i
) {
351 nsHttpConnection
*conn
= (nsHttpConnection
*) ent
->mActiveConns
[i
];
352 LOG((" active conn [%x] with trans [%x]\n", conn
, conn
->Transaction()));
357 // if this entry is empty, then we can remove it.
358 if (ent
->mIdleConns
.Count() == 0 &&
359 ent
->mActiveConns
.Count() == 0 &&
360 ent
->mPendingQ
.Count() == 0) {
361 LOG((" removing empty connection entry\n"));
363 return kHashEnumerateRemove
;
366 // else, use this opportunity to compact our arrays...
367 ent
->mIdleConns
.Compact();
368 ent
->mActiveConns
.Compact();
369 ent
->mPendingQ
.Compact();
371 return kHashEnumerateNext
;
375 nsHttpConnectionMgr::ShutdownPassCB(nsHashKey
*key
, void *data
, void *closure
)
377 nsHttpConnectionMgr
*self
= (nsHttpConnectionMgr
*) closure
;
378 nsConnectionEntry
*ent
= (nsConnectionEntry
*) data
;
380 nsHttpTransaction
*trans
;
381 nsHttpConnection
*conn
;
383 // close all active connections
384 while (ent
->mActiveConns
.Count()) {
385 conn
= (nsHttpConnection
*) ent
->mActiveConns
[0];
387 ent
->mActiveConns
.RemoveElementAt(0);
388 self
->mNumActiveConns
--;
390 conn
->Close(NS_ERROR_ABORT
);
394 // close all idle connections
395 while (ent
->mIdleConns
.Count()) {
396 conn
= (nsHttpConnection
*) ent
->mIdleConns
[0];
398 ent
->mIdleConns
.RemoveElementAt(0);
399 self
->mNumIdleConns
--;
401 conn
->Close(NS_ERROR_ABORT
);
405 // close all pending transactions
406 while (ent
->mPendingQ
.Count()) {
407 trans
= (nsHttpTransaction
*) ent
->mPendingQ
[0];
409 ent
->mPendingQ
.RemoveElementAt(0);
411 trans
->Close(NS_ERROR_ABORT
);
416 return kHashEnumerateRemove
;
419 //-----------------------------------------------------------------------------
422 nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry
*ent
)
424 LOG(("nsHttpConnectionMgr::ProcessPendingQForEntry [ci=%s]\n",
425 ent
->mConnInfo
->HashKey().get()));
427 PRInt32 i
, count
= ent
->mPendingQ
.Count();
429 LOG((" pending-count=%u\n", count
));
430 nsHttpTransaction
*trans
= nsnull
;
431 nsHttpConnection
*conn
= nsnull
;
432 for (i
=0; i
<count
; ++i
) {
433 trans
= (nsHttpTransaction
*) ent
->mPendingQ
[i
];
434 GetConnection(ent
, trans
->Caps(), &conn
);
439 LOG((" dispatching pending transaction...\n"));
441 // remove pending transaction
442 ent
->mPendingQ
.RemoveElementAt(i
);
444 nsresult rv
= DispatchTransaction(ent
, trans
, trans
->Caps(), conn
);
445 if (NS_SUCCEEDED(rv
))
448 LOG((" DispatchTransaction failed [rv=%x]\n", rv
));
449 // on failure, just put the transaction back
450 ent
->mPendingQ
.InsertElementAt(trans
, i
);
451 // might be something wrong with the connection... close it.
462 // we're at the active connection limit if any one of the following conditions is true:
463 // (1) at max-connections
464 // (2) keep-alive enabled and at max-persistent-connections-per-server/proxy
465 // (3) keep-alive disabled and at max-connections-per-server
467 nsHttpConnectionMgr::AtActiveConnectionLimit(nsConnectionEntry
*ent
, PRUint8 caps
)
469 nsHttpConnectionInfo
*ci
= ent
->mConnInfo
;
471 LOG(("nsHttpConnectionMgr::AtActiveConnectionLimit [ci=%s caps=%x]\n",
472 ci
->HashKey().get(), caps
));
474 // use >= just to be safe
475 if (mNumActiveConns
>= mMaxConns
) {
476 LOG((" num active conns == max conns\n"));
480 nsHttpConnection
*conn
;
481 PRInt32 i
, totalCount
, persistCount
= 0;
483 totalCount
= ent
->mActiveConns
.Count();
485 // count the number of persistent connections
486 for (i
=0; i
<totalCount
; ++i
) {
487 conn
= (nsHttpConnection
*) ent
->mActiveConns
[i
];
488 if (conn
->IsKeepAlive()) // XXX make sure this is thread-safe
492 LOG((" total=%d, persist=%d\n", totalCount
, persistCount
));
495 PRUint16 maxPersistConns
;
497 if (ci
->UsingHttpProxy() && !ci
->UsingSSL()) {
498 maxConns
= mMaxConnsPerProxy
;
499 maxPersistConns
= mMaxPersistConnsPerProxy
;
502 maxConns
= mMaxConnsPerHost
;
503 maxPersistConns
= mMaxPersistConnsPerHost
;
506 // use >= just to be safe
507 return (totalCount
>= maxConns
) || ( (caps
& NS_HTTP_ALLOW_KEEPALIVE
) &&
508 (persistCount
>= maxPersistConns
) );
512 nsHttpConnectionMgr::GetConnection(nsConnectionEntry
*ent
, PRUint8 caps
,
513 nsHttpConnection
**result
)
515 LOG(("nsHttpConnectionMgr::GetConnection [ci=%s caps=%x]\n",
516 ent
->mConnInfo
->HashKey().get(), PRUint32(caps
)));
520 if (AtActiveConnectionLimit(ent
, caps
)) {
521 LOG((" at active connection limit!\n"));
525 nsHttpConnection
*conn
= nsnull
;
527 if (caps
& NS_HTTP_ALLOW_KEEPALIVE
) {
528 // search the idle connection list
529 while (!conn
&& (ent
->mIdleConns
.Count() > 0)) {
530 conn
= (nsHttpConnection
*) ent
->mIdleConns
[0];
531 // we check if the connection can be reused before even checking if
532 // it is a "matching" connection.
533 if (!conn
->CanReuse()) {
534 LOG((" dropping stale connection: [conn=%x]\n", conn
));
535 conn
->Close(NS_ERROR_ABORT
);
539 LOG((" reusing connection [conn=%x]\n", conn
));
540 ent
->mIdleConns
.RemoveElementAt(0);
546 conn
= new nsHttpConnection();
551 nsresult rv
= conn
->Init(ent
->mConnInfo
, mMaxRequestDelay
);
557 // We created a new connection that will become active, purge the
558 // oldest idle connection if we've reached the upper limit.
559 if (mNumIdleConns
+ mNumActiveConns
+ 1 > mMaxConns
)
560 mCT
.Enumerate(PurgeOneIdleConnectionCB
, this);
562 // XXX this just purges a random idle connection. we should instead
563 // enumerate the entire hash table to find the eldest idle connection.
570 nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry
*ent
,
571 nsAHttpTransaction
*trans
,
573 nsHttpConnection
*conn
)
575 LOG(("nsHttpConnectionMgr::DispatchTransaction [ci=%s trans=%x caps=%x conn=%x]\n",
576 ent
->mConnInfo
->HashKey().get(), trans
, caps
, conn
));
578 nsConnectionHandle
*handle
= new nsConnectionHandle(conn
);
580 return NS_ERROR_OUT_OF_MEMORY
;
583 nsHttpPipeline
*pipeline
= nsnull
;
584 if (conn
->SupportsPipelining() && (caps
& NS_HTTP_ALLOW_PIPELINING
)) {
585 LOG((" looking to build pipeline...\n"));
586 if (BuildPipeline(ent
, trans
, &pipeline
))
590 // hold an owning ref to this connection
591 ent
->mActiveConns
.AppendElement(conn
);
595 // give the transaction the indirect reference to the connection.
596 trans
->SetConnection(handle
);
598 nsresult rv
= conn
->Activate(trans
, caps
);
601 LOG((" conn->Activate failed [rv=%x]\n", rv
));
602 ent
->mActiveConns
.RemoveElement(conn
);
604 // sever back references to connection, and do so without triggering
605 // a call to ReclaimConnection ;-)
606 trans
->SetConnection(nsnull
);
607 NS_RELEASE(handle
->mConn
);
608 // destroy the connection
612 // if we were unable to activate the pipeline, then this will destroy
613 // the pipeline, which will cause each the transactions owned by the
614 // pipeline to be restarted.
615 NS_IF_RELEASE(pipeline
);
622 nsHttpConnectionMgr::BuildPipeline(nsConnectionEntry
*ent
,
623 nsAHttpTransaction
*firstTrans
,
624 nsHttpPipeline
**result
)
626 if (mMaxPipelinedRequests
< 2)
629 nsHttpPipeline
*pipeline
= nsnull
;
630 nsHttpTransaction
*trans
;
632 PRInt32 i
= 0, numAdded
= 0;
633 while (i
< ent
->mPendingQ
.Count()) {
634 trans
= (nsHttpTransaction
*) ent
->mPendingQ
[i
];
635 if (trans
->Caps() & NS_HTTP_ALLOW_PIPELINING
) {
637 pipeline
= new nsHttpPipeline
;
640 pipeline
->AddTransaction(firstTrans
);
643 pipeline
->AddTransaction(trans
);
645 // remove transaction from pending queue
646 ent
->mPendingQ
.RemoveElementAt(i
);
649 if (++numAdded
== mMaxPipelinedRequests
)
653 ++i
; // skip to next pending transaction
659 LOG((" pipelined %u transactions\n", numAdded
));
660 NS_ADDREF(*result
= pipeline
);
665 nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction
*trans
)
667 // since "adds" and "cancels" are processed asynchronously and because
668 // various events might trigger an "add" directly on the socket thread,
669 // we must take care to avoid dispatching a transaction that has already
670 // been canceled (see bug 190001).
671 if (NS_FAILED(trans
->Status())) {
672 LOG((" transaction was canceled... dropping event!\n"));
676 PRUint8 caps
= trans
->Caps();
677 nsHttpConnectionInfo
*ci
= trans
->ConnectionInfo();
678 NS_ASSERTION(ci
, "no connection info");
680 nsCStringKey
key(ci
->HashKey());
681 nsConnectionEntry
*ent
= (nsConnectionEntry
*) mCT
.Get(&key
);
683 ent
= new nsConnectionEntry(ci
);
685 return NS_ERROR_OUT_OF_MEMORY
;
689 nsHttpConnection
*conn
;
691 // check if the transaction already has a sticky reference to a connection.
692 // if so, then we can just use it directly. XXX check if alive??
693 // XXX add a TakeConnection method or something to make this clearer!
694 nsConnectionHandle
*handle
= (nsConnectionHandle
*) trans
->Connection();
696 NS_ASSERTION(caps
& NS_HTTP_STICKY_CONNECTION
, "unexpected caps");
697 NS_ASSERTION(handle
->mConn
, "no connection");
699 // steal reference from connection handle.
700 // XXX prevent SetConnection(nsnull) from calling ReclaimConnection
701 conn
= handle
->mConn
;
702 handle
->mConn
= nsnull
;
704 // destroy connection handle.
705 trans
->SetConnection(nsnull
);
707 // remove sticky connection from active connection list; we'll add it
708 // right back in DispatchTransaction.
709 if (ent
->mActiveConns
.RemoveElement(conn
))
712 NS_ERROR("sticky connection not found in active list");
713 return NS_ERROR_UNEXPECTED
;
717 GetConnection(ent
, caps
, &conn
);
721 LOG((" adding transaction to pending queue [trans=%x pending-count=%u]\n",
722 trans
, ent
->mPendingQ
.Count()+1));
723 // put this transaction on the pending queue...
724 InsertTransactionSorted(ent
->mPendingQ
, trans
);
729 rv
= DispatchTransaction(ent
, trans
, caps
, conn
);
736 //-----------------------------------------------------------------------------
739 nsHttpConnectionMgr::OnMsgShutdown(PRInt32
, void *)
741 LOG(("nsHttpConnectionMgr::OnMsgShutdown\n"));
743 mCT
.Reset(ShutdownPassCB
, this);
745 // signal shutdown complete
746 nsAutoMonitor
mon(mMonitor
);
751 nsHttpConnectionMgr::OnMsgNewTransaction(PRInt32 priority
, void *param
)
753 LOG(("nsHttpConnectionMgr::OnMsgNewTransaction [trans=%p]\n", param
));
755 nsHttpTransaction
*trans
= (nsHttpTransaction
*) param
;
756 trans
->SetPriority(priority
);
757 nsresult rv
= ProcessNewTransaction(trans
);
759 trans
->Close(rv
); // for whatever its worth
764 nsHttpConnectionMgr::OnMsgReschedTransaction(PRInt32 priority
, void *param
)
766 LOG(("nsHttpConnectionMgr::OnMsgNewTransaction [trans=%p]\n", param
));
768 nsHttpTransaction
*trans
= (nsHttpTransaction
*) param
;
769 trans
->SetPriority(priority
);
771 nsHttpConnectionInfo
*ci
= trans
->ConnectionInfo();
772 nsCStringKey
key(ci
->HashKey());
773 nsConnectionEntry
*ent
= (nsConnectionEntry
*) mCT
.Get(&key
);
775 PRInt32 index
= ent
->mPendingQ
.IndexOf(trans
);
777 ent
->mPendingQ
.RemoveElementAt(index
);
778 InsertTransactionSorted(ent
->mPendingQ
, trans
);
786 nsHttpConnectionMgr::OnMsgCancelTransaction(PRInt32 reason
, void *param
)
788 LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param
));
790 nsHttpTransaction
*trans
= (nsHttpTransaction
*) param
;
792 // if the transaction owns a connection and the transaction is not done,
793 // then ask the connection to close the transaction. otherwise, close the
794 // transaction directly (removing it from the pending queue first).
796 nsAHttpConnection
*conn
= trans
->Connection();
797 if (conn
&& !trans
->IsDone())
798 conn
->CloseTransaction(trans
, reason
);
800 nsHttpConnectionInfo
*ci
= trans
->ConnectionInfo();
801 nsCStringKey
key(ci
->HashKey());
802 nsConnectionEntry
*ent
= (nsConnectionEntry
*) mCT
.Get(&key
);
804 PRInt32 index
= ent
->mPendingQ
.IndexOf(trans
);
806 ent
->mPendingQ
.RemoveElementAt(index
);
807 nsHttpTransaction
*temp
= trans
;
808 NS_RELEASE(temp
); // b/c NS_RELEASE nulls its argument!
811 trans
->Close(reason
);
817 nsHttpConnectionMgr::OnMsgProcessPendingQ(PRInt32
, void *param
)
819 nsHttpConnectionInfo
*ci
= (nsHttpConnectionInfo
*) param
;
821 LOG(("nsHttpConnectionMgr::OnMsgProcessPendingQ [ci=%s]\n", ci
->HashKey().get()));
823 // start by processing the queue identified by the given connection info.
824 nsCStringKey
key(ci
->HashKey());
825 nsConnectionEntry
*ent
= (nsConnectionEntry
*) mCT
.Get(&key
);
826 if (!(ent
&& ProcessPendingQForEntry(ent
))) {
827 // if we reach here, it means that we couldn't dispatch a transaction
828 // for the specified connection info. walk the connection table...
829 mCT
.Enumerate(ProcessOneTransactionCB
, this);
836 nsHttpConnectionMgr::OnMsgPruneDeadConnections(PRInt32
, void *)
838 LOG(("nsHttpConnectionMgr::OnMsgPruneDeadConnections\n"));
840 if (mNumIdleConns
> 0)
841 mCT
.Enumerate(PruneDeadConnectionsCB
, this);
845 nsHttpConnectionMgr::OnMsgReclaimConnection(PRInt32
, void *param
)
847 LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection [conn=%p]\n", param
));
849 nsHttpConnection
*conn
= (nsHttpConnection
*) param
;
852 // 1) remove the connection from the active list
853 // 2) if keep-alive, add connection to idle list
854 // 3) post event to process the pending transaction queue
857 nsHttpConnectionInfo
*ci
= conn
->ConnectionInfo();
860 nsCStringKey
key(ci
->HashKey());
861 nsConnectionEntry
*ent
= (nsConnectionEntry
*) mCT
.Get(&key
);
863 NS_ASSERTION(ent
, "no connection entry");
865 ent
->mActiveConns
.RemoveElement(conn
);
867 if (conn
->CanReuse()) {
868 LOG((" adding connection to idle list\n"));
869 // hold onto this connection in the idle list. we push it to
870 // the end of the list so as to ensure that we'll visit older
871 // connections first before getting to this one.
872 ent
->mIdleConns
.AppendElement(conn
);
876 LOG((" connection cannot be reused; closing connection\n"));
877 // make sure the connection is closed and release our reference.
878 conn
->Close(NS_ERROR_ABORT
);
879 nsHttpConnection
*temp
= conn
;
884 OnMsgProcessPendingQ(NS_OK
, ci
); // releases |ci|
889 nsHttpConnectionMgr::OnMsgUpdateParam(PRInt32
, void *param
)
891 PRUint16 name
= (NS_PTR_TO_INT32(param
) & 0xFFFF0000) >> 16;
892 PRUint16 value
= NS_PTR_TO_INT32(param
) & 0x0000FFFF;
895 case MAX_CONNECTIONS
:
898 case MAX_CONNECTIONS_PER_HOST
:
899 mMaxConnsPerHost
= value
;
901 case MAX_CONNECTIONS_PER_PROXY
:
902 mMaxConnsPerProxy
= value
;
904 case MAX_PERSISTENT_CONNECTIONS_PER_HOST
:
905 mMaxPersistConnsPerHost
= value
;
907 case MAX_PERSISTENT_CONNECTIONS_PER_PROXY
:
908 mMaxPersistConnsPerProxy
= value
;
910 case MAX_REQUEST_DELAY
:
911 mMaxRequestDelay
= value
;
913 case MAX_PIPELINED_REQUESTS
:
914 mMaxPipelinedRequests
= value
;
917 NS_NOTREACHED("unexpected parameter name");
921 //-----------------------------------------------------------------------------
922 // nsHttpConnectionMgr::nsConnectionHandle
924 nsHttpConnectionMgr::nsConnectionHandle::~nsConnectionHandle()
927 gHttpHandler
->ReclaimConnection(mConn
);
932 NS_IMPL_THREADSAFE_ISUPPORTS0(nsHttpConnectionMgr::nsConnectionHandle
)
935 nsHttpConnectionMgr::nsConnectionHandle::OnHeadersAvailable(nsAHttpTransaction
*trans
,
936 nsHttpRequestHead
*req
,
937 nsHttpResponseHead
*resp
,
940 return mConn
->OnHeadersAvailable(trans
, req
, resp
, reset
);
944 nsHttpConnectionMgr::nsConnectionHandle::ResumeSend()
946 return mConn
->ResumeSend();
950 nsHttpConnectionMgr::nsConnectionHandle::ResumeRecv()
952 return mConn
->ResumeRecv();
956 nsHttpConnectionMgr::nsConnectionHandle::CloseTransaction(nsAHttpTransaction
*trans
, nsresult reason
)
958 mConn
->CloseTransaction(trans
, reason
);
962 nsHttpConnectionMgr::nsConnectionHandle::GetConnectionInfo(nsHttpConnectionInfo
**result
)
964 mConn
->GetConnectionInfo(result
);
968 nsHttpConnectionMgr::nsConnectionHandle::GetSecurityInfo(nsISupports
**result
)
970 mConn
->GetSecurityInfo(result
);
974 nsHttpConnectionMgr::nsConnectionHandle::IsPersistent()
976 return mConn
->IsPersistent();
980 nsHttpConnectionMgr::nsConnectionHandle::IsReused()
982 return mConn
->IsReused();
986 nsHttpConnectionMgr::nsConnectionHandle::PushBack(const char *buf
, PRUint32 bufLen
)
988 return mConn
->PushBack(buf
, bufLen
);