base: Make it possible to replace the MessageLoop's task runner
[chromium-blink-merge.git] / net / tools / quic / quic_simple_client.cc
blobbbd314e7a3740209fec374dd277bc4391c32e2c1
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/tools/quic/quic_simple_client.h"
7 #include "base/logging.h"
8 #include "base/run_loop.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "net/base/net_errors.h"
11 #include "net/http/http_request_info.h"
12 #include "net/http/http_response_info.h"
13 #include "net/quic/crypto/quic_random.h"
14 #include "net/quic/quic_connection.h"
15 #include "net/quic/quic_connection_helper.h"
16 #include "net/quic/quic_default_packet_writer.h"
17 #include "net/quic/quic_protocol.h"
18 #include "net/quic/quic_server_id.h"
19 #include "net/quic/spdy_utils.h"
20 #include "net/spdy/spdy_http_utils.h"
21 #include "net/udp/udp_client_socket.h"
23 using std::string;
24 using std::vector;
26 namespace net {
27 namespace tools {
29 QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address,
30 const QuicServerId& server_id,
31 const QuicVersionVector& supported_versions)
32 : server_address_(server_address),
33 server_id_(server_id),
34 local_port_(0),
35 helper_(CreateQuicConnectionHelper()),
36 initialized_(false),
37 supported_versions_(supported_versions),
38 weak_factory_(this) {
41 QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address,
42 const QuicServerId& server_id,
43 const QuicVersionVector& supported_versions,
44 const QuicConfig& config)
45 : server_address_(server_address),
46 server_id_(server_id),
47 config_(config),
48 local_port_(0),
49 helper_(CreateQuicConnectionHelper()),
50 initialized_(false),
51 supported_versions_(supported_versions),
52 weak_factory_(this) {
55 QuicSimpleClient::~QuicSimpleClient() {
56 if (connected()) {
57 session()->connection()->SendConnectionClosePacket(
58 QUIC_PEER_GOING_AWAY, "");
62 bool QuicSimpleClient::Initialize() {
63 DCHECK(!initialized_);
65 if (!CreateUDPSocket()) {
66 return false;
69 initialized_ = true;
70 return true;
73 QuicSimpleClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
74 QuicPacketWriter* writer)
75 : writer_(writer) {}
77 QuicSimpleClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
79 QuicPacketWriter* QuicSimpleClient::DummyPacketWriterFactory::Create(
80 QuicConnection* /*connection*/) const {
81 return writer_;
84 bool QuicSimpleClient::CreateUDPSocket() {
85 scoped_ptr<UDPClientSocket> socket(
86 new UDPClientSocket(DatagramSocket::DEFAULT_BIND,
87 RandIntCallback(),
88 &net_log_,
89 NetLog::Source()));
91 int address_family = server_address_.GetSockAddrFamily();
92 if (bind_to_address_.size() != 0) {
93 client_address_ = IPEndPoint(bind_to_address_, local_port_);
94 } else if (address_family == AF_INET) {
95 IPAddressNumber any4;
96 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
97 client_address_ = IPEndPoint(any4, local_port_);
98 } else {
99 IPAddressNumber any6;
100 CHECK(net::ParseIPLiteralToNumber("::", &any6));
101 client_address_ = IPEndPoint(any6, local_port_);
104 int rc = socket->Connect(server_address_);
105 if (rc != OK) {
106 LOG(ERROR) << "Connect failed: " << ErrorToShortString(rc);
107 return false;
110 rc = socket->SetReceiveBufferSize(kDefaultSocketReceiveBuffer);
111 if (rc != OK) {
112 LOG(ERROR) << "SetReceiveBufferSize() failed: " << ErrorToShortString(rc);
113 return false;
116 rc = socket->SetSendBufferSize(kDefaultSocketReceiveBuffer);
117 if (rc != OK) {
118 LOG(ERROR) << "SetSendBufferSize() failed: " << ErrorToShortString(rc);
119 return false;
122 rc = socket->GetLocalAddress(&client_address_);
123 if (rc != OK) {
124 LOG(ERROR) << "GetLocalAddress failed: " << ErrorToShortString(rc);
125 return false;
128 socket_.swap(socket);
129 packet_reader_.reset(new QuicPacketReader(socket_.get(), this,
130 BoundNetLog()));
132 if (socket != nullptr) {
133 socket->Close();
136 return true;
139 bool QuicSimpleClient::Connect() {
140 StartConnect();
141 packet_reader_->StartReading();
142 while (EncryptionBeingEstablished()) {
143 WaitForEvents();
145 return session_->connection()->connected();
148 QuicClientSession* QuicSimpleClient::CreateQuicClientSession(
149 const QuicConfig& config,
150 QuicConnection* connection,
151 const QuicServerId& server_id,
152 QuicCryptoClientConfig* crypto_config) {
153 return new QuicClientSession(config, connection, server_id_, &crypto_config_);
156 void QuicSimpleClient::StartConnect() {
157 DCHECK(initialized_);
158 DCHECK(!connected());
160 writer_.reset(CreateQuicPacketWriter());
161 connection_ = new QuicConnection(GenerateConnectionId(),
162 server_address_,
163 helper_.get(),
164 DummyPacketWriterFactory(writer_.get()),
165 /* owns_writer= */ false,
166 Perspective::IS_CLIENT,
167 server_id_.is_https(),
168 supported_versions_);
169 session_.reset(CreateQuicClientSession(config_, connection_, server_id_,
170 &crypto_config_));
171 session_->Initialize();
172 session_->CryptoConnect();
175 bool QuicSimpleClient::EncryptionBeingEstablished() {
176 return !session_->IsEncryptionEstablished() &&
177 session_->connection()->connected();
180 void QuicSimpleClient::Disconnect() {
181 DCHECK(initialized_);
183 if (connected()) {
184 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
187 writer_.reset();
188 packet_reader_.reset();
190 initialized_ = false;
193 void QuicSimpleClient::SendRequest(const HttpRequestInfo& headers,
194 base::StringPiece body,
195 bool fin) {
196 QuicSpdyClientStream* stream = CreateReliableClientStream();
197 if (stream == nullptr) {
198 LOG(DFATAL) << "stream creation failed!";
199 return;
201 SpdyHeaderBlock header_block;
202 SpdyMajorVersion spdy_version =
203 SpdyUtils::GetSpdyVersionForQuicVersion(stream->version());
204 CreateSpdyHeadersFromHttpRequest(headers, headers.extra_headers, spdy_version,
205 true, &header_block);
206 stream->SendRequest(header_block, body, fin);
207 stream->set_visitor(this);
210 void QuicSimpleClient::SendRequestAndWaitForResponse(
211 const HttpRequestInfo& request,
212 base::StringPiece body,
213 bool fin) {
214 SendRequest(request, body, fin);
215 while (WaitForEvents()) {}
218 void QuicSimpleClient::SendRequestsAndWaitForResponse(
219 const base::CommandLine::StringVector& url_list) {
220 for (size_t i = 0; i < url_list.size(); ++i) {
221 HttpRequestInfo request;
222 request.method = "GET";
223 request.url = GURL(url_list[i]);
224 SendRequest(request, "", true);
227 while (WaitForEvents()) {}
230 QuicSpdyClientStream* QuicSimpleClient::CreateReliableClientStream() {
231 if (!connected()) {
232 return nullptr;
235 return session_->CreateOutgoingDynamicStream();
238 void QuicSimpleClient::WaitForStreamToClose(QuicStreamId id) {
239 DCHECK(connected());
241 while (connected() && !session_->IsClosedStream(id)) {
242 WaitForEvents();
246 void QuicSimpleClient::WaitForCryptoHandshakeConfirmed() {
247 DCHECK(connected());
249 while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
250 WaitForEvents();
254 bool QuicSimpleClient::WaitForEvents() {
255 DCHECK(connected());
257 base::RunLoop().RunUntilIdle();
258 return session_->num_active_requests() != 0;
261 void QuicSimpleClient::OnClose(QuicDataStream* stream) {
262 QuicSpdyClientStream* client_stream =
263 static_cast<QuicSpdyClientStream*>(stream);
264 HttpResponseInfo response;
265 SpdyMajorVersion spdy_version =
266 SpdyUtils::GetSpdyVersionForQuicVersion(client_stream->version());
267 SpdyHeadersToHttpResponse(client_stream->headers(), spdy_version, &response);
268 if (response_listener_.get() != nullptr) {
269 response_listener_->OnCompleteResponse(
270 stream->id(), *response.headers, client_stream->data());
273 // Store response headers and body.
274 if (store_response_) {
275 latest_response_code_ = client_stream->response_code();
276 response.headers->GetNormalizedHeaders(&latest_response_headers_);
277 latest_response_body_ = client_stream->data();
281 bool QuicSimpleClient::connected() const {
282 return session_.get() && session_->connection() &&
283 session_->connection()->connected();
286 bool QuicSimpleClient::goaway_received() const {
287 return session_ != nullptr && session_->goaway_received();
290 size_t QuicSimpleClient::latest_response_code() const {
291 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
292 return latest_response_code_;
295 const string& QuicSimpleClient::latest_response_headers() const {
296 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
297 return latest_response_headers_;
300 const string& QuicSimpleClient::latest_response_body() const {
301 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
302 return latest_response_body_;
305 QuicConnectionId QuicSimpleClient::GenerateConnectionId() {
306 return helper_->GetRandomGenerator()->RandUint64();
309 QuicConnectionHelper* QuicSimpleClient::CreateQuicConnectionHelper() {
310 return new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
311 &clock_, QuicRandom::GetInstance());
314 QuicPacketWriter* QuicSimpleClient::CreateQuicPacketWriter() {
315 return new QuicDefaultPacketWriter(socket_.get());
318 void QuicSimpleClient::OnReadError(int result) {
319 LOG(ERROR) << "QuicSimpleClient read failed: " << ErrorToShortString(result);
320 Disconnect();
323 bool QuicSimpleClient::OnPacket(const QuicEncryptedPacket& packet,
324 IPEndPoint local_address,
325 IPEndPoint peer_address) {
326 session_->connection()->ProcessUdpPacket(local_address, peer_address, packet);
327 if (!session_->connection()->connected()) {
328 return false;
331 return true;
334 } // namespace tools
335 } // namespace net