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