Commit ed113b20 authored by rch's avatar rch Committed by Commit bot

Unify the QUIC client classes.

Review URL: https://codereview.chromium.org/1035533006

Cr-Commit-Position: refs/heads/master@{#322323}
parent 4b41ec18
......@@ -1143,8 +1143,6 @@ if (is_linux) {
sources = [
"tools/quic/quic_client.cc",
"tools/quic/quic_client.h",
"tools/quic/quic_client_session.cc",
"tools/quic/quic_client_session.h",
"tools/quic/quic_default_packet_writer.cc",
"tools/quic/quic_default_packet_writer.h",
"tools/quic/quic_dispatcher.cc",
......@@ -1167,8 +1165,6 @@ if (is_linux) {
"tools/quic/quic_server_session.h",
"tools/quic/quic_socket_utils.cc",
"tools/quic/quic_socket_utils.h",
"tools/quic/quic_spdy_client_stream.cc",
"tools/quic/quic_spdy_client_stream.h",
"tools/quic/quic_spdy_server_stream.cc",
"tools/quic/quic_spdy_server_stream.h",
"tools/quic/quic_time_wait_list_manager.cc",
......@@ -1267,12 +1263,12 @@ source_set("quic_tools") {
}
source_set("simple_quic_tools") {
sources = [
"tools/quic/quic_client_session.cc",
"tools/quic/quic_client_session.h",
"tools/quic/quic_simple_client.cc",
"tools/quic/quic_simple_client.h",
"tools/quic/quic_simple_client_session.cc",
"tools/quic/quic_simple_client_session.h",
"tools/quic/quic_simple_client_stream.cc",
"tools/quic/quic_simple_client_stream.h",
"tools/quic/quic_spdy_client_stream.cc",
"tools/quic/quic_spdy_client_stream.h",
"tools/quic/synchronous_host_resolver.cc",
"tools/quic/synchronous_host_resolver.h",
]
......
......@@ -814,10 +814,10 @@
'sources': [
'tools/quic/quic_simple_client.cc',
'tools/quic/quic_simple_client.h',
'tools/quic/quic_simple_client_session.cc',
'tools/quic/quic_simple_client_session.h',
'tools/quic/quic_simple_client_stream.cc',
'tools/quic/quic_simple_client_stream.h',
'tools/quic/quic_client_session.cc',
'tools/quic/quic_client_session.h',
'tools/quic/quic_spdy_client_stream.cc',
'tools/quic/quic_spdy_client_stream.h',
'tools/quic/synchronous_host_resolver.cc',
'tools/quic/synchronous_host_resolver.h',
],
......@@ -1237,8 +1237,6 @@
'sources': [
'tools/quic/quic_client.cc',
'tools/quic/quic_client.h',
'tools/quic/quic_client_session.cc',
'tools/quic/quic_client_session.h',
'tools/quic/quic_default_packet_writer.cc',
'tools/quic/quic_default_packet_writer.h',
'tools/quic/quic_dispatcher.cc',
......@@ -1261,8 +1259,6 @@
'tools/quic/quic_server_session.h',
'tools/quic/quic_socket_utils.cc',
'tools/quic/quic_socket_utils.h',
'tools/quic/quic_spdy_client_stream.cc',
'tools/quic/quic_spdy_client_stream.h',
'tools/quic/quic_spdy_server_stream.cc',
'tools/quic/quic_spdy_server_stream.h',
'tools/quic/quic_time_wait_list_manager.cc',
......
......@@ -1695,8 +1695,6 @@
'tools/dump_cache/url_utilities.cc',
'tools/dump_cache/url_utilities.h',
'tools/dump_cache/url_utilities_unittest.cc',
'tools/quic/quic_simple_client_session_test.cc',
'tools/quic/quic_simple_client_stream_test.cc',
'tools/quic/quic_simple_client_test.cc',
'tools/tld_cleanup/tld_cleanup_util_unittest.cc',
'udp/udp_socket_unittest.cc',
......
......@@ -8,12 +8,14 @@
#include "base/run_loop.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_connection_helper.h"
#include "net/quic/quic_default_packet_writer.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_server_id.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/udp/udp_client_socket.h"
using std::string;
......@@ -154,7 +156,7 @@ void QuicSimpleClient::StartConnect() {
Perspective::IS_CLIENT,
server_id_.is_https(),
supported_versions_);
session_.reset(new QuicSimpleClientSession(config_, connection_));
session_.reset(new QuicClientSession(config_, connection_));
session_->InitializeSession(server_id_, &crypto_config_);
session_->CryptoConnect();
}
......@@ -180,12 +182,15 @@ void QuicSimpleClient::Disconnect() {
void QuicSimpleClient::SendRequest(const HttpRequestInfo& headers,
base::StringPiece body,
bool fin) {
QuicSimpleClientStream* stream = CreateReliableClientStream();
QuicSpdyClientStream* stream = CreateReliableClientStream();
if (stream == nullptr) {
LOG(DFATAL) << "stream creation failed!";
return;
}
stream->SendRequest(headers, body, fin);
SpdyHeaderBlock header_block;
CreateSpdyHeadersFromHttpRequest(headers, headers.extra_headers, SPDY3, true,
&header_block);
stream->SendRequest(header_block, body, fin);
stream->set_visitor(this);
}
......@@ -209,7 +214,7 @@ void QuicSimpleClient::SendRequestsAndWaitForResponse(
while (WaitForEvents()) {}
}
QuicSimpleClientStream* QuicSimpleClient::CreateReliableClientStream() {
QuicSpdyClientStream* QuicSimpleClient::CreateReliableClientStream() {
if (!connected()) {
return nullptr;
}
......@@ -241,17 +246,19 @@ bool QuicSimpleClient::WaitForEvents() {
}
void QuicSimpleClient::OnClose(QuicDataStream* stream) {
QuicSimpleClientStream* client_stream =
static_cast<QuicSimpleClientStream*>(stream);
QuicSpdyClientStream* client_stream =
static_cast<QuicSpdyClientStream*>(stream);
HttpResponseInfo response;
SpdyHeadersToHttpResponse(client_stream->headers(), SPDY3, &response);
if (response_listener_.get() != nullptr) {
response_listener_->OnCompleteResponse(
stream->id(), *client_stream->headers(), client_stream->data());
stream->id(), *response.headers, client_stream->data());
}
// Store response headers and body.
if (store_response_) {
latest_response_code_ = client_stream->headers()->response_code();
client_stream->headers()->GetNormalizedHeaders(&latest_response_headers_);
latest_response_code_ = client_stream->response_code();
response.headers->GetNormalizedHeaders(&latest_response_headers_);
latest_response_body_ = client_stream->data();
}
}
......
......@@ -23,8 +23,8 @@
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_packet_reader.h"
#include "net/tools/quic/quic_simple_client_session.h"
#include "net/tools/quic/quic_simple_client_stream.h"
#include "net/tools/quic/quic_client_session.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
namespace net {
......@@ -101,9 +101,9 @@ class QuicSimpleClient : public QuicDataStream::Visitor,
void SendRequestsAndWaitForResponse(
const base::CommandLine::StringVector& url_list);
// Returns a newly created QuicSimpleClientStream, owned by the
// Returns a newly created QuicSpdyClientStream, owned by the
// QuicSimpleClient.
QuicSimpleClientStream* CreateReliableClientStream();
QuicSpdyClientStream* CreateReliableClientStream();
// Wait for events until the stream with the given ID is closed.
void WaitForStreamToClose(QuicStreamId id);
......@@ -124,7 +124,7 @@ class QuicSimpleClient : public QuicDataStream::Visitor,
// QuicDataStream::Visitor
void OnClose(QuicDataStream* stream) override;
QuicSimpleClientSession* session() { return session_.get(); }
QuicClientSession* session() { return session_.get(); }
bool connected() const;
bool goaway_received() const;
......@@ -238,7 +238,7 @@ class QuicSimpleClient : public QuicDataStream::Visitor,
scoped_ptr<QuicPacketWriter> writer_;
// Session which manages streams.
scoped_ptr<QuicSimpleClientSession> session_;
scoped_ptr<QuicClientSession> session_;
// UDP socket connected to the server.
scoped_ptr<UDPClientSocket> socket_;
......
// 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.
#include "net/tools/quic/quic_simple_client_session.h"
#include "base/logging.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/quic_server_id.h"
#include "net/tools/quic/quic_simple_client_stream.h"
using std::string;
namespace net {
namespace tools {
QuicSimpleClientSession::QuicSimpleClientSession(const QuicConfig& config,
QuicConnection* connection)
: QuicClientSessionBase(connection, config), respect_goaway_(true) {
}
QuicSimpleClientSession::~QuicSimpleClientSession() {
}
void QuicSimpleClientSession::InitializeSession(
const QuicServerId& server_id,
QuicCryptoClientConfig* crypto_config) {
crypto_stream_.reset(
new QuicCryptoClientStream(server_id, this, nullptr, crypto_config));
QuicClientSessionBase::InitializeSession();
}
void QuicSimpleClientSession::OnProofValid(
const QuicCryptoClientConfig::CachedState& /*cached*/) {}
void QuicSimpleClientSession::OnProofVerifyDetailsAvailable(
const ProofVerifyDetails& /*verify_details*/) {}
QuicSimpleClientStream* QuicSimpleClientSession::CreateOutgoingDataStream() {
if (!crypto_stream_->encryption_established()) {
DVLOG(1) << "Encryption not active so no outgoing stream created.";
return nullptr;
}
if (GetNumOpenStreams() >= get_max_open_streams()) {
DVLOG(1) << "Failed to create a new outgoing stream. "
<< "Already " << GetNumOpenStreams() << " open.";
return nullptr;
}
if (goaway_received() && respect_goaway_) {
DVLOG(1) << "Failed to create a new outgoing stream. "
<< "Already received goaway.";
return nullptr;
}
QuicSimpleClientStream* stream
= new QuicSimpleClientStream(GetNextStreamId(), this);
ActivateStream(stream);
return stream;
}
QuicCryptoClientStream* QuicSimpleClientSession::GetCryptoStream() {
return crypto_stream_.get();
}
void QuicSimpleClientSession::CryptoConnect() {
DCHECK(flow_controller());
crypto_stream_->CryptoConnect();
}
int QuicSimpleClientSession::GetNumSentClientHellos() const {
return crypto_stream_->num_sent_client_hellos();
}
QuicDataStream* QuicSimpleClientSession::CreateIncomingDataStream(
QuicStreamId id) {
DLOG(ERROR) << "Server push not supported";
return nullptr;
}
} // namespace tools
} // namespace net
// 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.
//
// A client specific QuicSession subclass.
#ifndef NET_TOOLS_QUIC_QUIC_SIMPLE_CLIENT_SESSION_H_
#define NET_TOOLS_QUIC_QUIC_SIMPLE_CLIENT_SESSION_H_
#include <string>
#include "base/basictypes.h"
#include "net/quic/quic_client_session_base.h"
#include "net/quic/quic_crypto_client_stream.h"
#include "net/quic/quic_protocol.h"
#include "net/tools/quic/quic_simple_client_stream.h"
namespace net {
class QuicConnection;
class QuicServerId;
class ReliableQuicStream;
namespace tools {
class QuicSimpleClientSession : public QuicClientSessionBase {
public:
QuicSimpleClientSession(const QuicConfig& config, QuicConnection* connection);
~QuicSimpleClientSession() override;
void InitializeSession(const QuicServerId& server_id,
QuicCryptoClientConfig* config);
// QuicSession methods:
QuicSimpleClientStream* CreateOutgoingDataStream() override;
QuicCryptoClientStream* GetCryptoStream() override;
// QuicSimpleClientSessionBase methods:
void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
void OnProofVerifyDetailsAvailable(
const ProofVerifyDetails& verify_details) override;
// Performs a crypto handshake with the server.
void CryptoConnect();
// Returns the number of client hello messages that have been sent on the
// crypto stream. If the handshake has completed then this is one greater
// than the number of round-trips needed for the handshake.
int GetNumSentClientHellos() const;
void set_respect_goaway(bool respect_goaway) {
respect_goaway_ = respect_goaway;
}
protected:
// QuicSession methods:
QuicDataStream* CreateIncomingDataStream(QuicStreamId id) override;
private:
scoped_ptr<QuicCryptoClientStream> crypto_stream_;
// If this is set to false, the client will ignore server GOAWAYs and allow
// the creation of streams regardless of the high chance they will fail.
bool respect_goaway_;
DISALLOW_COPY_AND_ASSIGN(QuicSimpleClientSession);
};
} // namespace tools
} // namespace net
#endif // NET_TOOLS_QUIC_QUIC_SIMPLE_CLIENT_SESSION_H_
// 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.
#include "net/tools/quic/quic_simple_client_session.h"
#include <vector>
#include "net/base/ip_endpoint.h"
#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
#include "net/quic/quic_flags.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_simple_client_stream.h"
#include "testing/gtest/include/gtest/gtest.h"
using net::test::CryptoTestUtils;
using net::test::DefaultQuicConfig;
using net::test::MockConnection;
using net::test::PacketSavingConnection;
using net::test::QuicSessionPeer;
using net::test::SupportedVersions;
using net::test::TestPeerIPAddress;
using net::test::ValueRestore;
using net::test::kTestPort;
using testing::Invoke;
using testing::_;
namespace net {
namespace tools {
namespace test {
namespace {
const char kServerHostname[] = "www.example.org";
const uint16 kPort = 80;
class QuicSimpleClientSessionTest
: public ::testing::TestWithParam<QuicVersion> {
protected:
QuicSimpleClientSessionTest()
: connection_(new PacketSavingConnection(Perspective::IS_CLIENT,
SupportedVersions(GetParam()))) {
session_.reset(new QuicSimpleClientSession(DefaultQuicConfig(),
connection_));
session_->InitializeSession(
QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
&crypto_config_);
// Advance the time, because timers do not like uninitialized times.
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
}
void CompleteCryptoHandshake() {
session_->CryptoConnect();
CryptoTestUtils::HandshakeWithFakeServer(
connection_, session_->GetCryptoStream());
}
PacketSavingConnection* connection_;
scoped_ptr<QuicSimpleClientSession> session_;
QuicCryptoClientConfig crypto_config_;
};
INSTANTIATE_TEST_CASE_P(Tests, QuicSimpleClientSessionTest,
::testing::ValuesIn(QuicSupportedVersions()));
TEST_P(QuicSimpleClientSessionTest, CryptoConnect) {
CompleteCryptoHandshake();
}
TEST_P(QuicSimpleClientSessionTest, MaxNumStreams) {
session_->config()->SetMaxStreamsPerConnection(1, 1);
// Initialize crypto before the client session will create a stream.
CompleteCryptoHandshake();
QuicSimpleClientStream* stream = session_->CreateOutgoingDataStream();
ASSERT_TRUE(stream);
EXPECT_FALSE(session_->CreateOutgoingDataStream());
// Close a stream and ensure I can now open a new one.
session_->CloseStream(stream->id());
stream = session_->CreateOutgoingDataStream();
EXPECT_TRUE(stream);
}
TEST_P(QuicSimpleClientSessionTest, GoAwayReceived) {
CompleteCryptoHandshake();
// After receiving a GoAway, I should no longer be able to create outgoing
// streams.
session_->OnGoAway(QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away."));
EXPECT_EQ(nullptr, session_->CreateOutgoingDataStream());
}
TEST_P(QuicSimpleClientSessionTest, SetFecProtectionFromConfig) {
ValueRestore<bool> old_flag(&FLAGS_enable_quic_fec, true);
// Set FEC config in client's connection options.
QuicTagVector copt;
copt.push_back(kFHDR);
session_->config()->SetConnectionOptionsToSend(copt);
// Doing the handshake should set up FEC config correctly.
CompleteCryptoHandshake();
// Verify that headers stream is always protected and data streams are
// optionally protected.
EXPECT_EQ(FEC_PROTECT_ALWAYS,
QuicSessionPeer::GetHeadersStream(session_.get())->fec_policy());
QuicSimpleClientStream* stream = session_->CreateOutgoingDataStream();
ASSERT_TRUE(stream);
EXPECT_EQ(FEC_PROTECT_OPTIONAL, stream->fec_policy());
}
// Regression test for b/17206611.
TEST_P(QuicSimpleClientSessionTest, InvalidPacketReceived) {
// Create Packet with 0 length.
QuicEncryptedPacket invalid_packet(nullptr, 0, false);
IPEndPoint server_address(TestPeerIPAddress(), kTestPort);
IPEndPoint client_address(TestPeerIPAddress(), kTestPort);
EXPECT_CALL(*reinterpret_cast<MockConnection*>(session_->connection()),
ProcessUdpPacket(server_address, client_address, _))
.WillRepeatedly(
Invoke(reinterpret_cast<MockConnection*>(session_->connection()),
&MockConnection::ReallyProcessUdpPacket));
// Validate that empty packets don't close the connection.
EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(0);
session_->connection()->ProcessUdpPacket(client_address, server_address,
invalid_packet);
// Verifiy that small, invalid packets don't close the connection.
char buf[2] = {0x00, 0x01};
QuicEncryptedPacket valid_packet(buf, 2, false);
// Close connection shouldn't be called.
EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(0);
session_->connection()->ProcessUdpPacket(client_address, server_address,
valid_packet);
}
} // namespace
} // namespace test
} // namespace tools
} // namespace net
// 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.
#include "net/tools/quic/quic_simple_client_stream.h"
#include "net/http/http_response_info.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/tools/quic/quic_simple_client_session.h"
using base::StringPiece;
using std::string;
namespace net {
namespace tools {
static const size_t kHeaderBufInitialSize = 4096;
QuicSimpleClientStream::QuicSimpleClientStream(QuicStreamId id,
QuicSimpleClientSession* session)
: QuicDataStream(id, session),
read_buf_(new GrowableIOBuffer()),
response_headers_received_(false),
header_bytes_read_(0),
header_bytes_written_(0) {
read_buf_->SetCapacity(kHeaderBufInitialSize);
}
QuicSimpleClientStream::~QuicSimpleClientStream() {
}
void QuicSimpleClientStream::OnStreamFrame(const QuicStreamFrame& frame) {
if (!write_side_closed()) {
DVLOG(1) << "Got a response before the request was complete. "
<< "Aborting request.";
CloseWriteSide();
}
QuicDataStream::OnStreamFrame(frame);
}
void QuicSimpleClientStream::OnStreamHeadersComplete(bool fin,
size_t frame_len) {
header_bytes_read_ = frame_len;
QuicDataStream::OnStreamHeadersComplete(fin, frame_len);
}
uint32 QuicSimpleClientStream::ProcessData(const char* data,
uint32 data_len) {
int total_bytes_processed = 0;
// Are we still reading the response headers.
if (!response_headers_received_) {
// Grow the read buffer if necessary.
if (read_buf_->RemainingCapacity() < (int)data_len) {
read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
}
memcpy(read_buf_->data(), data, data_len);
read_buf_->set_offset(read_buf_->offset() + data_len);
ParseResponseHeaders();
} else {
data_.append(data + total_bytes_processed,
data_len - total_bytes_processed);
}
return data_len;
}
void QuicSimpleClientStream::OnFinRead() {
ReliableQuicStream::OnFinRead();
if (!response_headers_received_) {
Reset(QUIC_BAD_APPLICATION_PAYLOAD);
} else if (headers()->GetContentLength() != -1 &&
data_.size() !=
static_cast<size_t>(headers()->GetContentLength())) {
Reset(QUIC_BAD_APPLICATION_PAYLOAD);
}
}
size_t QuicSimpleClientStream::SendRequest(const HttpRequestInfo& headers,
StringPiece body,
bool fin) {
SpdyHeaderBlock header_block;
CreateSpdyHeadersFromHttpRequest(headers,
headers.extra_headers,
SPDY3,
/*direct=*/ true,
&header_block);
bool send_fin_with_headers = fin && body.empty();
size_t bytes_sent = body.size();
header_bytes_written_ =
WriteHeaders(header_block, send_fin_with_headers, nullptr);
bytes_sent += header_bytes_written_;
if (!body.empty()) {
WriteOrBufferData(body, fin, nullptr);
}
return bytes_sent;
}
int QuicSimpleClientStream::ParseResponseHeaders() {
size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
SpdyFramer framer(SPDY3);
SpdyHeaderBlock headers;
char* data = read_buf_->StartOfBuffer();
size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(),
&headers);
if (len == 0) {
return -1;
}
HttpResponseInfo info;
if (!SpdyHeadersToHttpResponse(headers, SPDY3, &info)) {
Reset(QUIC_BAD_APPLICATION_PAYLOAD);
return -1;
}
headers_ = info.headers;
response_headers_received_ = true;
size_t delta = read_buf_len - len;
if (delta > 0) {
data_.append(data + len, delta);
}
return static_cast<int>(len);
}
void QuicSimpleClientStream::SendBody(const string& data, bool fin) {
SendBody(data, fin, nullptr);
}
void QuicSimpleClientStream::SendBody(
const string& data,
bool fin,
QuicAckNotifier::DelegateInterface* delegate) {
WriteOrBufferData(data, fin, delegate);
}
} // namespace tools
} // namespace net
// 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_TOOLS_QUIC_QUIC_SIMPLE_CLIENT_STREAM_H_
#define NET_TOOLS_QUIC_QUIC_SIMPLE_CLIENT_STREAM_H_
#include <sys/types.h>
#include <string>
#include "base/basictypes.h"
#include "base/strings/string_piece.h"
#include "net/base/io_buffer.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/quic/quic_data_stream.h"
#include "net/quic/quic_protocol.h"
#include "net/tools/balsa/balsa_frame.h"
#include "net/tools/balsa/balsa_headers.h"
namespace net {
namespace tools {
class QuicSimpleClientSession;
// All this does right now is send an SPDY request, and aggregate the
// SPDY response.
class QuicSimpleClientStream : public QuicDataStream {
public:
QuicSimpleClientStream(QuicStreamId id, QuicSimpleClientSession* session);
~QuicSimpleClientStream() override;
// Override the base class to close the write side as soon as we get a
// response.
// SPDY/HTTP does not support bidirectional streaming.
void OnStreamFrame(const QuicStreamFrame& frame) override;
// Override the base class to store the size of the headers.
void OnStreamHeadersComplete(bool fin, size_t frame_len) override;
// ReliableQuicStream implementation called by the session when there's
// data for us.
uint32 ProcessData(const char* data, uint32 data_len) override;
void OnFinRead() override;
// Serializes the headers and body, sends it to the server, and
// returns the number of bytes sent.
size_t SendRequest(const HttpRequestInfo& headers,
base::StringPiece body,
bool fin);
// Sends body data to the server, or buffers if it can't be sent immediately.
void SendBody(const std::string& data, bool fin);
// As above, but |delegate| will be notified once |data| is ACKed.
void SendBody(const std::string& data,
bool fin,
QuicAckNotifier::DelegateInterface* delegate);
// Returns the response data.
const std::string& data() { return data_; }
// Returns whatever headers have been received for this stream.
scoped_refptr<HttpResponseHeaders> headers() { return headers_; }
size_t header_bytes_read() const { return header_bytes_read_; }
size_t header_bytes_written() const { return header_bytes_written_; }
// While the server's set_priority shouldn't be called externally, the creator
// of client-side streams should be able to set the priority.
using QuicDataStream::set_priority;
private:
int ParseResponseHeaders();
scoped_refptr<HttpResponseHeaders> headers_;
std::string data_;
scoped_refptr<GrowableIOBuffer> read_buf_;
bool response_headers_received_;
size_t header_bytes_read_;
size_t header_bytes_written_;
DISALLOW_COPY_AND_ASSIGN(QuicSimpleClientStream);
};
} // namespace tools
} // namespace net
#endif // NET_TOOLS_QUIC_QUIC_SIMPLE_CLIENT_STREAM_H_
// Copyright 2013 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.
#include "net/tools/quic/quic_simple_client_stream.h"
#include "base/strings/string_number_conversions.h"
#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/tools/quic/quic_simple_client_session.h"
#include "net/tools/quic/spdy_utils.h"
#include "net/tools/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using net::test::DefaultQuicConfig;
using net::test::MockConnection;
using net::test::SupportedVersions;
using std::string;
using testing::StrictMock;
using testing::TestWithParam;
namespace net {
namespace tools {
namespace test {
namespace {
class QuicSimpleClientStreamTest : public TestWithParam<QuicVersion> {
public:
QuicSimpleClientStreamTest()
: connection_(
new StrictMock<MockConnection>(Perspective::IS_CLIENT,
SupportedVersions(GetParam()))),
session_(DefaultQuicConfig(), connection_),
headers_(new HttpResponseHeaders("")),
body_("hello world") {
session_.InitializeSession(
QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
&crypto_config_);
headers_->ReplaceStatusLine("HTTP/1.1 200 Ok");
headers_->AddHeader("content-length: 11");
SpdyHeaderBlock header_block;
CreateSpdyHeadersFromHttpResponse(*headers_, SPDY3, &header_block);
headers_string_ = SpdyUtils::SerializeUncompressedHeaders(header_block);
// New streams rely on having the peer's flow control receive window
// negotiated in the config.
session_.config()->SetInitialStreamFlowControlWindowToSend(
kInitialStreamFlowControlWindowForTest);
session_.config()->SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
stream_.reset(new QuicSimpleClientStream(3, &session_));
}
StrictMock<MockConnection>* connection_;
QuicSimpleClientSession session_;
scoped_ptr<QuicSimpleClientStream> stream_;
scoped_refptr<HttpResponseHeaders> headers_;
string headers_string_;
string body_;
QuicCryptoClientConfig crypto_config_;
};
INSTANTIATE_TEST_CASE_P(Tests, QuicSimpleClientStreamTest,
::testing::ValuesIn(QuicSupportedVersions()));
TEST_P(QuicSimpleClientStreamTest, TestFraming) {
EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
headers_string_.c_str(), headers_string_.size()));
EXPECT_EQ(body_.size(),
stream_->ProcessData(body_.c_str(), body_.size()));
EXPECT_EQ(200, stream_->headers()->response_code());
EXPECT_EQ(body_, stream_->data());
}
TEST_P(QuicSimpleClientStreamTest, TestFramingOnePacket) {
string message = headers_string_ + body_;
EXPECT_EQ(message.size(), stream_->ProcessData(
message.c_str(), message.size()));
EXPECT_EQ(200, stream_->headers()->response_code());
EXPECT_EQ(body_, stream_->data());
}
TEST_P(QuicSimpleClientStreamTest, DISABLED_TestFramingExtraData) {
string large_body = "hello world!!!!!!";
EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
headers_string_.c_str(), headers_string_.size()));
// The headers should parse successfully.
EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error());
EXPECT_EQ(200, stream_->headers()->response_code());
EXPECT_CALL(*connection_,
SendRstStream(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD, 0));
stream_->ProcessData(large_body.c_str(), large_body.size());
EXPECT_NE(QUIC_STREAM_NO_ERROR, stream_->stream_error());
}
TEST_P(QuicSimpleClientStreamTest, TestNoBidirectionalStreaming) {
QuicStreamFrame frame(3, false, 3, MakeIOVector("asd"));
EXPECT_FALSE(stream_->write_side_closed());
stream_->OnStreamFrame(frame);
EXPECT_TRUE(stream_->write_side_closed());
}
} // namespace
} // namespace test
} // namespace tools
} // namespace net
......@@ -100,9 +100,9 @@ bool QuicSpdyClientStream::ParseResponseHeaders(const char* data,
return true;
}
ssize_t QuicSpdyClientStream::SendRequest(const SpdyHeaderBlock& headers,
StringPiece body,
bool fin) {
size_t QuicSpdyClientStream::SendRequest(const SpdyHeaderBlock& headers,
StringPiece body,
bool fin) {
bool send_fin_with_headers = fin && body.empty();
size_t bytes_sent = body.size();
header_bytes_written_ =
......
......@@ -40,9 +40,9 @@ class QuicSpdyClientStream : public QuicDataStream {
// Serializes the headers and body, sends it to the server, and
// returns the number of bytes sent.
ssize_t SendRequest(const SpdyHeaderBlock& headers,
base::StringPiece body,
bool fin);
size_t SendRequest(const SpdyHeaderBlock& headers,
base::StringPiece body,
bool fin);
// Sends body data to the server, or buffers if it can't be sent immediately.
void SendBody(const std::string& data, bool fin);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment