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/embedded_test_server/controllable_http_response.h"
6
7 #include "base/check_op.h"
8 #include "base/functional/bind.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/task/single_thread_task_runner.h"
11 #include "net/base/tracing.h"
12 #include "net/test/embedded_test_server/http_response.h"
13
14 namespace net::test_server {
15
16 class ControllableHttpResponse::Interceptor : public HttpResponse {
17 public:
Interceptor(base::WeakPtr<ControllableHttpResponse> controller,scoped_refptr<base::SingleThreadTaskRunner> controller_task_runner,const HttpRequest & http_request)18 explicit Interceptor(
19 base::WeakPtr<ControllableHttpResponse> controller,
20 scoped_refptr<base::SingleThreadTaskRunner> controller_task_runner,
21 const HttpRequest& http_request)
22 : controller_(controller),
23 controller_task_runner_(controller_task_runner),
24 http_request_(std::make_unique<HttpRequest>(http_request)) {}
25
26 Interceptor(const Interceptor&) = delete;
27 Interceptor& operator=(const Interceptor&) = delete;
28
29 ~Interceptor() override = default;
30
31 private:
SendResponse(base::WeakPtr<HttpResponseDelegate> delegate)32 void SendResponse(base::WeakPtr<HttpResponseDelegate> delegate) override {
33 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
34 base::SingleThreadTaskRunner::GetCurrentDefault();
35 CHECK(task_runner);
36 controller_task_runner_->PostTask(
37 FROM_HERE, base::BindOnce(&ControllableHttpResponse::OnRequest,
38 controller_, std::move(task_runner), delegate,
39 std::move(http_request_)));
40 }
41
42 base::WeakPtr<ControllableHttpResponse> controller_;
43 scoped_refptr<base::SingleThreadTaskRunner> controller_task_runner_;
44
45 std::unique_ptr<HttpRequest> http_request_;
46 };
47
ControllableHttpResponse(EmbeddedTestServer * embedded_test_server,const std::string & relative_url,bool relative_url_is_prefix)48 ControllableHttpResponse::ControllableHttpResponse(
49 EmbeddedTestServer* embedded_test_server,
50 const std::string& relative_url,
51 bool relative_url_is_prefix) {
52 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
53 embedded_test_server->RegisterRequestHandler(base::BindRepeating(
54 RequestHandler, weak_ptr_factory_.GetWeakPtr(),
55 base::SingleThreadTaskRunner::GetCurrentDefault(),
56 base::Owned(new bool(true)), relative_url, relative_url_is_prefix));
57 }
58
59 ControllableHttpResponse::~ControllableHttpResponse() = default;
60
WaitForRequest()61 void ControllableHttpResponse::WaitForRequest() {
62 TRACE_EVENT("test", "ControllableHttpResponse::WaitForRequest");
63 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
64 CHECK_EQ(State::WAITING_FOR_REQUEST, state_)
65 << "WaitForRequest() called twice.";
66 loop_.Run();
67 CHECK(embedded_test_server_task_runner_);
68 state_ = State::READY_TO_SEND_DATA;
69 }
70
Send(net::HttpStatusCode http_status,const std::string & content_type,const std::string & content,const std::vector<std::string> & cookies,const std::vector<std::string> & extra_headers)71 void ControllableHttpResponse::Send(
72 net::HttpStatusCode http_status,
73 const std::string& content_type,
74 const std::string& content,
75 const std::vector<std::string>& cookies,
76 const std::vector<std::string>& extra_headers) {
77 TRACE_EVENT("test", "ControllableHttpResponse::Send", "http_status",
78 http_status, "content_type", content_type, "content", content,
79 "cookies", cookies);
80 std::string content_data(base::StringPrintf(
81 "HTTP/1.1 %d %s\nContent-type: %s\n", static_cast<int>(http_status),
82 net::GetHttpReasonPhrase(http_status), content_type.c_str()));
83 for (auto& cookie : cookies)
84 content_data += "Set-Cookie: " + cookie + "\n";
85 for (auto& header : extra_headers)
86 content_data += header + "\n";
87 content_data += "\n";
88 content_data += content;
89 Send(content_data);
90 }
91
Send(const std::string & bytes)92 void ControllableHttpResponse::Send(const std::string& bytes) {
93 TRACE_EVENT("test", "ControllableHttpResponse::Send", "bytes", bytes);
94 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
95 CHECK_EQ(State::READY_TO_SEND_DATA, state_) << "Send() called without any "
96 "opened connection. Did you "
97 "call WaitForRequest()?";
98 base::RunLoop loop;
99 embedded_test_server_task_runner_->PostTask(
100 FROM_HERE, base::BindOnce(&HttpResponseDelegate::SendContents, delegate_,
101 bytes, loop.QuitClosure()));
102 loop.Run();
103 }
104
Done()105 void ControllableHttpResponse::Done() {
106 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
107 CHECK_EQ(State::READY_TO_SEND_DATA, state_) << "Done() called without any "
108 "opened connection. Did you "
109 "call WaitForRequest()?";
110 embedded_test_server_task_runner_->PostTask(
111 FROM_HERE,
112 base::BindOnce(&HttpResponseDelegate::FinishResponse, delegate_));
113 state_ = State::DONE;
114 }
115
has_received_request()116 bool ControllableHttpResponse::has_received_request() {
117 return loop_.AnyQuitCalled();
118 }
119
OnRequest(scoped_refptr<base::SingleThreadTaskRunner> embedded_test_server_task_runner,base::WeakPtr<HttpResponseDelegate> delegate,std::unique_ptr<HttpRequest> http_request)120 void ControllableHttpResponse::OnRequest(
121 scoped_refptr<base::SingleThreadTaskRunner>
122 embedded_test_server_task_runner,
123 base::WeakPtr<HttpResponseDelegate> delegate,
124 std::unique_ptr<HttpRequest> http_request) {
125 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
126 CHECK(embedded_test_server_task_runner);
127 CHECK(!embedded_test_server_task_runner_)
128 << "A ControllableHttpResponse can only handle one request at a time";
129 embedded_test_server_task_runner_ = embedded_test_server_task_runner;
130 delegate_ = delegate;
131 http_request_ = std::move(http_request);
132 loop_.Quit();
133 }
134
135 // Helper function used in the ControllableHttpResponse constructor.
136 // static
RequestHandler(base::WeakPtr<ControllableHttpResponse> controller,scoped_refptr<base::SingleThreadTaskRunner> controller_task_runner,bool * available,const std::string & relative_url,bool relative_url_is_prefix,const HttpRequest & request)137 std::unique_ptr<HttpResponse> ControllableHttpResponse::RequestHandler(
138 base::WeakPtr<ControllableHttpResponse> controller,
139 scoped_refptr<base::SingleThreadTaskRunner> controller_task_runner,
140 bool* available,
141 const std::string& relative_url,
142 bool relative_url_is_prefix,
143 const HttpRequest& request) {
144 if (!*available)
145 return nullptr;
146
147 if (request.relative_url == relative_url ||
148 (relative_url_is_prefix &&
149 request.relative_url.starts_with(relative_url))) {
150 *available = false;
151 return std::make_unique<ControllableHttpResponse::Interceptor>(
152 controller, controller_task_runner, request);
153 }
154
155 return nullptr;
156 }
157
158 } // namespace net::test_server
159