// 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/bind.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 controller, scoped_refptr controller_task_runner, const HttpRequest& http_request) : controller_(controller), controller_task_runner_(controller_task_runner), http_request_(std::make_unique(http_request)) {} ~Interceptor() override {} private: void SendResponse(const SendBytesCallback& send, SendCompleteCallback done) override { controller_task_runner_->PostTask( FROM_HERE, base::BindOnce(&ControllableHttpResponse::OnRequest, controller_, base::ThreadTaskRunnerHandle::Get(), send, std::move(done), std::move(http_request_))); } base::WeakPtr controller_; scoped_refptr controller_task_runner_; std::unique_ptr http_request_; DISALLOW_COPY_AND_ASSIGN(Interceptor); }; ControllableHttpResponse::ControllableHttpResponse( EmbeddedTestServer* embedded_test_server, const std::string& relative_url, bool relative_url_is_prefix) { 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& cookies) { std::string content_data(base::StringPrintf( "HTTP/1.1 %d %s\nContent-type: %s\n", static_cast(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, std::move(done_)); state_ = State::DONE; } void ControllableHttpResponse::OnRequest( scoped_refptr embedded_test_server_task_runner, const SendBytesCallback& send, SendCompleteCallback done, std::unique_ptr 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_ = std::move(done); http_request_ = std::move(http_request); loop_.Quit(); } // Helper function used in the ControllableHttpResponse constructor. // static std::unique_ptr ControllableHttpResponse::RequestHandler( base::WeakPtr controller, scoped_refptr 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( controller, controller_task_runner, request); } return nullptr; } } // namespace test_server } // namespace net