nsDocShell
as an example client of the nsIHttpChannel
API
nsDocShell::LoadURI(string)
nsIURI
from stringnsDocShell::LoadURI(nsIURI)
nsIInputStream
for read response from; passes them with URI to ...nsDocShell::InternalLoad
nsDocShell::DoURILoad
nsIChannel
for the URI (NS_NewChannel
)nsIHttpChannel
nsDocShell::DoChannelLoad
nsURILoader::OpenURI
nsIStreamListener
pointer, 'loader' to nsURILoader::OpenChannel
- it creates an nsDocumentOpenInfo
object, which implements nsIStreamListener
, i.e. has OnStartRequest
, OnStopRequest
, OnDataAvailable
, the three functions in which channel responses are received asynchronously.nsHttpChannel::AsyncOpen
OpenURI
; OpenChannel
isn't named the best, since the opening happens in the context of OpenURI
, its calling function.This is where it hits Necko code. But the interface for clients of Necko is important to consider:
channel->AsyncOpen
.nsIStreamListener::OnStartRequest
(header info)nsIStreamListener::OnDataAvailable
(data in single or multiple chunks)nsIStreamListener::OnStopRequest
(no more data from http)This all happens on the main thread, in a non-blocking fashion: make your request on the main thread, then carry on and get the async response later, also on the main thread. There is an option to receive OnDataAvailable specifically on a non-main thread, but all other calls happen on the main thread.
Then in Necko Http code (still on the main thread for now):
nsHttpChannel::AsyncOpen
nsHttpChannel::BeginConnect()
nsHttpConnectionInfo
object for the channelnsHttpChannel::Connect
nsHttpChannel::ContinueConnect
nsHttpChannel::SetupTransaction
nsHttpTransaction
, and Init
s it with mRequestHead
(the request headers) and mUploadStream
(which was created from the request data in channel setup)nsIAsyncInputStream
(for the response; corresponds to the nsPipeInputStream
for the response stream pipe)nsInputStreamPump
nsHttpChannel::gHttpHandler->InitiateTransaction
(called from Connect
)
nsHttpHandler
object, which adds the transaction to the nsHttpConnectionMgr
(one of these per nsHttpHandler
).nsHttpConnectionMgr::PostEvent
nsConnEvent
with params including the handler function, nsHttpConnectionMgr::OnMsgNewTransaction
, and the recently created nsHttpTransaction
.nsConnEvent
to the socket threadBack to the context of nsHttpChannel::ContinueConnect
:
nsInputStreamPump->AsyncRead
nsIAsyncInputStream::AsyncWait
(the input for the response stream pipe created with the nsHttpTransaction
, i.e. nsPipeInputStream::AsyncWait
), with target thread set to the current thread, i.e. main. So, subsequent callbacks will be dispatched to the main thread.nsPipeInputStream::AsyncWait
nsInputStreamReadyEvent
, which is created now and may be called laterEt voila, the transaction has been posted to the socket thread, and the main thread continues on, unblocked from network IO.
So, on the socket thread...
The event queue works around to nsHttpConnectionMgr::OnMsgNewTransaction
(with the nsHttpTransaction
passed as a param - Remember the event was posted earlier by InitiateTransaction
from the main thread).
nsHttpConnectionMgr::OnMsgNewTransaction
nsHttpConnectionMgr::ProcessNewTransaction
gSocketThread
)nsClassHashtable<nsCStringHashKey, nsConnectionEntry>
called mCT
in nsHttpConnectionMgr
.MakeNewConnection
- creates socket etc.).nsConnectionEntry
has a single nsHttpConnectionInfo
object attached, a pending queue of nsHttpTransactions
, and 3 arrays for connections:
nsHttpConnection
snsHttpConnection
snsHalfOpenSocket
snsHttpConnectionMgr::TryDispatchTransaction
DispatchTransaction
is called, along with good code comments: best to read the code for more detail.nsHttpConnectionMgr::DispatchTransaction
nsHttpConnectionMgr::DispatchAbstractTransaction
nsHttpConnection::Activate
nsHttpConnection::OnOutputStreamReady
nsHttpConnection::OnSocketWritable
mTransaction
)`ResumeRecv
)nsHttpConnection::ResumeRecv
nsHttpTransaction::ReadSegments
ReadRequestSegment
is passed to mRequestStream->ReadSegments
- this function pointer is called and used to read the request bytes, which in turn calls ...nsHttpConnection::OnReadSegment
mSocketOut->Write
Back to the context of OnSocketWritable
:
nsIAsyncInputStream::AsyncWait
(i.e. mSocketIn
)
The HTTP request is now written to the socket, which has a callback to the nsHttpConnection
...
Note: from what I can tell, there are some cases where the transaction is queued up to be written to the socket later if it's not writable now, or in the case of pipelining or SPDY where it's done in batches. But I'm not an expert in either of these things.
Once the socket is readable (more async behavior), nsHttpConnection::OnInputStreamReady
is called on the socket thread.
nsHttpConnection::OnInputStreamReady
nsHttpConnection::OnSocketReadable
nsHttpTransaction::WriteSegments
nsHttpConnection::OnWriteSegment
mSocketIn->Read
to the transaction's pipensPipeOutputStream::WriteSegments
nsPipe::AdvanceWriteCursor
nsPipeInputStream::OnInputReadable
nsPipeEvents::NotifyInputReady
nsPipeEvents
object. Once this object goes out of scope, mCallback->OnInputStreamReady
is called.nsInputStreamReadyEvent
: it is a runnable that dispatches itself to a previously set target thread, and calls its internal mCallback->OnInputStreamReady
function.Remember that nsPipeInputStream::AsyncWait
was called earlier, after the transaction was initially created and posted to the connection manager on the socket thread. And in that function it created a proxy callback because it wished to have OnInputStreamReady
called on the main thread.
Back on the main thread:
nsInputStreamPump::OnInputStreamReady
nsInputStreamPump::OnStateStart
, nsInputStreamPump::OnStateTransfer
and nsInputStreamPump::OnStateStop
.nsIStreamListener::OnStartRequest
, nsIStreamListener::OnDataAvailable
and nsIStreamListener::OnStopRequest
respectively.And that brings us back to the nsHttpChannel
API and nsDocShell
gets its data.