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