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