blob: 0d99fd178da41d03e175eb9ca88906815417bdd1 [file] [log] [blame]
Andreea Costinase45d54b2020-03-10 09:21:14 +01001// Copyright 2020 The Chromium OS 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#ifndef SYSTEM_PROXY_PROXY_CONNECT_JOB_H_
5#define SYSTEM_PROXY_PROXY_CONNECT_JOB_H_
6
7#include <list>
8#include <memory>
9#include <string>
10#include <string_view>
11#include <vector>
12
13#include <base/callback_forward.h>
Andreea Costinas08a5d182020-04-29 22:12:47 +020014#include <base/cancelable_callback.h>
Andreea Costinase45d54b2020-03-10 09:21:14 +010015#include <base/files/file_descriptor_watcher_posix.h>
16#include <gtest/gtest_prod.h> // for FRIEND_TEST
17
Garrick Evans3388a032020-03-24 11:25:55 +090018namespace patchpanel {
Andreea Costinase45d54b2020-03-10 09:21:14 +010019class SocketForwarder;
20class Socket;
Garrick Evans3388a032020-03-24 11:25:55 +090021} // namespace patchpanel
Andreea Costinase45d54b2020-03-10 09:21:14 +010022
23namespace system_proxy {
24// ProxyConnectJob asynchronously sets up a connection to a remote target on
25// behalf of a client. Internally, it performs the following steps:
26// - waits for the client to send a HTTP connect request;
27// - extracts the target url from the connect request;
28// - requests proxy resolution for the target url and waits for the result;
29// - performs the proxy authentication and connection setup to the remote
30// target.
31class ProxyConnectJob {
32 public:
33 using OnConnectionSetupFinishedCallback = base::OnceCallback<void(
Garrick Evans3388a032020-03-24 11:25:55 +090034 std::unique_ptr<patchpanel::SocketForwarder>, ProxyConnectJob*)>;
Andreea Costinase45d54b2020-03-10 09:21:14 +010035
36 // Will be invoked by ProxyConnectJob to resolve the proxy for |target_url_|.
37 // The passed |callback| is expected to be called with the list of proxy
38 // servers, which will always contain at least one entry, the default proxy.
39 using ResolveProxyCallback = base::OnceCallback<void(
40 const std::string& url,
41 base::OnceCallback<void(const std::list<std::string>&)> callback)>;
42
Garrick Evans3388a032020-03-24 11:25:55 +090043 ProxyConnectJob(std::unique_ptr<patchpanel::Socket> socket,
Andreea Costinase45d54b2020-03-10 09:21:14 +010044 const std::string& credentials,
45 ResolveProxyCallback resolve_proxy_callback,
46 OnConnectionSetupFinishedCallback setup_finished_callback);
47 ProxyConnectJob(const ProxyConnectJob&) = delete;
48 ProxyConnectJob& operator=(const ProxyConnectJob&) = delete;
49 virtual ~ProxyConnectJob();
50
51 // Marks |client_socket_| as non-blocking and adds a watcher that calls
52 // |OnClientReadReady| when the socket is read ready.
53 virtual bool Start();
54 void OnProxyResolution(const std::list<std::string>& proxy_servers);
55
56 friend std::ostream& operator<<(std::ostream& stream,
57 const ProxyConnectJob& job);
58
59 private:
60 friend class ServerProxyTest;
61 friend class ProxyConnectJobTest;
62 FRIEND_TEST(ServerProxyTest, HandlePendingJobs);
Andreea Costinas5862b102020-03-19 14:45:36 +010063 FRIEND_TEST(ServerProxyTest, HandleConnectRequest);
Andreea Costinase45d54b2020-03-10 09:21:14 +010064 FRIEND_TEST(ProxyConnectJobTest, SuccessfulConnection);
Andreea Costinased3f9782020-05-20 17:09:46 +020065 FRIEND_TEST(ProxyConnectJobTest, SuccessfulConnectionAltEnding);
Andreea Costinase45d54b2020-03-10 09:21:14 +010066 FRIEND_TEST(ProxyConnectJobTest, BadHttpRequestWrongMethod);
67 FRIEND_TEST(ProxyConnectJobTest, BadHttpRequestNoEmptyLine);
68
69 // Reads data from the socket into |raw_request| until the first empty line,
70 // which would mark the end of the HTTP request header.
71 // This method does not validate the headers.
72 bool TryReadHttpHeader(std::vector<char>* raw_request);
73
74 // Called when the client socket is ready for reading.
75 void OnClientReadReady();
76
77 // Called from |OnProxyResolution|, after the proxy for |target_url_| is
78 // resolved.
79 void DoCurlServerConnection(const std::string& proxy_url);
80
81 void OnError(const std::string_view& http_error_message);
82
Andreea Costinas08a5d182020-04-29 22:12:47 +020083 void OnClientConnectTimeout();
84
Andreea Costinase45d54b2020-03-10 09:21:14 +010085 std::string target_url_;
86 const std::string credentials_;
87 std::list<std::string> proxy_servers_;
88 ResolveProxyCallback resolve_proxy_callback_;
89 OnConnectionSetupFinishedCallback setup_finished_callback_;
Andreea Costinas08a5d182020-04-29 22:12:47 +020090 base::CancelableClosure client_connect_timeout_callback_;
91
Garrick Evans3388a032020-03-24 11:25:55 +090092 std::unique_ptr<patchpanel::Socket> client_socket_;
Andreea Costinase45d54b2020-03-10 09:21:14 +010093 std::unique_ptr<base::FileDescriptorWatcher::Controller> read_watcher_;
Andreea Costinas833eb7c2020-06-12 11:09:15 +020094 base::WeakPtrFactory<ProxyConnectJob> weak_ptr_factory_{this};
Andreea Costinase45d54b2020-03-10 09:21:14 +010095};
96} // namespace system_proxy
97
98#endif // SYSTEM_PROXY_PROXY_CONNECT_JOB_H_