| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef NET_HTTP_HTTP_PIPELINED_CONNECTION_IMPL_H_ |
| #define NET_HTTP_HTTP_PIPELINED_CONNECTION_IMPL_H_ |
| |
| #include <map> |
| #include <queue> |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "base/location.h" |
| #include "base/memory/linked_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "net/base/completion_callback.h" |
| #include "net/base/net_export.h" |
| #include "net/base/net_log.h" |
| #include "net/base/ssl_config_service.h" |
| #include "net/http/http_pipelined_connection.h" |
| #include "net/http/http_request_info.h" |
| #include "net/http/http_stream_parser.h" |
| #include "net/proxy/proxy_info.h" |
| |
| namespace net { |
| |
| class ClientSocketHandle; |
| class GrowableIOBuffer; |
| class HostPortPair; |
| class HttpNetworkSession; |
| class HttpRequestHeaders; |
| class HttpResponseInfo; |
| class IOBuffer; |
| class SSLCertRequestInfo; |
| class SSLInfo; |
| |
| // This class manages all of the state for a single pipelined connection. It |
| // tracks the order that HTTP requests are sent and enforces that the |
| // subsequent reads occur in the appropriate order. |
| // |
| // If an error occurs related to pipelining, ERR_PIPELINE_EVICTION will be |
| // returned to the client. This indicates the client should retry the request |
| // without pipelining. |
| class NET_EXPORT_PRIVATE HttpPipelinedConnectionImpl |
| : public HttpPipelinedConnection { |
| public: |
| class Factory : public HttpPipelinedConnection::Factory { |
| public: |
| virtual HttpPipelinedConnection* CreateNewPipeline( |
| ClientSocketHandle* connection, |
| HttpPipelinedConnection::Delegate* delegate, |
| const HostPortPair& origin, |
| const SSLConfig& used_ssl_config, |
| const ProxyInfo& used_proxy_info, |
| const BoundNetLog& net_log, |
| bool was_npn_negotiated, |
| NextProto protocol_negotiated) override; |
| }; |
| |
| HttpPipelinedConnectionImpl(ClientSocketHandle* connection, |
| Delegate* delegate, |
| const HostPortPair& origin, |
| const SSLConfig& used_ssl_config, |
| const ProxyInfo& used_proxy_info, |
| const BoundNetLog& net_log, |
| bool was_npn_negotiated, |
| NextProto protocol_negotiated); |
| virtual ~HttpPipelinedConnectionImpl(); |
| |
| // HttpPipelinedConnection interface. |
| |
| // Used by HttpStreamFactoryImpl and friends. |
| virtual HttpPipelinedStream* CreateNewStream() override; |
| |
| // Used by HttpPipelinedHost. |
| virtual int depth() const override; |
| virtual bool usable() const override; |
| virtual bool active() const override; |
| |
| // Used by HttpStreamFactoryImpl. |
| virtual const SSLConfig& used_ssl_config() const override; |
| virtual const ProxyInfo& used_proxy_info() const override; |
| virtual const BoundNetLog& net_log() const override; |
| virtual bool was_npn_negotiated() const override; |
| virtual NextProto protocol_negotiated() const override; |
| |
| // Used by HttpPipelinedStream. |
| |
| // Notifies this pipeline that a stream is no longer using it. |
| void OnStreamDeleted(int pipeline_id); |
| |
| // Effective implementation of HttpStream. Note that we don't directly |
| // implement that interface. Instead, these functions will be called by the |
| // pass-through methods in HttpPipelinedStream. |
| void InitializeParser(int pipeline_id, |
| const HttpRequestInfo* request, |
| const BoundNetLog& net_log); |
| |
| int SendRequest(int pipeline_id, |
| const std::string& request_line, |
| const HttpRequestHeaders& headers, |
| HttpResponseInfo* response, |
| const CompletionCallback& callback); |
| |
| int ReadResponseHeaders(int pipeline_id, |
| const CompletionCallback& callback); |
| |
| int ReadResponseBody(int pipeline_id, |
| IOBuffer* buf, int buf_len, |
| const CompletionCallback& callback); |
| |
| void Close(int pipeline_id, |
| bool not_reusable); |
| |
| UploadProgress GetUploadProgress(int pipeline_id) const; |
| |
| HttpResponseInfo* GetResponseInfo(int pipeline_id); |
| |
| bool IsResponseBodyComplete(int pipeline_id) const; |
| |
| bool CanFindEndOfResponse(int pipeline_id) const; |
| |
| bool IsMoreDataBuffered(int pipeline_id) const; |
| |
| bool IsConnectionReused(int pipeline_id) const; |
| |
| void SetConnectionReused(int pipeline_id); |
| |
| void GetSSLInfo(int pipeline_id, |
| SSLInfo* ssl_info); |
| |
| void GetSSLCertRequestInfo(int pipeline_id, |
| SSLCertRequestInfo* cert_request_info); |
| |
| // Attempts to drain the response body for |stream| so that the pipeline may |
| // be reused. |
| void Drain(HttpPipelinedStream* stream, HttpNetworkSession* session); |
| |
| private: |
| enum StreamState { |
| STREAM_CREATED, |
| STREAM_BOUND, |
| STREAM_SENDING, |
| STREAM_SENT, |
| STREAM_READ_PENDING, |
| STREAM_ACTIVE, |
| STREAM_CLOSED, |
| STREAM_READ_EVICTED, |
| STREAM_UNUSED, |
| }; |
| enum SendRequestState { |
| SEND_STATE_START_IMMEDIATELY, |
| SEND_STATE_START_NEXT_DEFERRED_REQUEST, |
| SEND_STATE_SEND_ACTIVE_REQUEST, |
| SEND_STATE_COMPLETE, |
| SEND_STATE_EVICT_PENDING_REQUESTS, |
| SEND_STATE_NONE, |
| }; |
| enum ReadHeadersState { |
| READ_STATE_START_IMMEDIATELY, |
| READ_STATE_START_NEXT_DEFERRED_READ, |
| READ_STATE_READ_HEADERS, |
| READ_STATE_READ_HEADERS_COMPLETE, |
| READ_STATE_WAITING_FOR_CLOSE, |
| READ_STATE_STREAM_CLOSED, |
| READ_STATE_NONE, |
| READ_STATE_EVICT_PENDING_READS, |
| }; |
| |
| struct PendingSendRequest { |
| PendingSendRequest(); |
| ~PendingSendRequest(); |
| |
| int pipeline_id; |
| std::string request_line; |
| HttpRequestHeaders headers; |
| HttpResponseInfo* response; |
| CompletionCallback callback; |
| }; |
| |
| struct StreamInfo { |
| StreamInfo(); |
| ~StreamInfo(); |
| |
| linked_ptr<HttpStreamParser> parser; |
| CompletionCallback read_headers_callback; |
| CompletionCallback pending_user_callback; |
| StreamState state; |
| NetLog::Source source; |
| }; |
| |
| typedef std::map<int, StreamInfo> StreamInfoMap; |
| |
| // Called after the first request is sent or in a task sometime after the |
| // first stream is added to this pipeline. This gives the first request |
| // priority to send, but doesn't hold up other requests if it doesn't. |
| // When called the first time, notifies the |delegate_| that we can accept new |
| // requests. |
| void ActivatePipeline(); |
| |
| // Responsible for sending one request at a time and waiting until each |
| // comepletes. |
| int DoSendRequestLoop(int result); |
| |
| // Called when an asynchronous Send() completes. |
| void OnSendIOCallback(int result); |
| |
| // Activates the only request in |pending_send_request_queue_|. This should |
| // only be called via SendRequest() when the send loop is idle. |
| int DoStartRequestImmediately(int result); |
| |
| // Activates the first request in |pending_send_request_queue_| that hasn't |
| // been closed, if any. This is called via DoSendComplete() after a prior |
| // request complets. |
| int DoStartNextDeferredRequest(int result); |
| |
| // Sends the active request. |
| int DoSendActiveRequest(int result); |
| |
| // Notifies the user that the send has completed. This may be called directly |
| // after SendRequest() for a synchronous request, or it may be called in |
| // response to OnSendIOCallback for an asynchronous request. |
| int DoSendComplete(int result); |
| |
| // Evicts all unsent deferred requests. This is called if there is a Send() |
| // error or one of our streams informs us the connection is no longer |
| // reusable. |
| int DoEvictPendingSendRequests(int result); |
| |
| // Ensures that only the active request's HttpPipelinedSocket can read from |
| // the underlying socket until it completes. A HttpPipelinedSocket informs us |
| // that it's done by calling Close(). |
| int DoReadHeadersLoop(int result); |
| |
| // Called when the pending asynchronous ReadResponseHeaders() completes. |
| void OnReadIOCallback(int result); |
| |
| // Invokes DoStartNextDeferredRead() if the read loop is idle. This is called |
| // via a task queued when the previous |active_read_id_| closes its stream |
| // after a succesful response. |
| void StartNextDeferredRead(); |
| |
| // Activates the next read request immediately. This is called via |
| // ReadResponseHeaders() if that stream is at the front of |request_order_| |
| // and the read loop is idle. |
| int DoStartReadImmediately(int result); |
| |
| // Activates the next read request in |request_order_| if it's ready to go. |
| // This is called via StartNextDeferredRead(). |
| int DoStartNextDeferredRead(int result); |
| |
| // Calls ReadResponseHeaders() on the active request's parser. |
| int DoReadHeaders(int result); |
| |
| // Notifies the user that reading the headers has completed. This may happen |
| // directly after DoReadNextHeaders() if the response is already available. |
| // Otherwise, it is called in response to OnReadIOCallback(). |
| int DoReadHeadersComplete(int result); |
| |
| // Halts the read loop until Close() is called by the active stream. |
| int DoReadWaitForClose(int result); |
| |
| // Cleans up the state associated with the active request. Invokes |
| // DoReadNextHeaders() in a new task to start the next response. This is |
| // called after the active request's HttpPipelinedSocket calls Close(). |
| int DoReadStreamClosed(); |
| |
| // Removes all pending ReadResponseHeaders() requests from the queue. This may |
| // happen if there is an error with the pipeline or one of our |
| // HttpPipelinedSockets indicates the connection was suddenly closed. |
| int DoEvictPendingReadHeaders(int result); |
| |
| // Determines if the response headers indicate pipelining will work. This is |
| // called every time we receive headers. |
| void CheckHeadersForPipelineCompatibility(int pipeline_id, int result); |
| |
| // Reports back to |delegate_| whether pipelining will work. |
| void ReportPipelineFeedback(int pipeline_id, Feedback feedback); |
| |
| // Posts a task to fire the user's callback in response to SendRequest() or |
| // ReadResponseHeaders() completing on an underlying parser. This might be |
| // invoked in response to our own IO callbacks, or it may be invoked if the |
| // underlying parser completes SendRequest() or ReadResponseHeaders() |
| // synchronously, but we've already returned ERR_IO_PENDING to the user's |
| // SendRequest() or ReadResponseHeaders() call into us. |
| void QueueUserCallback(int pipeline_id, |
| const CompletionCallback& callback, |
| int rv, |
| const tracked_objects::Location& from_here); |
| |
| // Invokes the callback queued in QueueUserCallback(). |
| void FireUserCallback(int pipeline_id, int result); |
| |
| Delegate* delegate_; |
| scoped_ptr<ClientSocketHandle> connection_; |
| SSLConfig used_ssl_config_; |
| ProxyInfo used_proxy_info_; |
| BoundNetLog net_log_; |
| bool was_npn_negotiated_; |
| // Protocol negotiated with the server. |
| NextProto protocol_negotiated_; |
| scoped_refptr<GrowableIOBuffer> read_buf_; |
| int next_pipeline_id_; |
| bool active_; |
| bool usable_; |
| bool completed_one_request_; |
| base::WeakPtrFactory<HttpPipelinedConnectionImpl> weak_factory_; |
| |
| StreamInfoMap stream_info_map_; |
| |
| std::queue<int> request_order_; |
| |
| std::queue<PendingSendRequest*> pending_send_request_queue_; |
| scoped_ptr<PendingSendRequest> active_send_request_; |
| SendRequestState send_next_state_; |
| bool send_still_on_call_stack_; |
| |
| ReadHeadersState read_next_state_; |
| int active_read_id_; |
| bool read_still_on_call_stack_; |
| |
| DISALLOW_COPY_AND_ASSIGN(HttpPipelinedConnectionImpl); |
| }; |
| |
| } // namespace net |
| |
| #endif // NET_HTTP_HTTP_PIPELINED_CONNECTION_IMPL_H_ |