xref: /aosp_15_r20/external/cronet/net/test/spawned_test_server/remote_test_server_spawner_request.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/test/spawned_test_server/remote_test_server_spawner_request.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/functional/bind.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "build/build_config.h"
16 #include "net/base/elements_upload_data_stream.h"
17 #include "net/base/io_buffer.h"
18 #include "net/base/port_util.h"
19 #include "net/base/upload_bytes_element_reader.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
22 #include "net/url_request/url_request.h"
23 #include "net/url_request/url_request_context.h"
24 #include "net/url_request/url_request_context_builder.h"
25 #include "net/url_request/url_request_test_util.h"
26 #include "url/gurl.h"
27 
28 namespace net {
29 
30 static const int kBufferSize = 2048;
31 
32 class RemoteTestServerSpawnerRequest::Core : public URLRequest::Delegate {
33  public:
34   Core();
35 
36   Core(const Core&) = delete;
37   Core& operator=(const Core&) = delete;
38 
39   ~Core() override;
40 
41   void SendRequest(const GURL& url, const std::string& post_data);
42 
43   // Blocks until request is finished. If |response| isn't nullptr then server
44   // response is copied to *response. Returns true if the request was completed
45   // successfully.
46   [[nodiscard]] bool WaitForCompletion(std::string* response);
47 
48  private:
49   // URLRequest::Delegate methods.
50   void OnResponseStarted(URLRequest* request, int net_error) override;
51   void OnReadCompleted(URLRequest* request, int num_bytes) override;
52 
53   void ReadResponse();
54   void OnCommandCompleted(int net_error);
55 
56   // Request results.
57   int result_code_ = 0;
58   std::string data_received_;
59 
60   // WaitableEvent to notify when the request is finished.
61   base::WaitableEvent event_;
62 
63   std::unique_ptr<URLRequestContext> context_;
64   std::unique_ptr<URLRequest> request_;
65 
66   scoped_refptr<IOBuffer> read_buffer_;
67 
68   THREAD_CHECKER(thread_checker_);
69 };
70 
Core()71 RemoteTestServerSpawnerRequest::Core::Core()
72     : event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
73              base::WaitableEvent::InitialState::NOT_SIGNALED),
74       read_buffer_(base::MakeRefCounted<IOBufferWithSize>(kBufferSize)) {
75   DETACH_FROM_THREAD(thread_checker_);
76 }
77 
SendRequest(const GURL & url,const std::string & post_data)78 void RemoteTestServerSpawnerRequest::Core::SendRequest(
79     const GURL& url,
80     const std::string& post_data) {
81   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
82 
83   // Prepare the URLRequest for sending the command.
84   DCHECK(!request_.get());
85   context_ = CreateTestURLRequestContextBuilder()->Build();
86   request_ = context_->CreateRequest(url, DEFAULT_PRIORITY, this,
87                                      TRAFFIC_ANNOTATION_FOR_TESTS);
88 
89   if (post_data.empty()) {
90     request_->set_method("GET");
91   } else {
92     request_->set_method("POST");
93     std::unique_ptr<UploadElementReader> reader(
94         UploadOwnedBytesElementReader::CreateWithString(post_data));
95     request_->set_upload(
96         ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
97     request_->SetExtraRequestHeaderByName(HttpRequestHeaders::kContentType,
98                                           "application/json",
99                                           /*overwrite=*/true);
100   }
101 
102   request_->Start();
103 }
104 
~Core()105 RemoteTestServerSpawnerRequest::Core::~Core() {
106   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
107 }
108 
WaitForCompletion(std::string * response)109 bool RemoteTestServerSpawnerRequest::Core::WaitForCompletion(
110     std::string* response) {
111   // Called by RemoteTestServerSpawnerRequest::WaitForCompletion() on the main
112   // thread.
113 
114   event_.Wait();
115   if (response)
116     *response = data_received_;
117   return result_code_ == OK;
118 }
119 
OnCommandCompleted(int net_error)120 void RemoteTestServerSpawnerRequest::Core::OnCommandCompleted(int net_error) {
121   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
122   DCHECK_NE(ERR_IO_PENDING, net_error);
123   DCHECK(!event_.IsSignaled());
124 
125   // If request has failed, return the error code.
126   if (net_error != OK) {
127     LOG(ERROR) << "request failed, error: " << ErrorToString(net_error);
128     result_code_ = net_error;
129   } else if (request_->GetResponseCode() != 200) {
130     LOG(ERROR) << "Spawner server returned bad status: "
131                << request_->response_headers()->GetStatusLine() << ", "
132                << data_received_;
133     result_code_ = ERR_FAILED;
134   }
135 
136   if (result_code_ != OK)
137     data_received_.clear();
138 
139   request_.reset();
140   context_.reset();
141 
142   event_.Signal();
143 }
144 
ReadResponse()145 void RemoteTestServerSpawnerRequest::Core::ReadResponse() {
146   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
147 
148   while (true) {
149     int result = request_->Read(read_buffer_.get(), kBufferSize);
150     if (result == ERR_IO_PENDING)
151       return;
152 
153     if (result <= 0) {
154       OnCommandCompleted(result);
155       return;
156     }
157 
158     data_received_.append(read_buffer_->data(), result);
159   }
160 }
161 
OnResponseStarted(URLRequest * request,int net_error)162 void RemoteTestServerSpawnerRequest::Core::OnResponseStarted(
163     URLRequest* request,
164     int net_error) {
165   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
166   DCHECK_NE(ERR_IO_PENDING, net_error);
167   DCHECK_EQ(request, request_.get());
168 
169   if (net_error != OK) {
170     OnCommandCompleted(net_error);
171     return;
172   }
173 
174   ReadResponse();
175 }
176 
OnReadCompleted(URLRequest * request,int read_result)177 void RemoteTestServerSpawnerRequest::Core::OnReadCompleted(URLRequest* request,
178                                                            int read_result) {
179   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
180   DCHECK_NE(ERR_IO_PENDING, read_result);
181   DCHECK_EQ(request, request_.get());
182 
183   if (read_result <= 0) {
184     OnCommandCompleted(read_result);
185     return;
186   }
187 
188   data_received_.append(read_buffer_->data(), read_result);
189 
190   ReadResponse();
191 }
192 
RemoteTestServerSpawnerRequest(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,const GURL & url,const std::string & post_data)193 RemoteTestServerSpawnerRequest::RemoteTestServerSpawnerRequest(
194     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
195     const GURL& url,
196     const std::string& post_data)
197     : io_task_runner_(io_task_runner),
198       core_(std::make_unique<Core>()),
199       allowed_port_(
200           std::make_unique<ScopedPortException>(url.EffectiveIntPort())) {
201   io_task_runner_->PostTask(
202       FROM_HERE, base::BindOnce(&Core::SendRequest,
203                                 base::Unretained(core_.get()), url, post_data));
204 }
205 
~RemoteTestServerSpawnerRequest()206 RemoteTestServerSpawnerRequest::~RemoteTestServerSpawnerRequest() {
207   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
208   io_task_runner_->DeleteSoon(FROM_HERE, core_.release());
209 }
210 
WaitForCompletion(std::string * response)211 bool RemoteTestServerSpawnerRequest::WaitForCompletion(std::string* response) {
212   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
213   return core_->WaitForCompletion(response);
214 }
215 
216 }  // namespace net
217