// Copyright 2021 The Chromium Authors // 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/http1_connection.h" #include #include #include "base/functional/bind.h" #include "base/functional/callback_forward.h" #include "base/functional/callback_helpers.h" #include "base/strings/stringprintf.h" #include "net/base/completion_once_callback.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "net/socket/stream_socket.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_response.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" namespace net::test_server { Http1Connection::Http1Connection( std::unique_ptr socket, EmbeddedTestServerConnectionListener* connection_listener, EmbeddedTestServer* server_delegate) : socket_(std::move(socket)), connection_listener_(connection_listener), server_delegate_(server_delegate), read_buf_(base::MakeRefCounted(4096)) {} Http1Connection::~Http1Connection() { weak_factory_.InvalidateWeakPtrs(); } void Http1Connection::OnSocketReady() { ReadData(); } std::unique_ptr Http1Connection::TakeSocket() { return std::move(socket_); } StreamSocket* Http1Connection::Socket() { return socket_.get(); } base::WeakPtr Http1Connection::GetWeakPtr() { return weak_factory_.GetWeakPtr(); } void Http1Connection::ReadData() { while (true) { int rv = socket_->Read(read_buf_.get(), read_buf_->size(), base::BindOnce(&Http1Connection::OnReadCompleted, weak_factory_.GetWeakPtr())); if (rv == ERR_IO_PENDING) return; if (HandleReadResult(rv)) { return; } } } void Http1Connection::OnReadCompleted(int rv) { if (!HandleReadResult(rv)) ReadData(); } bool Http1Connection::HandleReadResult(int rv) { if (rv <= 0) { server_delegate_->RemoveConnection(this); return true; } if (connection_listener_) connection_listener_->ReadFromSocket(*socket_, rv); request_parser_.ProcessChunk(std::string_view(read_buf_->data(), rv)); if (request_parser_.ParseRequest() != HttpRequestParser::ACCEPTED) return false; std::unique_ptr request = request_parser_.GetRequest(); SSLInfo ssl_info; if (socket_->GetSSLInfo(&ssl_info)) request->ssl_info = ssl_info; server_delegate_->HandleRequest(weak_factory_.GetWeakPtr(), std::move(request), socket_.get()); return true; } void Http1Connection::AddResponse(std::unique_ptr response) { responses_.push_back(std::move(response)); } void Http1Connection::SendResponseHeaders(HttpStatusCode status, const std::string& status_reason, const base::StringPairs& headers) { std::string response_builder; base::StringAppendF(&response_builder, "HTTP/1.1 %d %s\r\n", status, status_reason.c_str()); for (const auto& header_pair : headers) { const std::string& header_name = header_pair.first; const std::string& header_value = header_pair.second; base::StringAppendF(&response_builder, "%s: %s\r\n", header_name.c_str(), header_value.c_str()); } base::StringAppendF(&response_builder, "\r\n"); SendRawResponseHeaders(response_builder); } void Http1Connection::SendRawResponseHeaders(const std::string& headers) { SendContents(headers, base::DoNothing()); } void Http1Connection::SendContents(const std::string& contents, base::OnceClosure callback) { if (contents.empty()) { std::move(callback).Run(); return; } scoped_refptr buf = base::MakeRefCounted( base::MakeRefCounted(contents), contents.length()); SendInternal(std::move(callback), buf); } void Http1Connection::FinishResponse() { server_delegate_->RemoveConnection(this, connection_listener_); } void Http1Connection::SendContentsAndFinish(const std::string& contents) { SendContents(contents, base::BindOnce(&HttpResponseDelegate::FinishResponse, weak_factory_.GetWeakPtr())); } void Http1Connection::SendHeadersContentAndFinish( HttpStatusCode status, const std::string& status_reason, const base::StringPairs& headers, const std::string& contents) { SendResponseHeaders(status, status_reason, headers); SendContentsAndFinish(contents); } void Http1Connection::SendInternal(base::OnceClosure callback, scoped_refptr buf) { while (buf->BytesRemaining() > 0) { auto split_callback = base::SplitOnceCallback(std::move(callback)); callback = std::move(split_callback.first); int rv = socket_->Write(buf.get(), buf->BytesRemaining(), base::BindOnce(&Http1Connection::OnSendInternalDone, base::Unretained(this), std::move(split_callback.second), buf), TRAFFIC_ANNOTATION_FOR_TESTS); if (rv == ERR_IO_PENDING) return; if (rv < 0) break; buf->DidConsume(rv); } // The Http1Connection will be deleted by the callback since we only need // to serve a single request. std::move(callback).Run(); } void Http1Connection::OnSendInternalDone(base::OnceClosure callback, scoped_refptr buf, int rv) { if (rv < 0) { std::move(callback).Run(); return; } buf->DidConsume(rv); SendInternal(std::move(callback), buf); } } // namespace net::test_server