nsDocShell as an example client of the nsIHttpChannel API

  1. nsDocShell::LoadURI(string)
  2. nsDocShell::LoadURI(nsIURI)
  3. nsDocShell::InternalLoad
  4. nsDocShell::DoURILoad
  5. nsDocShell::DoChannelLoad
  6. nsURILoader::OpenURI
  7. nsHttpChannel::AsyncOpen

This is where it hits Necko code. But the interface for clients of Necko is important to consider:

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):

  1. nsHttpChannel::AsyncOpen
  2. nsHttpChannel::BeginConnect()
  3. nsHttpChannel::Connect
  4. nsHttpChannel::ContinueConnect
  5. nsHttpChannel::SetupTransaction
  6. nsHttpChannel::gHttpHandler->InitiateTransaction (called from Connect)
  7. nsHttpConnectionMgr::PostEvent

Back to the context of nsHttpChannel::ContinueConnect:

  1. nsInputStreamPump->AsyncRead
  2. nsPipeInputStream::AsyncWait

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).

  1. nsHttpConnectionMgr::OnMsgNewTransaction
  2. nsHttpConnectionMgr::ProcessNewTransaction
  3. nsHttpConnectionMgr::TryDispatchTransaction
  4. nsHttpConnectionMgr::DispatchTransaction
  5. nsHttpConnectionMgr::DispatchAbstractTransaction
  6. nsHttpConnection::Activate
  7. nsHttpConnection::OnOutputStreamReady
  8. nsHttpConnection::OnSocketWritable
  9. nsHttpConnection::ResumeRecv
  10. nsHttpTransaction::ReadSegments
  11. nsHttpConnection::OnReadSegment

Back to the context of OnSocketWritable:

  1. 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.

  1. nsHttpConnection::OnInputStreamReady
  2. nsHttpConnection::OnSocketReadable
  3. nsHttpTransaction::WriteSegments
  4. nsHttpConnection::OnWriteSegment
  5. nsPipeOutputStream::WriteSegments
  6. nsPipe::AdvanceWriteCursor
  7. nsPipeInputStream::OnInputReadable
  8. nsPipeEvents::NotifyInputReady

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:

  1. nsInputStreamPump::OnInputStreamReady

And that brings us back to the nsHttpChannel API and nsDocShell gets its data.

See also