1 // Copyright 2021 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/http1_connection.h"
6
7 #include <utility>
8
9 #include "base/functional/bind.h"
10 #include "base/functional/callback_forward.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/strings/stringprintf.h"
13 #include "net/base/completion_once_callback.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/test_completion_callback.h"
16 #include "net/socket/stream_socket.h"
17 #include "net/test/embedded_test_server/embedded_test_server.h"
18 #include "net/test/embedded_test_server/http_response.h"
19 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
20
21 namespace net::test_server {
22
Http1Connection(std::unique_ptr<StreamSocket> socket,EmbeddedTestServerConnectionListener * connection_listener,EmbeddedTestServer * server_delegate)23 Http1Connection::Http1Connection(
24 std::unique_ptr<StreamSocket> socket,
25 EmbeddedTestServerConnectionListener* connection_listener,
26 EmbeddedTestServer* server_delegate)
27 : socket_(std::move(socket)),
28 connection_listener_(connection_listener),
29 server_delegate_(server_delegate),
30 read_buf_(base::MakeRefCounted<IOBufferWithSize>(4096)) {}
31
~Http1Connection()32 Http1Connection::~Http1Connection() {
33 weak_factory_.InvalidateWeakPtrs();
34 }
35
OnSocketReady()36 void Http1Connection::OnSocketReady() {
37 ReadData();
38 }
39
TakeSocket()40 std::unique_ptr<StreamSocket> Http1Connection::TakeSocket() {
41 return std::move(socket_);
42 }
43
Socket()44 StreamSocket* Http1Connection::Socket() {
45 return socket_.get();
46 }
47
GetWeakPtr()48 base::WeakPtr<HttpConnection> Http1Connection::GetWeakPtr() {
49 return weak_factory_.GetWeakPtr();
50 }
51
ReadData()52 void Http1Connection::ReadData() {
53 while (true) {
54 int rv = socket_->Read(read_buf_.get(), read_buf_->size(),
55 base::BindOnce(&Http1Connection::OnReadCompleted,
56 weak_factory_.GetWeakPtr()));
57 if (rv == ERR_IO_PENDING)
58 return;
59
60 if (HandleReadResult(rv)) {
61 return;
62 }
63 }
64 }
65
OnReadCompleted(int rv)66 void Http1Connection::OnReadCompleted(int rv) {
67 if (!HandleReadResult(rv))
68 ReadData();
69 }
70
HandleReadResult(int rv)71 bool Http1Connection::HandleReadResult(int rv) {
72 if (rv <= 0) {
73 server_delegate_->RemoveConnection(this);
74 return true;
75 }
76
77 if (connection_listener_)
78 connection_listener_->ReadFromSocket(*socket_, rv);
79
80 request_parser_.ProcessChunk(base::StringPiece(read_buf_->data(), rv));
81 if (request_parser_.ParseRequest() != HttpRequestParser::ACCEPTED)
82 return false;
83
84 std::unique_ptr<HttpRequest> request = request_parser_.GetRequest();
85
86 SSLInfo ssl_info;
87 if (socket_->GetSSLInfo(&ssl_info))
88 request->ssl_info = ssl_info;
89
90 server_delegate_->HandleRequest(weak_factory_.GetWeakPtr(),
91 std::move(request));
92 return true;
93 }
94
AddResponse(std::unique_ptr<HttpResponse> response)95 void Http1Connection::AddResponse(std::unique_ptr<HttpResponse> response) {
96 responses_.push_back(std::move(response));
97 }
98
SendResponseHeaders(HttpStatusCode status,const std::string & status_reason,const base::StringPairs & headers)99 void Http1Connection::SendResponseHeaders(HttpStatusCode status,
100 const std::string& status_reason,
101 const base::StringPairs& headers) {
102 std::string response_builder;
103
104 base::StringAppendF(&response_builder, "HTTP/1.1 %d %s\r\n", status,
105 status_reason.c_str());
106 for (const auto& header_pair : headers) {
107 const std::string& header_name = header_pair.first;
108 const std::string& header_value = header_pair.second;
109 base::StringAppendF(&response_builder, "%s: %s\r\n", header_name.c_str(),
110 header_value.c_str());
111 }
112
113 base::StringAppendF(&response_builder, "\r\n");
114 SendRawResponseHeaders(response_builder);
115 }
116
SendRawResponseHeaders(const std::string & headers)117 void Http1Connection::SendRawResponseHeaders(const std::string& headers) {
118 SendContents(headers, base::DoNothing());
119 }
120
SendContents(const std::string & contents,base::OnceClosure callback)121 void Http1Connection::SendContents(const std::string& contents,
122 base::OnceClosure callback) {
123 if (contents.empty()) {
124 std::move(callback).Run();
125 return;
126 }
127
128 scoped_refptr<DrainableIOBuffer> buf =
129 base::MakeRefCounted<DrainableIOBuffer>(
130 base::MakeRefCounted<StringIOBuffer>(contents), contents.length());
131
132 SendInternal(std::move(callback), buf);
133 }
134
FinishResponse()135 void Http1Connection::FinishResponse() {
136 server_delegate_->RemoveConnection(this, connection_listener_);
137 }
138
SendContentsAndFinish(const std::string & contents)139 void Http1Connection::SendContentsAndFinish(const std::string& contents) {
140 SendContents(contents, base::BindOnce(&HttpResponseDelegate::FinishResponse,
141 weak_factory_.GetWeakPtr()));
142 }
143
SendHeadersContentAndFinish(HttpStatusCode status,const std::string & status_reason,const base::StringPairs & headers,const std::string & contents)144 void Http1Connection::SendHeadersContentAndFinish(
145 HttpStatusCode status,
146 const std::string& status_reason,
147 const base::StringPairs& headers,
148 const std::string& contents) {
149 SendResponseHeaders(status, status_reason, headers);
150 SendContentsAndFinish(contents);
151 }
152
SendInternal(base::OnceClosure callback,scoped_refptr<DrainableIOBuffer> buf)153 void Http1Connection::SendInternal(base::OnceClosure callback,
154 scoped_refptr<DrainableIOBuffer> buf) {
155 while (buf->BytesRemaining() > 0) {
156 auto split_callback = base::SplitOnceCallback(std::move(callback));
157 callback = std::move(split_callback.first);
158 int rv =
159 socket_->Write(buf.get(), buf->BytesRemaining(),
160 base::BindOnce(&Http1Connection::OnSendInternalDone,
161 base::Unretained(this),
162 std::move(split_callback.second), buf),
163 TRAFFIC_ANNOTATION_FOR_TESTS);
164 if (rv == ERR_IO_PENDING)
165 return;
166
167 if (rv < 0)
168 break;
169 buf->DidConsume(rv);
170 }
171
172 // The Http1Connection will be deleted by the callback since we only need
173 // to serve a single request.
174 std::move(callback).Run();
175 }
176
OnSendInternalDone(base::OnceClosure callback,scoped_refptr<DrainableIOBuffer> buf,int rv)177 void Http1Connection::OnSendInternalDone(base::OnceClosure callback,
178 scoped_refptr<DrainableIOBuffer> buf,
179 int rv) {
180 if (rv < 0) {
181 std::move(callback).Run();
182 return;
183 }
184 buf->DidConsume(rv);
185 SendInternal(std::move(callback), buf);
186 }
187
188 } // namespace net::test_server
189