Chromium Code Reviews| Index: net/docs/life-of-a-url-request.md |
| diff --git a/net/docs/life-of-a-url-request.md b/net/docs/life-of-a-url-request.md |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a475085b6bfd6d4028e3bf17a0c1d9c4df231906 |
| --- /dev/null |
| +++ b/net/docs/life-of-a-url-request.md |
| @@ -0,0 +1,473 @@ |
| +# Life of a URLRequest |
| + |
| +This document is intended as an overview of the core layers of the network |
| +stack, their basic responsibilities, how they fit together, and where some of |
| +the pain points are, without going into too much detail. Though it touches a |
| +bit on the renderer process and the content/loader stack, the focus is on net/ |
| +itself. |
| + |
| +It's particularly targeted at people new to the Chrome network stack, but |
| +should also be useful for team members who may be experts at some parts of the |
| +stack, but are largely unfamiliar with other components. It starts by walking |
| +through how a basic request issued by Blink works its way through the network |
| +stack, and then moves on to discuss how various components plug in. |
| + |
| + |
| +# Anatomy of the Network Stack |
| + |
| +The main top-level network stack object is the URLRequextContext. The context |
| +has non-owning pointers to everything needed to create and issue a URLRequest. |
| +The context must outlive all requests that use it. Creating a context is a |
| +rather complicated process, and it's recommended that most embedders use |
| +URLRequestContextBuilder to do this. Chrome itself has several request |
| +contexts that the network stack team owns: |
| + |
| +* The proxy URLRequestContext, owned by the IOThread and used to get PAC |
| +scripts while avoiding re-entrancy. |
| +* The system URLRequestContext, also owned by the IOThread, used for requests |
| +that aren't associated with a profile. |
| +* Each profile, including incognito profiles, has a number of URLRequestContexts |
| +that are created as needed: |
| + * The main URLRequestContext is mostly created in ProfileIOData, though it |
| + has a couple components that are passed in from content's StoragePartition |
| + code. Several other components are shared with the system URLRequestContext, |
| + like the HostResolver. |
| + * Each non-incognito profile also has a media request context, which uses a |
| + different on-disk cache than the main request context. This prevents a |
| + single huge media file from evicting everything else in the cache. |
| + * On desktop platforms, each profile has a request context for extensions. |
| + * Each profile has two contexts for each isolated app (One for media, one |
| + for everything else). |
| + |
| +The "HttpNetworkSession" is another major network stack object. It has |
|
xunjieli
2015/07/10 20:32:26
nit: I think the quotes can be removed, since quot
mmenke
2015/07/10 21:37:32
Done.
|
| +pointers to the network stack objects that more directly deal with sockets, and |
| +their dependendencies. Its main objects are the HttpStreamFactory, the socket |
| +pools, and the SPDY/QUIC session pools. |
| + |
| +This document does not mention either of these objects much, but at layers |
| +above the HttpStreamFactory, objects often grab their dependencies from the |
| +URLRequestContext, while the HttpStreamFactory and layers below it generally |
| +get their dependencies from the HttpNetworkSession. |
| + |
| + |
| +# How many "Delegates"? |
| + |
| +The network stack informs the embedder of important events for a request using |
| +two main interfaces: The URLRequest::Delegate interface and the NetworkDelegate |
|
xunjieli
2015/07/10 20:32:26
nit: lowercase "The" after the colon.
mmenke
2015/07/10 21:37:32
Done.
|
| +interface. |
| + |
| +The URLRequest::Delegate interface consists of small set callbacks needed to let |
|
xunjieli
2015/07/10 20:32:26
[a] small set [of] callbacks?
mmenke
2015/07/10 21:37:32
Done.
|
| +the embedder drive a request forward. URLRequest::Delegates generally own the |
| +URLRequest. |
| + |
| +The NetworkDelegate is a single object shared by all requests, and includes |
| +callbacks corresponding to most of the URLRequest::Delegate's callbacks, as well |
| +as an assortment of other methods. The NetworkDelegate is optional, the |
|
xunjieli
2015/07/10 20:32:26
nit: Add a conjunction in "The NetworkDelegate is
mmenke
2015/07/10 21:37:31
Done.
|
| +URLRequest::Delegate is not. |
| + |
| + |
| +# Overview |
| + |
| +A request for data is normally dispatched from the renderer to the browser |
| +process. There a URLRequest is created to drive the request. A |
| +protocol-specific job (e.g. HTTP, data, file) is attached to the request. That |
| +job first checks the cache, and then creates a network connection, if necessary, |
| +to actually fetch the data. That connection object interacts with network socket |
| +pools to potentially re-use sockets; the socket pools create and connect a |
| +socket if there is no appropriate existing socket. Once that socket exists, the |
| +HTTP request is dispatched, the response read and parsed, and the result |
| +returned back up the stack and sent over to the renderer. |
| + |
| +Of course, it's not quite that simple :-}. |
| + |
| +Consider a simple request issued by the renderer process. Suppose it's an HTTP |
| +request, the response is uncompressed, and no matching entry in the cache. |
| + |
| +### Request Starts in a Child Process |
|
xunjieli
2015/07/10 20:32:26
I find it a bit confusing that this doc mentioned
mmenke
2015/07/10 21:37:32
That's right.
|
| + |
| +* ResourceDispatcher to creates an IPCResourceLoaderBridge. |
|
xunjieli
2015/07/10 20:32:26
nit: remove "to".
mmenke
2015/07/10 21:37:32
Done.
|
| +* The IPCResourceLoaderBridge asks ResourceDispatcher to start the request. |
| +* ResourceDispatcher sends an IPC to the ResourceDispatcherHost in the |
| +browser process. |
| + |
| +### ResourceDispatcherHost set up the request in the Browser Process |
| + |
| +* ResourceDispatcherHost uses the URLRequestContext to create the URLRequest. |
| +* ResourceDispatcherHost creates a ResourceLoader and ResourceHandler chain to |
|
xunjieli
2015/07/10 20:32:26
nit: and [a] ResourceHandler chain.
(It reads as i
mmenke
2015/07/10 21:37:31
Done, and rephrased to hopefully be clearer.
|
| +manage the URLRequest. |
| +* ResourceLoader starts the URLRequest. |
| + |
| +### Check the Cache, Request an HttpStream |
| + |
| +* The URLRequest asks the URLRequestJobFactory to create a URLRequestJob, |
| +usually a URLRequestHttpJob for HTTP/HTTPS requests. |
| +* The URLRequestHttpJob asks the HttpCache to create an HttpTransaction |
| +(always an HttpCache::Transaction). |
| +* The HttpCache::Transaction sees there's no cache entry for the request, |
| +and creates an HttpNetworkTransaction. |
| +* The HttpNetworkTransaction calls into the HttpStreamFactory to request an |
| +HttpStream. |
| + |
| +### Create an HttpStream |
| +* HttpStreamFactory creates an HttpStreamFactoryImpl::Job. |
| +* HttpStreamFactoryImpl::Job calls into the TransportClientSocketPool to |
| +populate an ClientSocketHandle. |
| +* TransportClientSocketPool has no idle sockets, so it creates a |
| +TransportConnectJob and starts it. |
| +* TransportConnectJob creates a StreamSocket and establishes a connection. |
| +* TransportClientSocketPool puts the StreamSocket in the ClientSocketHandle, |
| +and calls into HttpStreamFactoryImpl::Job. |
| +* HttpStreamFactoryImpl::Job creates an HttpBasicStream, which takes |
| +ownership of the ClientSocketHandle. |
| +* It returns the HttpBasicStream to the HttpNetworkTransaction. |
| + |
| +### Send request and read the response headers |
| + |
| +* HttpNetworkTransaction gives the request headers to the HttpBasicStream, |
| +and tells it to start the request. |
| +* HttpBasicStream sends the request, and waits for the response. |
| +* The HttpBasicStream sends the response headers back to the |
| +HttpNetworkTransaction. |
| +* The response headers are sent up to the URLRequest, to the ResourceLoader, |
| +through the ResourceHandler stack. |
|
xunjieli
2015/07/10 20:32:26
nit: I would replace "stack" with "chain" so there
mmenke
2015/07/10 21:37:32
Done.
|
| +* They're then sent by the AsyncResourceHandler to the ResourceDispatcher. |
|
xunjieli
2015/07/10 20:32:26
I got confused by the sudden mention of AsyncResou
mmenke
2015/07/10 21:37:32
Clarified that the AsyncResourceHandler is the las
|
| + |
| +### Response body is read |
| + |
| +* AsyncResourceHandler allocates a 512k ring buffer of shared memory to read |
| +the body of the request. |
| +* AsyncResourceHandler tells the ResourceLoader to read the response body to |
| +the buffer, 32kB at a time. |
| +* AsyncResourceHandler informs the ResourceDispatcher of each read. |
|
xunjieli
2015/07/10 20:32:26
How does AsyncResourceHandler inform the ResourceD
mmenke
2015/07/10 21:37:32
Done.
|
| +* ResourceDispatcher tells the AsyncResourceHandler when it's done with the |
| +data with each read, so it knows when parts of the buffer can be reused. |
| + |
| +### URLRequest is Destroyed |
|
xunjieli
2015/07/10 20:32:26
nit: s/Destroyed/destroyed.
I think we should sti
mmenke
2015/07/10 21:37:32
Done to all the "###" titles (Hrm, I was really in
|
| + |
| +* When complete, the RDH deletes the ResourceLoader, which deletes the |
|
xunjieli
2015/07/10 20:32:26
Does the chain of ResourceHandlers also get delete
mmenke
2015/07/10 21:37:32
Done.
|
| +URLRequest. |
| +* During destruction, the HttpNetworkTransaction determines if the socket is |
| +reusable, and if so, tells the HttpBasicStream to return it to the socket pool. |
| + |
| +# Details |
|
xunjieli
2015/07/10 20:32:26
I thought the life of a url is ended, because I di
|
| + |
| +Continuing with a "simple" URLRequest, here's a bit more detail on how things |
| +work. |
| + |
| +### Request Starts in a Child Process |
| + |
| +Each child process has at most one ResourceDispatcher, which is responsible for |
| +all URL request-related communication with the browser process. When something |
| +in the renderer needs to issue a resource request, it calls into the |
| +ResourceDispatcher, which returns an IPCResourceLoaderBridge to the caller. |
| +The caller uses the bridge to start a request. When started, the |
| +ResourceDispatcher assigns the request a per-renderer ID, and then sends the |
| +ID, along with all information needed to issue the request, to the |
| +ResourceDispatcherHost in the browser process. |
| + |
| +### ResourceDispatcherHost set up the request in the Browser Process |
| + |
| +The ResourceDispatcherHost (RDH), along with most of the network stack, lives |
| +on the browser process's IO thread. The browser process only has one RDH, |
| +which is responsible for handling all network requests initiated by |
| +ResourceDispatchers in all child processes, not just renderer process. |
| +Browser-initiated don't go through the RDH, with some exceptions. |
|
xunjieli
2015/07/10 20:32:26
nit: s/"Browser-initiated"/"requests initiated by
mmenke
2015/07/10 21:37:32
Done.
|
| + |
| +When the RDH sees the request, it calls into a URLRequestContext to create the |
| +URLRequest. The URLRequestContext has pointers to all the network stack |
| +objects needed to issue the request over the network, such as the cache, cookie |
| +store, and host resolver. The RDH then creates a chain of ResourceHandlers |
| +each of which can monitor/modify/delay/cancel the URLRequest and the |
| +information it returns. The only one of these I'll talk about here is the |
| +AsyncResourceHandler, which is the last ResourceHandler in the chain. The RDH |
| +then creates a ResourceLoader (Which is the URLRequest::Delegate), passes |
| +ownership of the URLRequest and the ResourceHandler chain to it, and then starts |
| +the ResourceLoader. |
| + |
| +The ResourceLoader checks that none of the ResourceHandlers want to cancel, |
| +modify, or delay the request, and then finally starts the URLRequest. |
| + |
| +### Check the Cache, Request an HttpStream |
| + |
| +The URLRequest then calls into the URLRequestJobFactory to create a |
| +URLRequestJob and then starts it. In the case of an HTTP or HTTPS request, this |
| +will be a URLRequestHttpJob. The URLRequestHttpJob attaches cookies to the |
| +request, if needed. |
| + |
| +The URLRequestHttpJob calls into the HttpCache to create an |
| +HttpCache::Transaction. If there's no matching entry in the cache, the |
| +HttpCache::Transaction will just call into the HttpNetworkLayer to create an |
| +HttpNetworkTransaction, and transparently wrap it. The HttpNetworkTransaction |
| +then calls into the HttpStreamFactory to request an HttpStream to the server. |
| + |
| +### Create an HttpStream |
| + |
| +The HttpStreamFactoryImpl::Job creates a ClientSocketHandle to hold a socket, |
| +once connected, and passes it into the ClientSocketPoolManager. The |
| +ClientSocketPoolManager assembles the TransportSocketParams needed to |
| +establish the connection and creates a group name ("host:port") used to |
| +identify sockets that can be used interchangeably. |
| + |
| +The ClientSocketPoolManager directs the request to the |
| +TransportClientSocketPool, since there's no proxy and it will be using |
| +HTTP/1.x. The pool sends it on to the |
| +ClientSocketPoolBase<TransportSocketParams> it wraps, which sends it on to its |
|
xunjieli
2015/07/10 20:32:26
I am not 100% sure on what the three "it" refer to
mmenke
2015/07/10 21:37:32
Good point. Removed almost all the its.
|
| +ClientSocketPoolBaseHelper. If there isn't already an idle connection, and there |
| +are available socket slots, the ClientSocketPoolBaseHelper will create a new |
| +TransportConnectJob using the aforementioned params object. This Job will do the |
| +actual DNS lookup by calling into the HostResolverImpl, if needed, and then |
| +finally establish a connection. |
| + |
| +Once the socket is connected, ownership of the socket is passed to the |
| +ClientSocketHandle. The HttpStreamFactoryImpl::Job is then informed the |
| +connection attempt succeeded, and it then creates an HttpBasicStream, which |
| +takes ownership of the ClientSocketHandle. It then passes ownership of the |
| +HttpBasicStream back to the HttpNetworkTransaction. |
| + |
| +### Send request and read the response headers |
| + |
| +The Transaction passes the request headers to the HttpBasicStream, which uses an |
| +HttpStreamParser to (finally) format the request headers and body (if present) |
| +and send them to the server. |
| + |
| +The HttpStreamParser waits to receive the response and then parses the HTTP/1.x |
| +response headers, and then passes them up through both Transaction classes |
|
xunjieli
2015/07/10 20:32:26
nit: I'd spell out what these two Transaction clas
mmenke
2015/07/10 21:37:32
Done.
|
| +to the URLRequestHttpJob. The URLRequestHttpJob saves any cookies, if needed, |
| +and then passes the headers up to the URLRequest and on to the ResourceLoader. |
| + |
| +The ResourceLoader passes them through the chain of ResourceHandlers, and then |
| +they make their way to the AsyncResourceHandler. The AsyncResourceHandler uses |
| +the renderer process ID ("child ID") to figure out which process the request |
| +was associated with, and then sends the headers along with the request ID to |
| +that process's ResourceDispatcher. The ResourceDispatcher uses the ID to |
| +figure out which IPCResourceLoaderBridge the headers should be sent to, which |
| +sends them on to whatever created the IPCResourceLoaderBridge in the first |
| +place. |
| + |
| +### Response body is read |
| + |
| +Without waiting to hear back from the ResourceDispatcher, the ResourceLoader |
| +tells its ResourceHandler chain to allocate memory to receive the response |
| +body. The AsyncResourceHandler creates a 512KB ring buffer of shared memory, |
| +and then passes the first 32KB of it to the ResourceLoader for the first read. |
| +The ResourceLoader then passes a 32KB body read request down through the |
| +URLRequest all the way down to the HttpResponseParser. Once some data is read, |
| +possibly less than 32KB, the number of bytes read makes its way back to the |
| +AsyncResourceHandler, which passes the shared memory buffer and the offset and |
| +amount of data read to the renderer process. |
| + |
| +The AsyncResourceHandler relies on ACKs from the renderer to prevent it from |
| +overwriting data that the renderer has yet to consume. This process repeats |
| +until the response body is completely read. |
| + |
| +### URLRequest is destroyed |
| + |
| +When the URLRequest informs the ResourceLoader it's complete, the |
| +ResourceLoader tells the ResourceHandlers, and the AsyncResourceHandler tells |
| +the ResourceDispatcher the request is complete. The RDH then deletes |
| +ResourceLoader, which deletes the URLRequest. |
|
xunjieli
2015/07/10 20:32:27
nit: I'd mention what happens to the chain of Reso
mmenke
2015/07/10 21:37:32
Done.
|
| + |
| +When the HttpNetworkTransaction is being torn down, it figures out if the |
| +socket is reusable. If not, it tells the HttpBasicStream to close the socket. |
| +Either way, the ClientSocketHandle returns the socket is then returned to the |
| +socket pool, either for reuse or so the socket pool knows it has another free |
| +socket slot. |
| + |
| + |
| +# Additional Topics |
| + |
| +## HTTP Cache |
| + |
| +The HttpCache::Transaction sits between the URLRequestHttpJob and the |
| +HttpNetworkTransaction, and implements the HttpTransaction interface, just like |
| +the HttpNetworkTransaction. The HttpCache::Transaction checks if a request can |
| +be served out of the cache. If a request needs to be revalidated, it handles |
| +sending a 204 revalidation request over the network. It may also break a range |
| +request into multiple cached and non-cached contiguous chunks, and may issue |
| +multiple network requests for a single range URLRequest. |
| + |
| +One important detail is that it has a read/write lock for each URL. The lock |
| +technically allows multiple reads at once, but since an HttpCache::Transaction |
| +always grabs the lock for writing and reading before downgrading it to a read |
| +only lock, all requests for the same URL are effectively done serially. Blink |
| +merges requests for the same URL in many cases, which mitigates this problem to |
| +some extent. |
| + |
| +The HttpCache::Transaction uses one of three disk_cache::Backends to actually |
| +store the cache's index and files: The in memory backend, the blockfile cache |
| +backend, and the simple cache backend. The first is used in incognito. The |
| +latter two are both stored on disk, and are used on different platforms. |
| + |
| +## Cancellation |
| + |
| +A request can be cancelled by the renderer process Blink or by any of the |
|
xunjieli
2015/07/10 20:32:26
Why is the "renderer process" called Blink? I thou
mmenke
2015/07/10 21:37:32
Removed the Blink (Was supposed to be "Blink in th
|
| +ResourceHandlers through the ResourceLoader. When the cancellation message |
|
xunjieli
2015/07/10 20:32:26
nit: maybe add the word "chain" here?
e.g. any Re
mmenke
2015/07/10 21:37:32
Done.
|
| +reaches the URLRequest, it passes on the fact it's been cancelled back to the |
| +ResourceLoader, which then sends the message down the ResourceHandler chain. |
| + |
| +When an HttpNetworkTransaction for a cancelled request is being torn down, it |
| +figures out if the socket the HttpStream owns can potentially be reused, based |
| +on the protocol (HTTP / SPDY / QUIC) and any received headers. If the socket |
| +potentially can be reused, an HttpResponseBodyDrainer is created to try and |
| +read any remaining body bytes of the HttpStream, if any, before returning the |
| +socket to the SocketPool. If this takes too long, or there's an error, the |
| +socket is closed instead. Since this all happens at the layer below the cache, |
| +any drained bytes are not written to the cache, and as far as the cache layer is |
| +concerned, it only has a partial response. |
| + |
| +## Redirects |
| + |
| +The URLRequestHttpJob checks if headers indicate a redirect when it receives |
| +them from the next layer down (Typically the HttpCache::Transaction). If they |
| +indicate a redirect, it tells the cache the response is complete, ignoring the |
| +body, so the cache only has the headers. The cache then treats it as a complete |
| +entry, even if the headers indicated there will be a body. |
| + |
| +The URLRequestHttpJob then checks if the URLRequest if the request should be |
| +followed. First it checks the scheme. Then it informs the ResourceLoader |
| +about the redirect, to give it a chance to cancel the request. The information |
| +makes its way down through the AsyncResourceHandler to the ResourceDispatcher |
| +and on into Blink, which checks if the redirect should be followed. |
| + |
| +The ResourceDispatcher then asynchronously sends a message back to either |
| +follow the redirect or cancel the request. In either case, the old |
| +HttpTransaction is destroyed, and the HttpNetworkTransaction attempts to drain |
| +the socket for reuse, just as in the cancellation case. If the redirect is |
| +followed, the URLRequest calls into the URLRequestJobFactory to create a new |
| +URLRequestJob, and then starts it. |
| + |
| +## Filters (gzip, SDCH, etc) |
| + |
| +When the URLRequestHttpJob receives headers, it sends a list of all Content- |
| +Encoding values to Filter::Factory, which creates a (possibly empty) chain of |
|
xunjieli
2015/07/10 20:32:26
nit: I think there is a space between the dash and
mmenke
2015/07/10 21:37:32
Done.
|
| +filters. As body bytes are received, they're passed through the filters at the |
| +URLRequestJob layer and the decoded bytes are passed back to the embedder. |
| + |
| +Since this is done above the cache layer, the cache stores the responses prior |
| +to decompression. As a result, if files aren't compressed over the wire, they |
| +aren't compressed in the cache, either. This behavior can also create problems |
| +when responses are SDCH compressed, as a dictionary and a cached file encoded |
| +using it may have different lifetimes. |
| + |
| +## Socket Pools |
| + |
| +The ClientSocketPoolManager is responsible for assembling the parameters needed |
| +to connect a socket, and then sending the request to the right socket pool. |
| +Each socket request sent to a socket pool comes with a socket params object, a |
| +ClientSocketHandle, and a "group name". The params object contains all the |
| +information a ConnectJob needs to create a connection of a given type, and |
| +different types of socket pools take different params types. The |
| +ClientSocketHandle will take temporary ownership of the socket, once connected |
| +socket, and return it to the socket pool when done. All connections with the |
| +same group name in the same pool can be used to service the same connection |
| +request, so it consists of host, port, protocol, and whether "privacy mode" is |
| +used for requests using the socket or not. |
| + |
| +All socket pool classes derive from the ClientSocketPoolBase<SocketParamType>. |
| +The ClientSocketPoolBase handles managing sockets - which requests to create |
| +sockets for, which requests get connected sockets first, which sockets belong |
| +to which groups, connection limits per group, keeping track of and closing idle |
| +sockets, etc. Each ClientSocketPoolBase subclass has its own ConnectJob type, |
| +which establishes a connection using the socket params, before the pool hands |
| +out the connected socket. |
| + |
| +## Socket Pool Layering |
| + |
| +Some socket pools are layered on top other socket pools. This is done when a |
| +"socket" in a higher layer needs to establish a connection in a lower level |
| +pool and then take ownership of it as part of its connection process. See later |
| +sections for examples. There are a couple additional complexities here. |
| + |
| +From the perspective of the lower layer pool, all of its sockets that a higher |
| +layer pools owns are actively in use, even when the higher layer pool considers |
| +them idle. As a result, when a lower layer pool is at its connection limit and |
| +needs to make a new connection, it will ask any higher layer pools pools to |
| +close an idle connection if they have one, so it can make a new connection. |
| + |
| +Sockets in the higher layer pool must have their own distinct group name in the |
|
xunjieli
2015/07/10 20:32:26
This sentence is a bit hard to understand. Conside
mmenke
2015/07/10 21:37:32
Tried to make it a bit clearer.
|
| +lower layer pool as well. This is needed so the lower layer pool won't, for |
| +example, group SSL and HTTP connections to the same port together. |
| + |
| +## SSL |
| + |
| +When an SSL connection is needed, the ClientSocketPoolManager assembles the |
| +parameters needed both to connect the TCP socket and establish an SSL |
| +connection. It then passes them to the SSLClientSocketPool, which creates |
| +an SSLConnectJob using them. The SSLConnectJob's first step is to call into the |
| +TransportSocketPool to establish a TCP connection. |
| + |
| +Once a connection is established by the lower layered pool, the SSLConnectJob |
| +then starts SSL negotiation. Once that's done, the SSL socket is passed back to |
| +the HttpStreamFactoryImpl::Job that initiated the request, and things proceed |
| +just as with HTTP. When complete, the socket is returned to the |
| +SSLClientSocketPool. |
| + |
| +## Proxies |
| + |
| +The first step the HttpStreamFactoryImpl::Job performs, just before calling |
| +into the ClientSocketPoolManager to create a socket, is to check with the |
| +ProxyService to see if a proxy is needed for the URL it's been given. The |
| +ClientSocketPoolManager then uses this information to find the correct proxy |
| +socket pool to send the request to. |
| + |
| +TODO(mmenke): Discuss proxy configurations, WPAD, tracing proxy resolver. |
| + |
| +## Proxy Socket Pools |
| + |
| +Each SOCKS or HTTP proxy has its own completely independent set of socket |
| +pools. They have their own exclusive TransportSocketPool, their own protocol- |
| +specific pool above it, and their own SSLSocketPool above that. HTTPS proxies |
| +also have a second SSLSocketPool between the the HttpProxyClientSocketPool and |
| +the TransportSocketPool, since they can talk SSL to both the proxy and the |
| +destination server, layered on top of each other. |
| + |
| +## SPDY |
| + |
| +Once an SSL connection is established, the HttpStreamFactoryImpl::Job checks if |
| +SPDY was negotiated over the socket. If so, it creates a SpdySession using the |
| +socket, and a SpdyHttpStream. The SpdyHttpStream will be passed to the |
| +HttpNetworkTransaction, which drives the stream as usual. |
| + |
| +The SpdySession will be shared with other Jobs connecting to the same server, |
| +and future Jobs will find the SpdySession before they try to create a |
| +connection. HttpServerProperties also tracks which servers supported SPDY when |
| +we last talked to them. We only try to establish a single connection to servers |
| +we think speak SPDY when multiple HttpStreamFactoryImpl::Jobs are trying to |
| +connect to them, to avoid wasting resources. |
| + |
| +## QUIC |
| + |
| +HttpServerProperties also tracks which servers have advertised QUIC support in |
| +the past. If a server has advertised QUIC support, a second |
| +HttpStreamFactoryImpl::Job will be created for SPDY, and will be raced against |
| +the one for HTTP/HTTPS connection. Whichever connects first will be used. |
| +Existing QUIC sessions will be reused if available. |
| + |
| +TODO(mmenke): Discuss SPDY/QUIC proxies? |
| + |
| +## Prioritization |
| + |
| +URLRequests are assigned a priority on creation. It only comes into play in |
| +a couple places: |
| + |
| +* The ResourceScheduler lives outside net/, and in some cases, delays starting |
| +low priority requests on a per-tab basis. |
| +* DNS lookups are initiated based on the highest priority request for a lookup. |
| +* Socket pools hand out and create sockets on prioritization. However, idle |
| +sockets will be assigned to low priority requests in preference to creating new |
| +sockets for higher priority requests. |
|
xunjieli
2015/07/10 20:32:26
I don't understand this sentence.
Do you instead
mmenke
2015/07/10 21:37:31
No...If we have no free socket slots, and a high p
|
| +* SPDY and QUIC both support sending priorities over-the-wire. |
| + |
| +At the socket pool layer, sockets are only assigned to socket requests once the |
| +socket is connected and SSL is negotiated, if needed. This is done so that if |
| +a higher priority request for a group reaches the socket pool before a |
| +connection is established, the first usable connection goes to the highest |
| +priority socket request. |
| + |
| +## Non-HTTP schemes |
| + |
| +The URLRequestJobFactory has a ProtocolHander for each supported scheme. |
| +Non-HTTP URLRequests have their own ProtocolHandlers. Some are implemented in |
| +net/, (like FTP, file, and data, though blink handles some data URLs |
| +internally), and others are implemented in content/ or chrome (like blob, |
| +chrome, and chrome-extension). |