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