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 "net/base/net_errors.h"
10 #include "net/http/http_request_info.h"
11 #include "net/http/http_response_info.h"
12 #include "net/quic/crypto/quic_random.h"
13 #include "net/quic/quic_connection.h"
14 #include "net/quic/quic_connection_helper.h"
15 #include "net/quic/quic_default_packet_writer.h"
16 #include "net/quic/quic_protocol.h"
17 #include "net/quic/quic_server_id.h"
18 #include "net/spdy/spdy_http_utils.h"
19 #include "net/udp/udp_client_socket.h"
27 QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address
,
28 const QuicServerId
& server_id
,
29 const QuicVersionVector
& supported_versions
)
30 : server_address_(server_address
),
31 server_id_(server_id
),
33 helper_(CreateQuicConnectionHelper()),
35 supported_versions_(supported_versions
),
39 QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address
,
40 const QuicServerId
& server_id
,
41 const QuicVersionVector
& supported_versions
,
42 const QuicConfig
& config
)
43 : server_address_(server_address
),
44 server_id_(server_id
),
47 helper_(CreateQuicConnectionHelper()),
49 supported_versions_(supported_versions
),
53 QuicSimpleClient::~QuicSimpleClient() {
55 session()->connection()->SendConnectionClosePacket(
56 QUIC_PEER_GOING_AWAY
, "");
60 bool QuicSimpleClient::Initialize() {
61 DCHECK(!initialized_
);
63 if (!CreateUDPSocket()) {
71 QuicSimpleClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
72 QuicPacketWriter
* writer
)
75 QuicSimpleClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
77 QuicPacketWriter
* QuicSimpleClient::DummyPacketWriterFactory::Create(
78 QuicConnection
* /*connection*/) const {
82 bool QuicSimpleClient::CreateUDPSocket() {
83 scoped_ptr
<UDPClientSocket
> socket(
84 new UDPClientSocket(DatagramSocket::DEFAULT_BIND
,
89 int address_family
= server_address_
.GetSockAddrFamily();
90 if (bind_to_address_
.size() != 0) {
91 client_address_
= IPEndPoint(bind_to_address_
, local_port_
);
92 } else if (address_family
== AF_INET
) {
94 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4
));
95 client_address_
= IPEndPoint(any4
, local_port_
);
98 CHECK(net::ParseIPLiteralToNumber("::", &any6
));
99 client_address_
= IPEndPoint(any6
, local_port_
);
102 int rc
= socket
->Connect(server_address_
);
104 LOG(ERROR
) << "Connect failed: " << ErrorToShortString(rc
);
108 rc
= socket
->SetReceiveBufferSize(kDefaultSocketReceiveBuffer
);
110 LOG(ERROR
) << "SetReceiveBufferSize() failed: " << ErrorToShortString(rc
);
114 rc
= socket
->SetSendBufferSize(kDefaultSocketReceiveBuffer
);
116 LOG(ERROR
) << "SetSendBufferSize() failed: " << ErrorToShortString(rc
);
120 rc
= socket
->GetLocalAddress(&client_address_
);
122 LOG(ERROR
) << "GetLocalAddress failed: " << ErrorToShortString(rc
);
126 socket_
.swap(socket
);
127 packet_reader_
.reset(new QuicPacketReader(socket_
.get(), this,
130 if (socket
!= nullptr) {
137 bool QuicSimpleClient::Connect() {
139 packet_reader_
->StartReading();
140 while (EncryptionBeingEstablished()) {
143 return session_
->connection()->connected();
146 void QuicSimpleClient::StartConnect() {
147 DCHECK(initialized_
);
148 DCHECK(!connected());
150 writer_
.reset(CreateQuicPacketWriter());
151 connection_
= new QuicConnection(GenerateConnectionId(),
154 DummyPacketWriterFactory(writer_
.get()),
155 /* owns_writer= */ false,
156 Perspective::IS_CLIENT
,
157 server_id_
.is_https(),
158 supported_versions_
);
159 session_
.reset(new QuicClientSession(config_
, connection_
));
160 session_
->InitializeSession(server_id_
, &crypto_config_
);
161 session_
->CryptoConnect();
164 bool QuicSimpleClient::EncryptionBeingEstablished() {
165 return !session_
->IsEncryptionEstablished() &&
166 session_
->connection()->connected();
169 void QuicSimpleClient::Disconnect() {
170 DCHECK(initialized_
);
173 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY
);
177 packet_reader_
.reset();
179 initialized_
= false;
182 void QuicSimpleClient::SendRequest(const HttpRequestInfo
& headers
,
183 base::StringPiece body
,
185 QuicSpdyClientStream
* stream
= CreateReliableClientStream();
186 if (stream
== nullptr) {
187 LOG(DFATAL
) << "stream creation failed!";
190 SpdyHeaderBlock header_block
;
191 CreateSpdyHeadersFromHttpRequest(headers
, headers
.extra_headers
, SPDY3
, true,
193 stream
->SendRequest(header_block
, body
, fin
);
194 stream
->set_visitor(this);
197 void QuicSimpleClient::SendRequestAndWaitForResponse(
198 const HttpRequestInfo
& request
,
199 base::StringPiece body
,
201 SendRequest(request
, body
, fin
);
202 while (WaitForEvents()) {}
205 void QuicSimpleClient::SendRequestsAndWaitForResponse(
206 const base::CommandLine::StringVector
& url_list
) {
207 for (size_t i
= 0; i
< url_list
.size(); ++i
) {
208 HttpRequestInfo request
;
209 request
.method
= "GET";
210 request
.url
= GURL(url_list
[i
]);
211 SendRequest(request
, "", true);
214 while (WaitForEvents()) {}
217 QuicSpdyClientStream
* QuicSimpleClient::CreateReliableClientStream() {
222 return session_
->CreateOutgoingDataStream();
225 void QuicSimpleClient::WaitForStreamToClose(QuicStreamId id
) {
228 while (connected() && !session_
->IsClosedStream(id
)) {
233 void QuicSimpleClient::WaitForCryptoHandshakeConfirmed() {
236 while (connected() && !session_
->IsCryptoHandshakeConfirmed()) {
241 bool QuicSimpleClient::WaitForEvents() {
244 base::RunLoop().RunUntilIdle();
245 return session_
->num_active_requests() != 0;
248 void QuicSimpleClient::OnClose(QuicDataStream
* stream
) {
249 QuicSpdyClientStream
* client_stream
=
250 static_cast<QuicSpdyClientStream
*>(stream
);
251 HttpResponseInfo response
;
252 SpdyHeadersToHttpResponse(client_stream
->headers(), SPDY3
, &response
);
253 if (response_listener_
.get() != nullptr) {
254 response_listener_
->OnCompleteResponse(
255 stream
->id(), *response
.headers
, client_stream
->data());
258 // Store response headers and body.
259 if (store_response_
) {
260 latest_response_code_
= client_stream
->response_code();
261 response
.headers
->GetNormalizedHeaders(&latest_response_headers_
);
262 latest_response_body_
= client_stream
->data();
266 bool QuicSimpleClient::connected() const {
267 return session_
.get() && session_
->connection() &&
268 session_
->connection()->connected();
271 bool QuicSimpleClient::goaway_received() const {
272 return session_
!= nullptr && session_
->goaway_received();
275 size_t QuicSimpleClient::latest_response_code() const {
276 LOG_IF(DFATAL
, !store_response_
) << "Response not stored!";
277 return latest_response_code_
;
280 const string
& QuicSimpleClient::latest_response_headers() const {
281 LOG_IF(DFATAL
, !store_response_
) << "Response not stored!";
282 return latest_response_headers_
;
285 const string
& QuicSimpleClient::latest_response_body() const {
286 LOG_IF(DFATAL
, !store_response_
) << "Response not stored!";
287 return latest_response_body_
;
290 QuicConnectionId
QuicSimpleClient::GenerateConnectionId() {
291 return helper_
->GetRandomGenerator()->RandUint64();
294 QuicConnectionHelper
* QuicSimpleClient::CreateQuicConnectionHelper() {
295 return new QuicConnectionHelper(
296 base::MessageLoop::current()->message_loop_proxy().get(),
298 QuicRandom::GetInstance());
301 QuicPacketWriter
* QuicSimpleClient::CreateQuicPacketWriter() {
302 return new QuicDefaultPacketWriter(socket_
.get());
305 void QuicSimpleClient::OnReadError(int result
) {
306 LOG(ERROR
) << "QuicSimpleClient read failed: " << ErrorToShortString(result
);
310 bool QuicSimpleClient::OnPacket(const QuicEncryptedPacket
& packet
,
311 IPEndPoint local_address
,
312 IPEndPoint peer_address
) {
313 session_
->connection()->ProcessUdpPacket(local_address
, peer_address
, packet
);
314 if (!session_
->connection()->connected()) {