// Copyright (c) 2009 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_FLIP_FLIP_STREAM_H_
#define NET_FLIP_FLIP_STREAM_H_
#include <string>
#include <list>
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/singleton.h"
#include "net/base/bandwidth_metrics.h"
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/load_log.h"
#include "net/flip/flip_framer.h"
#include "net/flip/flip_protocol.h"
namespace net {
class FlipSession;
class HttpRequestInfo;
class HttpResponseInfo;
class UploadData;
class UploadDataStream;
// The FlipStream is used by the FlipSession to represent each stream known
// on the FlipSession.
// Streams can be created either by the client or by the server. When they
// are initiated by the client, both the FlipSession and client object (such as
// a FlipNetworkTransaction) will maintain a reference to the stream. When
// initiated by the server, only the FlipSession will maintain any reference,
// until such a time as a client object requests a stream for the path.
class FlipStream : public base::RefCounted<FlipStream> {
public:
// FlipStream constructor
FlipStream(FlipSession* session, flip::FlipStreamId stream_id, bool pushed,
LoadLog* log);
// Ideally I'd use two abstract classes as interfaces for these two sections,
// but since we're ref counted, I can't make both abstract classes inherit
// from RefCounted or we'll have two separate ref counts for the same object.
// TODO(willchan): Consider using linked_ptr here orcreating proxy wrappers
// for FlipStream to provide the appropriate interface.
// ===================================================
// Interface for [Http|Flip]NetworkTransaction to use.
// Sends the request. If |upload_data| is non-NULL, sends that in the request
// body. |callback| is used when this completes asynchronously. Note that
// the actual SYN_STREAM packet will have already been sent by this point.
// Also note that FlipStream takes ownership of |upload_data|.
int SendRequest(UploadDataStream* upload_data,
HttpResponseInfo* response,
CompletionCallback* callback);
// Reads the response headers. Returns a net error code.
int ReadResponseHeaders(CompletionCallback* callback);
// Reads the response body. Returns a net error code or the number of bytes
// read.
int ReadResponseBody(
IOBuffer* buf, int buf_len, CompletionCallback* callback);
// Cancels the stream. Note that this does not immediately cause deletion of
// the stream. This function is used to cancel any callbacks from being
// invoked. TODO(willchan): It should also free up any memory associated with
// the stream, such as IOBuffers.
void Cancel();
// Returns the number of bytes uploaded.
uint64 GetUploadProgress() const;
const HttpResponseInfo* GetResponseInfo() const;
// Is this stream a pushed stream from the server.
bool pushed() const { return pushed_; }
// =================================
// Interface for FlipSession to use.
flip::FlipStreamId stream_id() const { return stream_id_; }
void set_stream_id(flip::FlipStreamId stream_id) { stream_id_ = stream_id; }
// For pushed streams, we track a path to identify them.
const std::string& path() const { return path_; }
void set_path(const std::string& path) { path_ = path; }
int priority() const { return priority_; }
void set_priority(int priority) { priority_ = priority; }
// Called by the FlipSession when a response (e.g. a SYN_REPLY) has been
// received for this stream. |path| is the path of the URL for a server
// initiated stream, otherwise is empty.
void OnResponseReceived(const HttpResponseInfo& response);
// Called by the FlipSession when response data has been received for this
// stream. This callback may be called multiple times as data arrives
// from the network, and will never be called prior to OnResponseReceived.
// |buffer| contains the data received. The stream must copy any data
// from this buffer before returning from this callback.
// |length| is the number of bytes received or an error.
// A zero-length count does not indicate end-of-stream.
// Returns true on success and false on error.
bool OnDataReceived(const char* buffer, int bytes);
// Called by the FlipSession when a write has completed. This callback
// will be called multiple times for each write which completes. Writes
// include the SYN_STREAM write and also DATA frame writes.
// |result| is the number of bytes written or a net error code.
void OnWriteComplete(int status);
// Called by the FlipSession when the request is finished. This callback
// will always be called at the end of the request and signals to the
// stream that the stream has no more network events. No further callbacks
// to the stream will be made after this call.
// |status| is an error code or OK.
void OnClose(int status);
bool cancelled() const { return cancelled_; }
private:
friend class base::RefCounted<FlipStream>;
enum State {
STATE_NONE,
STATE_SEND_HEADERS,
STATE_SEND_HEADERS_COMPLETE,
STATE_SEND_BODY,
STATE_SEND_BODY_COMPLETE,
STATE_READ_HEADERS,
STATE_READ_HEADERS_COMPLETE,
STATE_READ_BODY,
STATE_READ_BODY_COMPLETE,
STATE_DONE
};
~FlipStream();
// Try to make progress sending/receiving the request/response.
int DoLoop(int result);
// Call the user callback.
void DoCallback(int rv);
// The implementations of each state of the state machine.
int DoSendHeaders();
int DoSendHeadersComplete(int result);
int DoSendBody();
int DoSendBodyComplete(int result);
int DoReadHeaders();
int DoReadHeadersComplete(int result);
int DoReadBody();
int DoReadBodyComplete(int result);
// Update the histograms. Can safely be called repeatedly, but should only
// be called after the stream has completed.
void UpdateHistograms();
flip::FlipStreamId stream_id_;
std::string path_;
int priority_;
const bool pushed_;
// We buffer the response body as it arrives asynchronously from the stream.
// TODO(mbelshe): is this infinite buffering?
std::list<scoped_refptr<IOBufferWithSize> > response_body_;
bool download_finished_;
ScopedBandwidthMetrics metrics_;
scoped_refptr<FlipSession> session_;
HttpResponseInfo* response_;
scoped_ptr<UploadDataStream> request_body_stream_;
bool response_complete_; // TODO(mbelshe): fold this into the io_state.
State io_state_;
// Since we buffer the response, we also buffer the response status.
// Not valid until response_complete_ is true.
int response_status_;
CompletionCallback* user_callback_;
// User provided buffer for the ReadResponseBody() response.
scoped_refptr<IOBuffer> user_buffer_;
int user_buffer_len_;
bool cancelled_;
scoped_refptr<LoadLog> load_log_;
base::TimeTicks send_time_;
base::TimeTicks recv_first_byte_time_;
base::TimeTicks recv_last_byte_time_;
int send_bytes_;
int recv_bytes_;
bool histograms_recorded_;
DISALLOW_COPY_AND_ASSIGN(FlipStream);
};
} // namespace net
#endif // NET_FLIP_FLIP_STREAM_H_