quic_proxy_client_socket.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. // Copyright (c) 2017 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.
  4. #include "net/quic/quic_proxy_client_socket.h"
  5. #include <cstdio>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/values.h"
  10. #include "net/base/proxy_delegate.h"
  11. #include "net/http/http_auth_controller.h"
  12. #include "net/http/http_log_util.h"
  13. #include "net/http/http_response_headers.h"
  14. #include "net/log/net_log_source.h"
  15. #include "net/log/net_log_source_type.h"
  16. #include "net/quic/quic_http_utils.h"
  17. #include "net/spdy/spdy_http_utils.h"
  18. #include "net/traffic_annotation/network_traffic_annotation.h"
  19. namespace net {
  20. QuicProxyClientSocket::QuicProxyClientSocket(
  21. std::unique_ptr<QuicChromiumClientStream::Handle> stream,
  22. std::unique_ptr<QuicChromiumClientSession::Handle> session,
  23. const ProxyServer& proxy_server,
  24. const std::string& user_agent,
  25. const HostPortPair& endpoint,
  26. const NetLogWithSource& net_log,
  27. scoped_refptr<HttpAuthController> auth_controller,
  28. ProxyDelegate* proxy_delegate)
  29. : stream_(std::move(stream)),
  30. session_(std::move(session)),
  31. endpoint_(endpoint),
  32. auth_(std::move(auth_controller)),
  33. proxy_server_(proxy_server),
  34. proxy_delegate_(proxy_delegate),
  35. user_agent_(user_agent),
  36. net_log_(net_log) {
  37. DCHECK(stream_->IsOpen());
  38. request_.method = "CONNECT";
  39. request_.url = GURL("https://" + endpoint.ToString());
  40. net_log_.BeginEventReferencingSource(NetLogEventType::SOCKET_ALIVE,
  41. net_log_.source());
  42. net_log_.AddEventReferencingSource(
  43. NetLogEventType::HTTP2_PROXY_CLIENT_SESSION, stream_->net_log().source());
  44. }
  45. QuicProxyClientSocket::~QuicProxyClientSocket() {
  46. Disconnect();
  47. net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE);
  48. }
  49. const HttpResponseInfo* QuicProxyClientSocket::GetConnectResponseInfo() const {
  50. return response_.headers.get() ? &response_ : nullptr;
  51. }
  52. const scoped_refptr<HttpAuthController>&
  53. QuicProxyClientSocket::GetAuthController() const {
  54. return auth_;
  55. }
  56. int QuicProxyClientSocket::RestartWithAuth(CompletionOnceCallback callback) {
  57. // A QUIC Stream can only handle a single request, so the underlying
  58. // stream may not be reused and a new QuicProxyClientSocket must be
  59. // created (possibly on top of the same QUIC Session).
  60. next_state_ = STATE_DISCONNECTED;
  61. return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
  62. }
  63. // Ignore priority changes, just use priority of initial request. Since multiple
  64. // requests are pooled on the QuicProxyClientSocket, reprioritization doesn't
  65. // really work.
  66. //
  67. // TODO(mmenke): Use a single priority value for all QuicProxyClientSockets,
  68. // regardless of what priority they're created with.
  69. void QuicProxyClientSocket::SetStreamPriority(RequestPriority priority) {}
  70. // Sends a HEADERS frame to the proxy with a CONNECT request
  71. // for the specified endpoint. Waits for the server to send back
  72. // a HEADERS frame. OK will be returned if the status is 200.
  73. // ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status.
  74. // In any of these cases, Read() may be called to retrieve the HTTP
  75. // response body. Any other return values should be considered fatal.
  76. int QuicProxyClientSocket::Connect(CompletionOnceCallback callback) {
  77. DCHECK(connect_callback_.is_null());
  78. if (!stream_->IsOpen())
  79. return ERR_CONNECTION_CLOSED;
  80. DCHECK_EQ(STATE_DISCONNECTED, next_state_);
  81. next_state_ = STATE_GENERATE_AUTH_TOKEN;
  82. int rv = DoLoop(OK);
  83. if (rv == ERR_IO_PENDING)
  84. connect_callback_ = std::move(callback);
  85. return rv;
  86. }
  87. void QuicProxyClientSocket::Disconnect() {
  88. connect_callback_.Reset();
  89. read_callback_.Reset();
  90. read_buf_ = nullptr;
  91. write_callback_.Reset();
  92. write_buf_len_ = 0;
  93. next_state_ = STATE_DISCONNECTED;
  94. stream_->Reset(quic::QUIC_STREAM_CANCELLED);
  95. }
  96. bool QuicProxyClientSocket::IsConnected() const {
  97. return next_state_ == STATE_CONNECT_COMPLETE && stream_->IsOpen();
  98. }
  99. bool QuicProxyClientSocket::IsConnectedAndIdle() const {
  100. return IsConnected() && !stream_->HasBytesToRead();
  101. }
  102. const NetLogWithSource& QuicProxyClientSocket::NetLog() const {
  103. return net_log_;
  104. }
  105. bool QuicProxyClientSocket::WasEverUsed() const {
  106. return session_->WasEverUsed();
  107. }
  108. bool QuicProxyClientSocket::WasAlpnNegotiated() const {
  109. // Do not delegate to `session_`. While `session_` negotiates ALPN with the
  110. // proxy, this object represents the tunneled TCP connection to the origin.
  111. return false;
  112. }
  113. NextProto QuicProxyClientSocket::GetNegotiatedProtocol() const {
  114. // Do not delegate to `session_`. While `session_` negotiates ALPN with the
  115. // proxy, this object represents the tunneled TCP connection to the origin.
  116. return kProtoUnknown;
  117. }
  118. bool QuicProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
  119. // Do not delegate to `session_`. While `session_` has a secure channel to the
  120. // proxy, this object represents the tunneled TCP connection to the origin.
  121. return false;
  122. }
  123. int64_t QuicProxyClientSocket::GetTotalReceivedBytes() const {
  124. return stream_->NumBytesConsumed();
  125. }
  126. void QuicProxyClientSocket::ApplySocketTag(const SocketTag& tag) {
  127. // In the case of a connection to the proxy using HTTP/2 or HTTP/3 where the
  128. // underlying socket may multiplex multiple streams, applying this request's
  129. // socket tag to the multiplexed session would incorrectly apply the socket
  130. // tag to all mutliplexed streams. Fortunately socket tagging is only
  131. // supported on Android without the data reduction proxy, so only simple HTTP
  132. // proxies are supported, so proxies won't be using HTTP/2 or HTTP/3. Enforce
  133. // that a specific (non-default) tag isn't being applied.
  134. CHECK(tag == SocketTag());
  135. }
  136. int QuicProxyClientSocket::Read(IOBuffer* buf,
  137. int buf_len,
  138. CompletionOnceCallback callback) {
  139. DCHECK(connect_callback_.is_null());
  140. DCHECK(read_callback_.is_null());
  141. DCHECK(!read_buf_);
  142. if (next_state_ == STATE_DISCONNECTED)
  143. return ERR_SOCKET_NOT_CONNECTED;
  144. if (!stream_->IsOpen()) {
  145. return 0;
  146. }
  147. int rv =
  148. stream_->ReadBody(buf, buf_len,
  149. base::BindOnce(&QuicProxyClientSocket::OnReadComplete,
  150. weak_factory_.GetWeakPtr()));
  151. if (rv == ERR_IO_PENDING) {
  152. read_callback_ = std::move(callback);
  153. read_buf_ = buf;
  154. } else if (rv == 0) {
  155. net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, 0,
  156. nullptr);
  157. } else if (rv > 0) {
  158. net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, rv,
  159. buf->data());
  160. }
  161. return rv;
  162. }
  163. void QuicProxyClientSocket::OnReadComplete(int rv) {
  164. if (!stream_->IsOpen())
  165. rv = 0;
  166. if (!read_callback_.is_null()) {
  167. DCHECK(read_buf_);
  168. if (rv >= 0) {
  169. net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, rv,
  170. read_buf_->data());
  171. }
  172. read_buf_ = nullptr;
  173. std::move(read_callback_).Run(rv);
  174. }
  175. }
  176. int QuicProxyClientSocket::Write(
  177. IOBuffer* buf,
  178. int buf_len,
  179. CompletionOnceCallback callback,
  180. const NetworkTrafficAnnotationTag& traffic_annotation) {
  181. DCHECK(connect_callback_.is_null());
  182. DCHECK(write_callback_.is_null());
  183. if (next_state_ != STATE_CONNECT_COMPLETE)
  184. return ERR_SOCKET_NOT_CONNECTED;
  185. net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_SENT, buf_len,
  186. buf->data());
  187. int rv = stream_->WriteStreamData(
  188. base::StringPiece(buf->data(), buf_len), false,
  189. base::BindOnce(&QuicProxyClientSocket::OnWriteComplete,
  190. weak_factory_.GetWeakPtr()));
  191. if (rv == OK)
  192. return buf_len;
  193. if (rv == ERR_IO_PENDING) {
  194. write_callback_ = std::move(callback);
  195. write_buf_len_ = buf_len;
  196. }
  197. return rv;
  198. }
  199. void QuicProxyClientSocket::OnWriteComplete(int rv) {
  200. if (!write_callback_.is_null()) {
  201. if (rv == OK)
  202. rv = write_buf_len_;
  203. write_buf_len_ = 0;
  204. std::move(write_callback_).Run(rv);
  205. }
  206. }
  207. int QuicProxyClientSocket::SetReceiveBufferSize(int32_t size) {
  208. return ERR_NOT_IMPLEMENTED;
  209. }
  210. int QuicProxyClientSocket::SetSendBufferSize(int32_t size) {
  211. return ERR_NOT_IMPLEMENTED;
  212. }
  213. int QuicProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
  214. return IsConnected() ? session_->GetPeerAddress(address)
  215. : ERR_SOCKET_NOT_CONNECTED;
  216. }
  217. int QuicProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
  218. return IsConnected() ? session_->GetSelfAddress(address)
  219. : ERR_SOCKET_NOT_CONNECTED;
  220. }
  221. void QuicProxyClientSocket::OnIOComplete(int result) {
  222. DCHECK_NE(STATE_DISCONNECTED, next_state_);
  223. int rv = DoLoop(result);
  224. if (rv != ERR_IO_PENDING) {
  225. // Connect() finished (successfully or unsuccessfully).
  226. DCHECK(!connect_callback_.is_null());
  227. std::move(connect_callback_).Run(rv);
  228. }
  229. }
  230. int QuicProxyClientSocket::DoLoop(int last_io_result) {
  231. DCHECK_NE(next_state_, STATE_DISCONNECTED);
  232. int rv = last_io_result;
  233. do {
  234. State state = next_state_;
  235. next_state_ = STATE_DISCONNECTED;
  236. switch (state) {
  237. case STATE_GENERATE_AUTH_TOKEN:
  238. DCHECK_EQ(OK, rv);
  239. rv = DoGenerateAuthToken();
  240. break;
  241. case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
  242. rv = DoGenerateAuthTokenComplete(rv);
  243. break;
  244. case STATE_SEND_REQUEST:
  245. DCHECK_EQ(OK, rv);
  246. net_log_.BeginEvent(
  247. NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
  248. rv = DoSendRequest();
  249. break;
  250. case STATE_SEND_REQUEST_COMPLETE:
  251. net_log_.EndEventWithNetErrorCode(
  252. NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
  253. rv = DoSendRequestComplete(rv);
  254. break;
  255. case STATE_READ_REPLY:
  256. rv = DoReadReply();
  257. break;
  258. case STATE_READ_REPLY_COMPLETE:
  259. rv = DoReadReplyComplete(rv);
  260. net_log_.EndEventWithNetErrorCode(
  261. NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
  262. break;
  263. default:
  264. NOTREACHED() << "bad state";
  265. rv = ERR_UNEXPECTED;
  266. break;
  267. }
  268. } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED &&
  269. next_state_ != STATE_CONNECT_COMPLETE);
  270. return rv;
  271. }
  272. int QuicProxyClientSocket::DoGenerateAuthToken() {
  273. next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
  274. return auth_->MaybeGenerateAuthToken(
  275. &request_,
  276. base::BindOnce(&QuicProxyClientSocket::OnIOComplete,
  277. weak_factory_.GetWeakPtr()),
  278. net_log_);
  279. }
  280. int QuicProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
  281. DCHECK_NE(ERR_IO_PENDING, result);
  282. if (result == OK)
  283. next_state_ = STATE_SEND_REQUEST;
  284. return result;
  285. }
  286. int QuicProxyClientSocket::DoSendRequest() {
  287. next_state_ = STATE_SEND_REQUEST_COMPLETE;
  288. // Add Proxy-Authentication header if necessary.
  289. HttpRequestHeaders authorization_headers;
  290. if (auth_->HaveAuth()) {
  291. auth_->AddAuthorizationHeader(&authorization_headers);
  292. }
  293. if (proxy_delegate_) {
  294. HttpRequestHeaders proxy_delegate_headers;
  295. proxy_delegate_->OnBeforeTunnelRequest(proxy_server_,
  296. &proxy_delegate_headers);
  297. request_.extra_headers.MergeFrom(proxy_delegate_headers);
  298. }
  299. std::string request_line;
  300. BuildTunnelRequest(endpoint_, authorization_headers, user_agent_,
  301. &request_line, &request_.extra_headers);
  302. NetLogRequestHeaders(net_log_,
  303. NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
  304. request_line, &request_.extra_headers);
  305. spdy::Http2HeaderBlock headers;
  306. CreateSpdyHeadersFromHttpRequest(request_, request_.extra_headers, &headers);
  307. return stream_->WriteHeaders(std::move(headers), false, nullptr);
  308. }
  309. int QuicProxyClientSocket::DoSendRequestComplete(int result) {
  310. if (result >= 0) {
  311. // Wait for HEADERS frame from the server
  312. next_state_ = STATE_READ_REPLY; // STATE_READ_REPLY_COMPLETE;
  313. result = OK;
  314. }
  315. if (result >= 0 || result == ERR_IO_PENDING) {
  316. // Emit extra event so can use the same events as HttpProxyClientSocket.
  317. net_log_.BeginEvent(NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
  318. }
  319. return result;
  320. }
  321. int QuicProxyClientSocket::DoReadReply() {
  322. next_state_ = STATE_READ_REPLY_COMPLETE;
  323. int rv = stream_->ReadInitialHeaders(
  324. &response_header_block_,
  325. base::BindOnce(&QuicProxyClientSocket::OnReadResponseHeadersComplete,
  326. weak_factory_.GetWeakPtr()));
  327. if (rv == ERR_IO_PENDING)
  328. return ERR_IO_PENDING;
  329. if (rv < 0)
  330. return rv;
  331. return ProcessResponseHeaders(response_header_block_);
  332. }
  333. int QuicProxyClientSocket::DoReadReplyComplete(int result) {
  334. if (result < 0)
  335. return result;
  336. // Require the "HTTP/1.x" status line for SSL CONNECT.
  337. if (response_.headers->GetHttpVersion() < HttpVersion(1, 0))
  338. return ERR_TUNNEL_CONNECTION_FAILED;
  339. NetLogResponseHeaders(
  340. net_log_, NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
  341. response_.headers.get());
  342. if (proxy_delegate_) {
  343. int rv = proxy_delegate_->OnTunnelHeadersReceived(proxy_server_,
  344. *response_.headers);
  345. if (rv != OK) {
  346. DCHECK_NE(ERR_IO_PENDING, rv);
  347. return rv;
  348. }
  349. }
  350. switch (response_.headers->response_code()) {
  351. case 200: // OK
  352. next_state_ = STATE_CONNECT_COMPLETE;
  353. return OK;
  354. case 407: // Proxy Authentication Required
  355. next_state_ = STATE_CONNECT_COMPLETE;
  356. SanitizeProxyAuth(response_);
  357. return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
  358. default:
  359. // Ignore response to avoid letting the proxy impersonate the target
  360. // server. (See http://crbug.com/137891.)
  361. return ERR_TUNNEL_CONNECTION_FAILED;
  362. }
  363. }
  364. void QuicProxyClientSocket::OnReadResponseHeadersComplete(int result) {
  365. // Convert the now-populated spdy::Http2HeaderBlock to HttpResponseInfo
  366. if (result > 0)
  367. result = ProcessResponseHeaders(response_header_block_);
  368. if (result != ERR_IO_PENDING)
  369. OnIOComplete(result);
  370. }
  371. int QuicProxyClientSocket::ProcessResponseHeaders(
  372. const spdy::Http2HeaderBlock& headers) {
  373. if (SpdyHeadersToHttpResponse(headers, &response_) != OK) {
  374. DLOG(WARNING) << "Invalid headers";
  375. return ERR_QUIC_PROTOCOL_ERROR;
  376. }
  377. return OK;
  378. }
  379. } // namespace net