C++程序  |  331行  |  11.47 KB

// 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/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"
#include "net/ssl/ssl_config_service.h"

namespace net {

class ClientSocketHandle;
class GrowableIOBuffer;
class HostPortPair;
class HttpNetworkSession;
class HttpRequestHeaders;
class HttpResponseInfo;
class IOBuffer;
struct LoadTimingInfo;
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 IsConnectionReused(int pipeline_id) const;

  void SetConnectionReused(int pipeline_id);

  int64 GetTotalReceivedBytes(int pipeline_id) const;

  bool GetLoadTimingInfo(int pipeline_id,
                         LoadTimingInfo* load_timing_info) const;

  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_