| // Copyright 2017 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "net/test/embedded_test_server/controllable_http_response.h" | |
| #include "base/logging.h" | |
| #include "base/strings/stringprintf.h" | |
| #include "base/threading/thread_task_runner_handle.h" | |
| namespace net { | |
| namespace test_server { | |
| class ControllableHttpResponse::Interceptor : public HttpResponse { | |
| public: | |
| explicit Interceptor( | |
| base::WeakPtr<ControllableHttpResponse> controller, | |
| scoped_refptr<base::SingleThreadTaskRunner> controller_task_runner, | |
| const HttpRequest& http_request) | |
| : controller_(controller), | |
| controller_task_runner_(controller_task_runner), | |
| http_request_(std::make_unique<HttpRequest>(http_request)) {} | |
| ~Interceptor() override {} | |
| private: | |
| void SendResponse(const SendBytesCallback& send, | |
| const SendCompleteCallback& done) override { | |
| controller_task_runner_->PostTask( | |
| FROM_HERE, | |
| base::BindOnce(&ControllableHttpResponse::OnRequest, controller_, | |
| base::ThreadTaskRunnerHandle::Get(), send, done, | |
| std::move(http_request_))); | |
| } | |
| base::WeakPtr<ControllableHttpResponse> controller_; | |
| scoped_refptr<base::SingleThreadTaskRunner> controller_task_runner_; | |
| std::unique_ptr<HttpRequest> http_request_; | |
| DISALLOW_COPY_AND_ASSIGN(Interceptor); | |
| }; | |
| ControllableHttpResponse::ControllableHttpResponse( | |
| EmbeddedTestServer* embedded_test_server, | |
| const std::string& relative_url, | |
| bool relative_url_is_prefix) | |
| : weak_ptr_factory_(this) { | |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| embedded_test_server->RegisterRequestHandler(base::BindRepeating( | |
| RequestHandler, weak_ptr_factory_.GetWeakPtr(), | |
| base::ThreadTaskRunnerHandle::Get(), base::Owned(new bool(true)), | |
| relative_url, relative_url_is_prefix)); | |
| } | |
| ControllableHttpResponse::~ControllableHttpResponse() {} | |
| void ControllableHttpResponse::WaitForRequest() { | |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| DCHECK_EQ(State::WAITING_FOR_REQUEST, state_) | |
| << "WaitForRequest() called twice."; | |
| loop_.Run(); | |
| DCHECK(embedded_test_server_task_runner_); | |
| DCHECK(send_); | |
| DCHECK(done_); | |
| state_ = State::READY_TO_SEND_DATA; | |
| } | |
| void ControllableHttpResponse::Send(net::HttpStatusCode http_status, | |
| const std::string& content_type, | |
| const std::string& content, | |
| const std::vector<std::string>& cookies) { | |
| std::string content_data(base::StringPrintf( | |
| "HTTP/1.1 %d %s\nContent-type: %s\n", static_cast<int>(http_status), | |
| net::GetHttpReasonPhrase(http_status), content_type.c_str())); | |
| for (auto& cookie : cookies) | |
| content_data += "Set-Cookie: " + cookie + "\n"; | |
| content_data += "\n"; | |
| content_data += content; | |
| Send(content_data); | |
| } | |
| void ControllableHttpResponse::Send(const std::string& bytes) { | |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| DCHECK_EQ(State::READY_TO_SEND_DATA, state_) << "Send() called without any " | |
| "opened connection. Did you " | |
| "call WaitForRequest()?"; | |
| base::RunLoop loop; | |
| embedded_test_server_task_runner_->PostTask( | |
| FROM_HERE, base::BindOnce(send_, bytes, loop.QuitClosure())); | |
| loop.Run(); | |
| } | |
| void ControllableHttpResponse::Done() { | |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| DCHECK_EQ(State::READY_TO_SEND_DATA, state_) << "Done() called without any " | |
| "opened connection. Did you " | |
| "call WaitForRequest()?"; | |
| embedded_test_server_task_runner_->PostTask(FROM_HERE, done_); | |
| state_ = State::DONE; | |
| } | |
| void ControllableHttpResponse::OnRequest( | |
| scoped_refptr<base::SingleThreadTaskRunner> | |
| embedded_test_server_task_runner, | |
| const SendBytesCallback& send, | |
| const SendCompleteCallback& done, | |
| std::unique_ptr<HttpRequest> http_request) { | |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| DCHECK(!embedded_test_server_task_runner_) | |
| << "A ControllableHttpResponse can only handle one request at a time"; | |
| embedded_test_server_task_runner_ = embedded_test_server_task_runner; | |
| send_ = send; | |
| done_ = done; | |
| http_request_ = std::move(http_request); | |
| loop_.Quit(); | |
| } | |
| // Helper function used in the ControllableHttpResponse constructor. | |
| // static | |
| std::unique_ptr<HttpResponse> ControllableHttpResponse::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) { | |
| if (!*available) | |
| return nullptr; | |
| if (request.relative_url == relative_url || | |
| (relative_url_is_prefix && | |
| base::StartsWith(request.relative_url, relative_url, | |
| base::CompareCase::SENSITIVE))) { | |
| *available = false; | |
| return std::make_unique<ControllableHttpResponse::Interceptor>( | |
| controller, controller_task_runner, request); | |
| } | |
| return nullptr; | |
| } | |
| } // namespace test_server | |
| } // namespace net |