nsDocShell as an example client of the nsIHttpChannel API
- nsDocShell::LoadURI(string)- create nsIURIfrom string
 
- create 
- nsDocShell::LoadURI(nsIURI)- creates 2 nsIInputStreamfor read response from; passes them with URI to ...
 
- creates 2 
- nsDocShell::InternalLoad
- nsDocShell::DoURILoad- opens the nsIChannelfor the URI (NS_NewChannel)
- if "http:", it will be an nsIHttpChannel
 
- opens the 
- nsDocShell::DoChannelLoad
- nsURILoader::OpenURI- passes an nsIStreamListenerpointer, 'loader' tonsURILoader::OpenChannel- it creates annsDocumentOpenInfoobject, which implementsnsIStreamListener, i.e. hasOnStartRequest,OnStopRequest,OnDataAvailable, the three functions in which channel responses are received asynchronously.
 
- passes an 
- nsHttpChannel::AsyncOpen- called from OpenURI;OpenChannelisn't named the best, since the opening happens in the context ofOpenURI, its calling function.
 
- called from 
This is where it hits Necko code. But the interface for clients of Necko is important to consider:
- SEND REQUEST
  - URI helps creates channel
- setup channel (headers, request data, response callback...)
- channel->AsyncOpen.
 
- RECEIVE RESPONSE
  - get a callback to each of these:
    - nsIStreamListener::OnStartRequest(header info)
- nsIStreamListener::OnDataAvailable(data in single or multiple chunks)
- nsIStreamListener::OnStopRequest(no more data from http)
 
 
- get a callback to each of these:
    
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()- creates nsHttpConnectionInfoobject for the channel
- checks if we're proxying or not
- fires off the DNS prefetch request (dispatched to DNS thread pool)
- some other things
 
- creates 
- nsHttpChannel::Connect- might to a SpeculativeConnect (pre open TCP socket)
 
- nsHttpChannel::ContinueConnect- some cache stuff
 
- nsHttpChannel::SetupTransaction- creates new nsHttpTransaction, andInits it withmRequestHead(the request headers) andmUploadStream(which was created from the request data in channel setup)
- gets an nsIAsyncInputStream(for the response; corresponds to thensPipeInputStreamfor the response stream pipe)
- passes it to nsInputStreamPump
 
- creates new 
- nsHttpChannel::gHttpHandler->InitiateTransaction(called from- Connect)- This is the global nsHttpHandlerobject, which adds the transaction to thensHttpConnectionMgr(one of these pernsHttpHandler).
 
- This is the global 
- nsHttpConnectionMgr::PostEvent- creates an nsConnEventwith params including the handler function,nsHttpConnectionMgr::OnMsgNewTransaction, and the recently creatednsHttpTransaction.
- dispatches the nsConnEventto the socket thread
 
- creates an 
Back to the context of nsHttpChannel::ContinueConnect:
- nsInputStreamPump->AsyncRead- this pump calls nsIAsyncInputStream::AsyncWait(the input for the response stream pipe created with thensHttpTransaction, 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.
 
- this pump calls 
- nsPipeInputStream::AsyncWait- sets the callback to be used later for a response
- if a target is specified (in this case, the main thread), callback is proxied via an nsInputStreamReadyEvent, which is created now and may be called later
- Otherwise, the callback would be called directly, when the socket is readable
 
Et 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- (Notice the check that we're on gSocketThread)
- Gets conn info (i.e. hostname and port) from the transaction, and then gets or creates a connection entry from the connection table, an nsClassHashtable<nsCStringHashKey, nsConnectionEntry>calledmCTinnsHttpConnectionMgr.
- If a connection entry already exists matching the required conn info, then that one will be used; otherwise a new one is created (MakeNewConnection- creates socket etc.).
- Note: nsConnectionEntryhas a singlensHttpConnectionInfoobject attached, a pending queue ofnsHttpTransactions, and 3 arrays for connections:- active nsHttpConnections
- idle nsHttpConnections
- nsHalfOpenSockets
 
- active 
 
- (Notice the check that we're on 
- nsHttpConnectionMgr::TryDispatchTransaction- There is a series of decisions about whether DispatchTransactionis called, along with good code comments: best to read the code for more detail.
- Basically, if a connection is available...
 
- There is a series of decisions about whether 
- nsHttpConnectionMgr::DispatchTransaction
- nsHttpConnectionMgr::DispatchAbstractTransaction- the transaction is given an indirect reference to the connection (for use later, when the socket has received data from the far end).
 
- nsHttpConnection::Activate- this connection is passed the transaction
 
- nsHttpConnection::OnOutputStreamReady
- nsHttpConnection::OnSocketWritable- tries to write the request data from the current transaction (mTransaction)
- tells the transaction to now wait (`ResumeRecv)
 
- tries to write the request data from the current transaction (
- nsHttpConnection::ResumeRecv
- nsHttpTransaction::ReadSegments- ReadRequestSegmentis passed to- mRequestStream->ReadSegments- this function pointer is called and used to read the request bytes, which in turn calls ...
 
- nsHttpConnection::OnReadSegment- passes bytes read from request to mSocketOut->Write
 
- passes bytes read from request to 
Back to the context of OnSocketWritable:
- nsIAsyncInputStream::AsyncWait(i.e.- mSocketIn)- sets the callback and waits.
 
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- passes bytes from mSocketIn->Readto the transaction's pipe
 
- passes bytes from 
- nsPipeOutputStream::WriteSegments
- nsPipe::AdvanceWriteCursor
- nsPipeInputStream::OnInputReadable- so now the response is hitting the other end of the pipe, saying it has bytes to read
 
- nsPipeEvents::NotifyInputReady- puts the callback object into an nsPipeEventsobject. Once this object goes out of scope,mCallback->OnInputStreamReadyis called.
- Note: this callback may be a proxy object, nsInputStreamReadyEvent: it is a runnable that dispatches itself to a previously set target thread, and calls its internalmCallback->OnInputStreamReadyfunction.
 
- puts the callback object into an 
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- This function in turn calls nsInputStreamPump::OnStateStart,nsInputStreamPump::OnStateTransferandnsInputStreamPump::OnStateStop.
- These functions call nsIStreamListener::OnStartRequest,nsIStreamListener::OnDataAvailableandnsIStreamListener::OnStopRequestrespectively.
 
- This function in turn calls 
And that brings us back to the nsHttpChannel API and nsDocShell gets its data.