• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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