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"
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
),
35 helper_(CreateQuicConnectionHelper()),
37 supported_versions_(supported_versions
),
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
),
49 helper_(CreateQuicConnectionHelper()),
51 supported_versions_(supported_versions
),
52 initial_max_packet_length_(0),
53 weak_factory_(this) {}
55 QuicSimpleClient::~QuicSimpleClient() {
57 session()->connection()->SendConnectionClosePacket(
58 QUIC_PEER_GOING_AWAY
, "");
62 bool QuicSimpleClient::Initialize() {
63 DCHECK(!initialized_
);
65 if (!CreateUDPSocket()) {
73 QuicSimpleClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
74 QuicPacketWriter
* writer
)
77 QuicSimpleClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
79 QuicPacketWriter
* QuicSimpleClient::DummyPacketWriterFactory::Create(
80 QuicConnection
* /*connection*/) const {
84 bool QuicSimpleClient::CreateUDPSocket() {
85 scoped_ptr
<UDPClientSocket
> socket(
86 new UDPClientSocket(DatagramSocket::DEFAULT_BIND
,
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
) {
96 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4
));
97 client_address_
= IPEndPoint(any4
, local_port_
);
100 CHECK(net::ParseIPLiteralToNumber("::", &any6
));
101 client_address_
= IPEndPoint(any6
, local_port_
);
104 int rc
= socket
->Connect(server_address_
);
106 LOG(ERROR
) << "Connect failed: " << ErrorToShortString(rc
);
110 rc
= socket
->SetReceiveBufferSize(kDefaultSocketReceiveBuffer
);
112 LOG(ERROR
) << "SetReceiveBufferSize() failed: " << ErrorToShortString(rc
);
116 rc
= socket
->SetSendBufferSize(kDefaultSocketReceiveBuffer
);
118 LOG(ERROR
) << "SetSendBufferSize() failed: " << ErrorToShortString(rc
);
122 rc
= socket
->GetLocalAddress(&client_address_
);
124 LOG(ERROR
) << "GetLocalAddress failed: " << ErrorToShortString(rc
);
128 socket_
.swap(socket
);
129 packet_reader_
.reset(new QuicPacketReader(socket_
.get(), this,
132 if (socket
!= nullptr) {
139 bool QuicSimpleClient::Connect() {
141 packet_reader_
->StartReading();
142 while (EncryptionBeingEstablished()) {
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(),
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_
,
171 if (initial_max_packet_length_
!= 0) {
172 session_
->connection()->set_max_packet_length(initial_max_packet_length_
);
174 session_
->Initialize();
175 session_
->CryptoConnect();
178 bool QuicSimpleClient::EncryptionBeingEstablished() {
179 return !session_
->IsEncryptionEstablished() &&
180 session_
->connection()->connected();
183 void QuicSimpleClient::Disconnect() {
184 DCHECK(initialized_
);
187 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY
);
191 packet_reader_
.reset();
193 initialized_
= false;
196 void QuicSimpleClient::SendRequest(const HttpRequestInfo
& headers
,
197 base::StringPiece body
,
199 QuicSpdyClientStream
* stream
= CreateReliableClientStream();
200 if (stream
== nullptr) {
201 LOG(DFATAL
) << "stream creation failed!";
204 SpdyHeaderBlock header_block
;
205 SpdyMajorVersion spdy_version
=
206 SpdyUtils::GetSpdyVersionForQuicVersion(stream
->version());
207 CreateSpdyHeadersFromHttpRequest(headers
, headers
.extra_headers
, spdy_version
,
208 true, &header_block
);
209 stream
->SendRequest(header_block
, body
, fin
);
210 stream
->set_visitor(this);
213 void QuicSimpleClient::SendRequestAndWaitForResponse(
214 const HttpRequestInfo
& request
,
215 base::StringPiece body
,
217 SendRequest(request
, body
, fin
);
218 while (WaitForEvents()) {}
221 void QuicSimpleClient::SendRequestsAndWaitForResponse(
222 const base::CommandLine::StringVector
& url_list
) {
223 for (size_t i
= 0; i
< url_list
.size(); ++i
) {
224 HttpRequestInfo request
;
225 request
.method
= "GET";
226 request
.url
= GURL(url_list
[i
]);
227 SendRequest(request
, "", true);
230 while (WaitForEvents()) {}
233 QuicSpdyClientStream
* QuicSimpleClient::CreateReliableClientStream() {
238 return session_
->CreateOutgoingDynamicStream();
241 void QuicSimpleClient::WaitForStreamToClose(QuicStreamId id
) {
244 while (connected() && !session_
->IsClosedStream(id
)) {
249 void QuicSimpleClient::WaitForCryptoHandshakeConfirmed() {
252 while (connected() && !session_
->IsCryptoHandshakeConfirmed()) {
257 bool QuicSimpleClient::WaitForEvents() {
260 base::RunLoop().RunUntilIdle();
261 return session_
->num_active_requests() != 0;
264 bool QuicSimpleClient::MigrateSocket(const IPAddressNumber
& new_host
) {
269 bind_to_address_
= new_host
;
270 if (!CreateUDPSocket()) {
274 session_
->connection()->SetSelfAddress(client_address_
);
276 QuicPacketWriter
* writer
= CreateQuicPacketWriter();
277 DummyPacketWriterFactory
factory(writer
);
278 if (writer_
.get() != writer
) {
279 writer_
.reset(writer
);
281 session_
->connection()->SetQuicPacketWriter(writer
, false);
286 void QuicSimpleClient::OnClose(QuicDataStream
* stream
) {
287 QuicSpdyClientStream
* client_stream
=
288 static_cast<QuicSpdyClientStream
*>(stream
);
289 HttpResponseInfo response
;
290 SpdyMajorVersion spdy_version
=
291 SpdyUtils::GetSpdyVersionForQuicVersion(client_stream
->version());
292 SpdyHeadersToHttpResponse(client_stream
->headers(), spdy_version
, &response
);
293 if (response_listener_
.get() != nullptr) {
294 response_listener_
->OnCompleteResponse(
295 stream
->id(), *response
.headers
, client_stream
->data());
298 // Store response headers and body.
299 if (store_response_
) {
300 latest_response_code_
= client_stream
->response_code();
301 response
.headers
->GetNormalizedHeaders(&latest_response_headers_
);
302 latest_response_body_
= client_stream
->data();
306 bool QuicSimpleClient::connected() const {
307 return session_
.get() && session_
->connection() &&
308 session_
->connection()->connected();
311 bool QuicSimpleClient::goaway_received() const {
312 return session_
!= nullptr && session_
->goaway_received();
315 size_t QuicSimpleClient::latest_response_code() const {
316 LOG_IF(DFATAL
, !store_response_
) << "Response not stored!";
317 return latest_response_code_
;
320 const string
& QuicSimpleClient::latest_response_headers() const {
321 LOG_IF(DFATAL
, !store_response_
) << "Response not stored!";
322 return latest_response_headers_
;
325 const string
& QuicSimpleClient::latest_response_body() const {
326 LOG_IF(DFATAL
, !store_response_
) << "Response not stored!";
327 return latest_response_body_
;
330 QuicConnectionId
QuicSimpleClient::GenerateConnectionId() {
331 return helper_
->GetRandomGenerator()->RandUint64();
334 QuicConnectionHelper
* QuicSimpleClient::CreateQuicConnectionHelper() {
335 return new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
336 &clock_
, QuicRandom::GetInstance());
339 QuicPacketWriter
* QuicSimpleClient::CreateQuicPacketWriter() {
340 return new QuicDefaultPacketWriter(socket_
.get());
343 void QuicSimpleClient::OnReadError(int result
) {
344 LOG(ERROR
) << "QuicSimpleClient read failed: " << ErrorToShortString(result
);
348 bool QuicSimpleClient::OnPacket(const QuicEncryptedPacket
& packet
,
349 IPEndPoint local_address
,
350 IPEndPoint peer_address
) {
351 session_
->connection()->ProcessUdpPacket(local_address
, peer_address
, packet
);
352 if (!session_
->connection()->connected()) {