]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdistdist/test-dnsdistnghttp2_cc.cc
Merge pull request #11431 from jroessler-ox/docs-kskzskroll-update
[thirdparty/pdns.git] / pdns / dnsdistdist / test-dnsdistnghttp2_cc.cc
CommitLineData
f05cd66c
RG
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
1c2d079d 22#ifndef BOOST_TEST_DYN_LINK
f05cd66c 23#define BOOST_TEST_DYN_LINK
1c2d079d
FM
24#endif
25
f05cd66c
RG
26#define BOOST_TEST_NO_MAIN
27
28#include <boost/test/unit_test.hpp>
29
30#include "dnswriter.hh"
31#include "dnsdist.hh"
32#include "dnsdist-proxy-protocol.hh"
33#include "dnsdist-rings.hh"
34#include "dnsdist-nghttp2.hh"
690a9c40 35#include "sstuff.hh"
f05cd66c 36
cf25b82b 37#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
f05cd66c
RG
38#include <nghttp2/nghttp2.h>
39
40BOOST_AUTO_TEST_SUITE(test_dnsdistnghttp2_cc)
41
42struct ExpectedStep
43{
44public:
1226f653
RG
45 enum class ExpectedRequest
46 {
47 handshakeClient,
48 readFromClient,
49 writeToClient,
50 closeClient,
51 connectToBackend,
52 readFromBackend,
53 writeToBackend,
54 closeBackend
55 };
f05cd66c 56
4e82c08c 57 ExpectedStep(ExpectedRequest r, IOState n, size_t b = 0, std::function<void(int descriptor)> fn = nullptr) :
1226f653 58 cb(fn), request(r), nextState(n), bytes(b)
f05cd66c
RG
59 {
60 }
61
4e82c08c 62 std::function<void(int descriptor)> cb{nullptr};
f05cd66c
RG
63 ExpectedRequest request;
64 IOState nextState;
65 size_t bytes{0};
66};
67
68struct ExpectedData
69{
70 PacketBuffer d_query;
71 PacketBuffer d_response;
72};
73
1226f653 74static std::deque<ExpectedStep> s_steps;
f05cd66c 75static std::map<uint16_t, ExpectedData> s_responses;
8298e5d4 76static std::unique_ptr<FDMultiplexer> s_mplexer;
f05cd66c 77
1226f653 78std::ostream& operator<<(std::ostream& os, const ExpectedStep::ExpectedRequest d);
f05cd66c 79
1226f653 80std::ostream& operator<<(std::ostream& os, const ExpectedStep::ExpectedRequest d)
f05cd66c 81{
1226f653
RG
82 static const std::vector<std::string> requests = {"handshake with client", "read from client", "write to client", "close connection to client", "connect to the backend", "read from the backend", "write to the backend", "close connection to backend"};
83 os << requests.at(static_cast<size_t>(d));
f05cd66c
RG
84 return os;
85}
86
becad613 87class DOHConnection
f05cd66c 88{
becad613 89public:
0e6892c6
RG
90 DOHConnection(bool needProxyProtocol) :
91 d_session(std::unique_ptr<nghttp2_session, void (*)(nghttp2_session*)>(nullptr, nghttp2_session_del)), d_needProxyProtocol(needProxyProtocol)
f05cd66c
RG
92 {
93 nghttp2_session_callbacks* cbs = nullptr;
94 nghttp2_session_callbacks_new(&cbs);
95 std::unique_ptr<nghttp2_session_callbacks, void (*)(nghttp2_session_callbacks*)> callbacks(cbs, nghttp2_session_callbacks_del);
96 cbs = nullptr;
97 nghttp2_session_callbacks_set_send_callback(callbacks.get(), send_callback);
98 nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks.get(), on_frame_recv_callback);
99 nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks.get(), on_data_chunk_recv_callback);
100 nghttp2_session_callbacks_set_on_stream_close_callback(callbacks.get(), on_stream_close_callback);
101 nghttp2_session* sess = nullptr;
102 nghttp2_session_server_new(&sess, callbacks.get(), this);
103 d_session = std::unique_ptr<nghttp2_session, void (*)(nghttp2_session*)>(sess, nghttp2_session_del);
104
105 nghttp2_settings_entry iv[1] = {
106 {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
1226f653 107 nghttp2_submit_settings(d_session.get(), NGHTTP2_FLAG_NONE, iv, sizeof(iv) / sizeof(*iv));
f05cd66c
RG
108 }
109
110 PacketBuffer d_serverOutBuffer;
0e6892c6 111 PacketBuffer d_proxyProtocolBuffer;
1226f653
RG
112 std::map<uint32_t, PacketBuffer> d_queries;
113 std::map<uint32_t, PacketBuffer> d_responses;
114 std::unique_ptr<nghttp2_session, void (*)(nghttp2_session*)> d_session;
f05cd66c
RG
115 /* used to replace the stream ID in outgoing frames. Ugly but the library does not let us
116 test weird cases without that */
1226f653 117 std::map<uint32_t, uint32_t> d_idMapping;
0e6892c6 118 bool d_needProxyProtocol;
f05cd66c
RG
119
120 size_t submitIncoming(const PacketBuffer& data, size_t pos, size_t toWrite)
121 {
0e6892c6
RG
122 size_t consumed = 0;
123 if (d_needProxyProtocol) {
124 do {
125 auto bytesRemaining = isProxyHeaderComplete(d_proxyProtocolBuffer);
126 if (bytesRemaining < 0) {
127 size_t toConsume = toWrite > static_cast<size_t>(-bytesRemaining) ? static_cast<size_t>(-bytesRemaining) : toWrite;
128 d_proxyProtocolBuffer.insert(d_proxyProtocolBuffer.end(), data.begin() + pos, data.begin() + pos + toConsume);
129 pos += toConsume;
130 toWrite -= toConsume;
131 consumed += toConsume;
132
133 bytesRemaining = isProxyHeaderComplete(d_proxyProtocolBuffer);
134 if (bytesRemaining > 0) {
135 d_needProxyProtocol = false;
136 }
137 else if (bytesRemaining == 0) {
138 throw("Fatal error while parsing proxy protocol payload");
139 }
140 }
141 else if (bytesRemaining == 0) {
142 throw("Fatal error while parsing proxy protocol payload");
143 }
144
145 if (toWrite == 0) {
146 return consumed;
147 }
2a25c80f 148 } while (d_needProxyProtocol && toWrite > 0);
0e6892c6
RG
149 }
150
f05cd66c
RG
151 ssize_t readlen = nghttp2_session_mem_recv(d_session.get(), &data.at(pos), toWrite);
152 if (readlen < 0) {
153 throw("Fatal error while submitting: " + std::string(nghttp2_strerror(static_cast<int>(readlen))));
154 }
155
156 /* just in case, see if we have anything to send */
157 int rv = nghttp2_session_send(d_session.get());
158 if (rv != 0) {
159 throw("Fatal error while sending: " + std::string(nghttp2_strerror(rv)));
160 }
161
162 return readlen;
163 }
164
165 void submitResponse(uint32_t streamId, PacketBuffer& data)
166 {
9f5bb193 167 const nghttp2_nv hdrs[] = {{(uint8_t*)":status", (uint8_t*)"200", sizeof(":status") - 1, sizeof("200") - 1, NGHTTP2_NV_FLAG_NONE}};
f05cd66c
RG
168 nghttp2_data_provider dataProvider;
169 dataProvider.source.ptr = &data;
170 dataProvider.read_callback = [](nghttp2_session* session, int32_t stream_id, uint8_t* buf, size_t length, uint32_t* data_flags, nghttp2_data_source* source, void* user_data) -> ssize_t {
171 auto buffer = reinterpret_cast<PacketBuffer*>(source->ptr);
172 size_t toCopy = 0;
173 if (buffer->size() > 0) {
174 toCopy = length > buffer->size() ? buffer->size() : length;
175 memcpy(buf, &buffer->at(0), toCopy);
176 buffer->erase(buffer->begin(), buffer->begin() + toCopy);
177 }
178
179 if (buffer->size() == 0) {
180 *data_flags |= NGHTTP2_DATA_FLAG_EOF;
181 }
182 // cerr<<"submitting response data of size "<<toCopy<<" for stream "<<stream_id<<endl;
183 return toCopy;
184 };
185
1226f653 186 int rv = nghttp2_submit_response(d_session.get(), streamId, hdrs, sizeof(hdrs) / sizeof(*hdrs), &dataProvider);
f05cd66c
RG
187 // cerr<<"Submitting response for stream ID "<<streamId<<": "<<rv<<endl;
188 BOOST_CHECK_EQUAL(rv, 0);
becad613
RG
189 /* just in case, see if we have anything to send */
190 rv = nghttp2_session_send(d_session.get());
191 BOOST_CHECK_EQUAL(rv, 0);
f05cd66c
RG
192 }
193
194 void submitError(uint32_t streamId, uint16_t status, const std::string& msg)
195 {
196 const std::string statusStr = std::to_string(status);
9f5bb193 197 const nghttp2_nv hdrs[] = {{(uint8_t*)":status", (uint8_t*)statusStr.c_str(), sizeof(":status") - 1, statusStr.size(), NGHTTP2_NV_FLAG_NONE}};
f05cd66c 198
1226f653 199 int rv = nghttp2_submit_response(d_session.get(), streamId, hdrs, sizeof(hdrs) / sizeof(*hdrs), nullptr);
f05cd66c 200 BOOST_CHECK_EQUAL(rv, 0);
becad613
RG
201 /* just in case, see if we have anything to send */
202 rv = nghttp2_session_send(d_session.get());
203 BOOST_CHECK_EQUAL(rv, 0);
f05cd66c
RG
204 }
205
206 void submitGoAway()
207 {
208 int rv = nghttp2_submit_goaway(d_session.get(), NGHTTP2_FLAG_NONE, 0, NGHTTP2_INTERNAL_ERROR, nullptr, 0);
209 BOOST_CHECK_EQUAL(rv, 0);
becad613
RG
210 /* just in case, see if we have anything to send */
211 rv = nghttp2_session_send(d_session.get());
212 BOOST_CHECK_EQUAL(rv, 0);
f05cd66c
RG
213 }
214
215private:
216 static ssize_t send_callback(nghttp2_session* session, const uint8_t* data, size_t length, int flags, void* user_data)
217 {
218 DOHConnection* conn = reinterpret_cast<DOHConnection*>(user_data);
219 // cerr<<"inserting "<<length<<" bytes into the server output buffer of size "<<conn->d_serverOutBuffer.size()<<endl;
220 if (!conn->d_idMapping.empty() && length > 9) {
221 /* frame type == DATA */
222 if (data[3] == NGHTTP2_DATA) {
223 uint32_t streamId = 0;
224 memcpy(&streamId, &data[5], sizeof(streamId));
225 const auto it = conn->d_idMapping.find(ntohl(streamId));
226 if (it != conn->d_idMapping.end()) {
227 streamId = htonl(it->second);
228 std::vector<uint8_t> editedData(length);
229 std::copy(data, data + length, editedData.begin());
230 memcpy(&editedData.at(5), &streamId, sizeof(streamId));
231 conn->d_serverOutBuffer.insert(conn->d_serverOutBuffer.end(), editedData.data(), editedData.data() + length);
232 return static_cast<ssize_t>(editedData.size());
233 }
234 }
235 }
236
237 conn->d_serverOutBuffer.insert(conn->d_serverOutBuffer.end(), data, data + length);
238 return static_cast<ssize_t>(length);
239 }
240
241 static int on_frame_recv_callback(nghttp2_session* session, const nghttp2_frame* frame, void* user_data)
242 {
243 DOHConnection* conn = reinterpret_cast<DOHConnection*>(user_data);
244 // cerr<<"Frame type is "<<std::to_string(frame->hd.type)<<endl;
245 if ((frame->hd.type == NGHTTP2_HEADERS || frame->hd.type == NGHTTP2_DATA) && frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
246#if 0
247 auto stream_data = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
248 /* For DATA and HEADERS frame, this callback may be called after on_stream_close_callback. Check that stream still alive. */
249 if (stream_data == nullptr) {
250 cerr<<"unable to find stream data!"<<endl;
251 return 0;
252 }
253#endif
254
255 auto& query = conn->d_queries.at(frame->hd.stream_id);
256 BOOST_REQUIRE_GT(query.size(), sizeof(dnsheader));
90686725 257 const dnsheader_aligned dh(query.data());
f05cd66c
RG
258 uint16_t id = ntohs(dh->id);
259 // cerr<<"got query ID "<<id<<endl;
260
261 const auto& expected = s_responses.at(id);
262 BOOST_REQUIRE_EQUAL(expected.d_query.size(), query.size());
263 for (size_t idx = 0; idx < query.size(); idx++) {
264 if (expected.d_query.at(idx) != query.at(idx)) {
1226f653 265 cerr << "Mismatch at offset " << idx << ", expected " << std::to_string(query.at(idx)) << " got " << std::to_string(expected.d_query.at(idx)) << endl;
f05cd66c
RG
266 BOOST_CHECK(false);
267 }
268 }
269
270 DNSName qname(reinterpret_cast<const char*>(query.data()), query.size(), sizeof(dnsheader), false);
271 if (qname == DNSName("goaway.powerdns.com.")) {
272 conn->submitGoAway();
273 }
274 else if (qname == DNSName("500.powerdns.com.") && (id % 2) == 0) {
275 /* we return a 500 on the first query only */
276 conn->submitError(frame->hd.stream_id, 500, "Server failure");
277 }
278 else if (qname == DNSName("wrong-stream-id.powerdns.com.") && (id % 2) == 0) {
279 /* we return a wrong stremad ID on the first query only */
4caba288 280 BOOST_CHECK_EQUAL(frame->hd.stream_id, 1);
f05cd66c
RG
281 conn->d_responses[frame->hd.stream_id] = expected.d_response;
282 /* use an invalid stream ID! */
283 conn->d_idMapping[frame->hd.stream_id] = frame->hd.stream_id + 4;
284 conn->submitResponse(frame->hd.stream_id, conn->d_responses.at(frame->hd.stream_id));
285 }
286 else {
287 conn->d_responses[frame->hd.stream_id] = expected.d_response;
288 conn->submitResponse(frame->hd.stream_id, conn->d_responses.at(frame->hd.stream_id));
289 }
290 conn->d_queries.erase(frame->hd.stream_id);
291 }
292
293 return 0;
294 }
295
296 static int on_data_chunk_recv_callback(nghttp2_session* session, uint8_t flags, int32_t stream_id, const uint8_t* data, size_t len, void* user_data)
297 {
298 DOHConnection* conn = reinterpret_cast<DOHConnection*>(user_data);
f05cd66c
RG
299 auto& query = conn->d_queries[stream_id];
300 query.insert(query.end(), data, data + len);
f05cd66c
RG
301 return 0;
302 }
303
304 static int on_stream_close_callback(nghttp2_session* session, int32_t stream_id, uint32_t error_code, void* user_data)
305 {
f05cd66c
RG
306 if (error_code == 0) {
307 return 0;
308 }
309
310 return 0;
311 }
f05cd66c
RG
312};
313
314static std::map<int, std::unique_ptr<DOHConnection>> s_connectionBuffers;
315
316class MockupTLSConnection : public TLSConnection
317{
318public:
0e6892c6 319 MockupTLSConnection(int descriptor, bool client = false, bool needProxyProtocol = false) :
1226f653 320 d_descriptor(descriptor), d_client(client)
f05cd66c 321 {
0e6892c6 322 s_connectionBuffers[d_descriptor] = std::make_unique<DOHConnection>(needProxyProtocol);
f05cd66c
RG
323 }
324
1226f653 325 ~MockupTLSConnection() {}
f05cd66c
RG
326
327 IOState tryHandshake() override
328 {
329 auto step = getStep();
330 BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::handshakeClient);
331
332 return step.nextState;
333 }
334
335 IOState tryWrite(const PacketBuffer& buffer, size_t& pos, size_t toWrite) override
336 {
337 auto& conn = s_connectionBuffers.at(d_descriptor);
338 auto step = getStep();
339 BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::writeToClient : ExpectedStep::ExpectedRequest::writeToBackend);
340
341 if (step.bytes == 0) {
342 if (step.nextState == IOState::NeedWrite) {
343 return step.nextState;
344 }
345 throw std::runtime_error("Remote host closed the connection");
346 }
347
348 toWrite -= pos;
349 BOOST_REQUIRE_GE(buffer.size(), pos + toWrite);
350
351 if (step.bytes < toWrite) {
352 toWrite = step.bytes;
353 }
354
355 conn->submitIncoming(buffer, pos, toWrite);
356 pos += toWrite;
357
358 return step.nextState;
359 }
360
1226f653 361 IOState tryRead(PacketBuffer& buffer, size_t& pos, size_t toRead, bool allowIncomplete = false) override
f05cd66c
RG
362 {
363 auto& conn = s_connectionBuffers.at(d_descriptor);
364 auto step = getStep();
365 BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::readFromClient : ExpectedStep::ExpectedRequest::readFromBackend);
366
367 if (step.bytes == 0) {
368 if (step.nextState == IOState::NeedRead) {
369 return step.nextState;
370 }
371 throw std::runtime_error("Remote host closed the connection");
372 }
373
374 auto& externalBuffer = conn->d_serverOutBuffer;
375 toRead -= pos;
376
377 if (step.bytes < toRead) {
378 toRead = step.bytes;
379 }
380 if (allowIncomplete) {
381 if (toRead > externalBuffer.size()) {
382 toRead = externalBuffer.size();
383 }
384 }
385 else {
386 BOOST_REQUIRE_GE(externalBuffer.size(), toRead);
387 }
388
389 BOOST_REQUIRE_GE(buffer.size(), toRead);
390
f05cd66c
RG
391 std::copy(externalBuffer.begin(), externalBuffer.begin() + toRead, buffer.begin() + pos);
392 pos += toRead;
393 externalBuffer.erase(externalBuffer.begin(), externalBuffer.begin() + toRead);
f05cd66c
RG
394
395 return step.nextState;
396 }
397
398 IOState tryConnect(bool fastOpen, const ComboAddress& remote) override
399 {
400 auto step = getStep();
401 BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::connectToBackend);
402
403 return step.nextState;
404 }
405
406 void close() override
407 {
408 auto step = getStep();
409 BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::closeClient : ExpectedStep::ExpectedRequest::closeBackend);
410 }
411
767f5514
RG
412 bool isUsable() const override
413 {
414 return true;
415 }
416
f05cd66c
RG
417 std::string getServerNameIndication() const override
418 {
419 return "";
420 }
421
422 std::vector<uint8_t> getNextProtocol() const override
423 {
424 return std::vector<uint8_t>();
425 }
426
427 LibsslTLSVersion getTLSVersion() const override
428 {
429 return LibsslTLSVersion::TLS13;
430 }
431
432 bool hasSessionBeenResumed() const override
433 {
434 return false;
435 }
436
437 std::vector<std::unique_ptr<TLSSession>> getSessions() override
438 {
439 return {};
440 }
441
442 void setSession(std::unique_ptr<TLSSession>& session) override
443 {
444 }
445
489caa9f
RG
446 std::vector<int> getAsyncFDs() override
447 {
448 return {};
449 }
450
f05cd66c
RG
451 /* unused in that context, don't bother */
452 void doHandshake() override
453 {
454 }
455
456 void connect(bool fastOpen, const ComboAddress& remote, const struct timeval& timeout) override
457 {
458 }
459
1226f653 460 size_t read(void* buffer, size_t bufferSize, const struct timeval& readTimeout, const struct timeval& totalTimeout = {0, 0}, bool allowIncomplete = false) override
f05cd66c
RG
461 {
462 return 0;
463 }
464
465 size_t write(const void* buffer, size_t bufferSize, const struct timeval& writeTimeout) override
466 {
467 return 0;
468 }
1226f653 469
f05cd66c
RG
470private:
471 ExpectedStep getStep() const
472 {
473 BOOST_REQUIRE(!s_steps.empty());
474 auto step = s_steps.front();
475 s_steps.pop_front();
476
477 if (step.cb) {
4e82c08c 478 step.cb(d_descriptor);
f05cd66c
RG
479 }
480
481 return step;
482 }
483
484 const int d_descriptor;
485 bool d_client{false};
486};
487
c02b7e13 488#include "test-dnsdistnghttp2_common.hh"
f05cd66c
RG
489
490class MockupQuerySender : public TCPQuerySender
491{
492public:
493 bool active() const override
494 {
495 return true;
496 }
497
f05cd66c
RG
498 void handleResponse(const struct timeval& now, TCPResponse&& response) override
499 {
500 if (d_customHandler) {
501 d_customHandler(d_id, now, std::move(response));
502 return;
503 }
504
505 BOOST_REQUIRE_GT(response.d_buffer.size(), sizeof(dnsheader));
90686725 506 const dnsheader_aligned dh(response.d_buffer.data());
f05cd66c
RG
507 uint16_t id = ntohs(dh->id);
508
509 BOOST_REQUIRE_EQUAL(id, d_id);
510 const auto& expected = s_responses.at(id);
511 BOOST_REQUIRE_EQUAL(expected.d_response.size(), response.d_buffer.size());
512 for (size_t idx = 0; idx < response.d_buffer.size(); idx++) {
513 if (expected.d_response.at(idx) != response.d_buffer.at(idx)) {
1226f653 514 cerr << "Mismatch at offset " << idx << ", expected " << std::to_string(response.d_buffer.at(idx)) << " got " << std::to_string(expected.d_response.at(idx)) << endl;
f05cd66c
RG
515 BOOST_CHECK(false);
516 }
517 }
518
519 if (expected.d_response != response.d_buffer) {
520 BOOST_REQUIRE(false);
521 }
522 d_valid = true;
523 }
524
af1bc11b 525 void handleXFRResponse([[maybe_unused]] const struct timeval& now, [[maybe_unused]] TCPResponse&& response) override
f05cd66c
RG
526 {
527 }
528
af1bc11b 529 void notifyIOError([[maybe_unused]] const struct timeval& now, [[maybe_unused]] TCPResponse&& response) override
f05cd66c
RG
530 {
531 d_error = true;
532 }
533
534 std::function<void(uint16_t id, const struct timeval& now, TCPResponse&& response)> d_customHandler;
535 uint16_t d_id{0};
536 bool d_valid{false};
537 bool d_error{false};
538};
539
f05cd66c
RG
540struct TestFixture
541{
542 TestFixture()
543 {
544 s_steps.clear();
545 s_responses.clear();
2bbc9eb0 546 s_mplexer = std::make_unique<MockupFDMultiplexer>();
f05cd66c
RG
547 }
548 ~TestFixture()
549 {
550 clearH2Connections();
551 s_steps.clear();
552 s_responses.clear();
553 s_mplexer.reset();
1226f653 554 }
f05cd66c
RG
555};
556
557BOOST_FIXTURE_TEST_CASE(test_SingleQuery, TestFixture)
558{
690a9c40 559 auto local = getBackendAddress("1", 80);
c114cd18 560 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
561 auto tlsCtx = std::make_shared<MockupTLSCtx>();
562 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
563
564 struct timeval now;
565 gettimeofday(&now, nullptr);
566
567 size_t counter = 1;
568 DNSName name("powerdns.com.");
569 PacketBuffer query;
570 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
571 pwQ.getHeader()->rd = 1;
572 pwQ.getHeader()->id = htons(counter);
573
574 PacketBuffer response;
575 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
576 pwR.getHeader()->qr = 1;
577 pwR.getHeader()->rd = 1;
578 pwR.getHeader()->ra = 1;
579 pwR.getHeader()->id = htons(counter);
580 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
581 pwR.xfr32BitInt(0x01020304);
582 pwR.commit();
583
584 s_responses[counter] = {query, response};
585
db5fbb86 586 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 587 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
588 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
589 backend->d_config.d_dohPath = "/dns-query";
590 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
591
592 auto sender = std::make_shared<MockupQuerySender>();
593 sender->d_id = counter;
592b1d99 594 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
595
596 s_steps = {
1226f653 597 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 598 /* opening */
1226f653 599 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 600 /* settings */
1226f653 601 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 602 /* headers */
1226f653 603 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 604 /* data */
4e82c08c 605 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
606 /* set the outgoing descriptor (backend connection) as ready */
607 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
608 }},
f05cd66c 609 /* read settings, headers and response from the server */
4e82c08c 610 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
becad613
RG
611 /* set the outgoing descriptor (backend connection) as NOT ready anymore */
612 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setNotReady(desc);
613 }},
f05cd66c 614 /* acknowledge settings */
4e82c08c 615 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
becad613
RG
616 s_connectionBuffers.at(desc)->submitGoAway();
617 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
618 }},
619 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1226f653 620 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
621 };
622
623 auto sliced = std::shared_ptr<TCPQuerySender>(sender);
624 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(internalQuery), false);
625 BOOST_CHECK_EQUAL(result, true);
626
627 while (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0) {
628 s_mplexer->run(&now);
629 }
630 BOOST_CHECK_EQUAL(sender->d_valid, true);
631}
632
633BOOST_FIXTURE_TEST_CASE(test_ConcurrentQueries, TestFixture)
634{
690a9c40 635 auto local = getBackendAddress("1", 80);
c114cd18 636 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
637 auto tlsCtx = std::make_shared<MockupTLSCtx>();
638 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
639
640 struct timeval now;
641 gettimeofday(&now, nullptr);
642
db5fbb86 643 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 644 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
645 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
646 backend->d_config.d_dohPath = "/dns-query";
647 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
648
649 size_t numberOfQueries = 2;
650 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
651 for (size_t counter = 0; counter < numberOfQueries; counter++) {
652 DNSName name("powerdns.com.");
653 PacketBuffer query;
654 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
655 pwQ.getHeader()->rd = 1;
656 pwQ.getHeader()->id = htons(counter);
657
658 PacketBuffer response;
659 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
660 pwR.getHeader()->qr = 1;
661 pwR.getHeader()->rd = 1;
662 pwR.getHeader()->ra = 1;
663 pwR.getHeader()->id = htons(counter);
664 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
665 pwR.xfr32BitInt(0x01020304);
666 pwR.commit();
667
668 s_responses[counter] = {query, response};
669
670 auto sender = std::make_shared<MockupQuerySender>();
671 sender->d_id = counter;
592b1d99 672 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
673 queries.push_back({std::move(sender), std::move(internalQuery)});
674 }
675
676 s_steps = {
1226f653 677 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 678 /* opening */
1226f653 679 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 680 /* settings */
1226f653 681 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 682 /* headers */
1226f653 683 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 684 /* data */
4e82c08c 685 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
686 /* set the outgoing descriptor (backend connection) as ready */
687 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
688 }},
f05cd66c 689 /* headers */
1226f653 690 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 691 /* data */
4e82c08c 692 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
693 /* set the outgoing descriptor (backend connection) as ready */
694 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
695 }},
f05cd66c 696 /* read settings, headers and responses from the server */
1226f653 697 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 698 /* acknowledge settings */
4e82c08c 699 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
becad613
RG
700 s_connectionBuffers.at(desc)->submitGoAway();
701 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
702 }},
703 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1226f653 704 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
705 };
706
707 for (auto& query : queries) {
708 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
709 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
710 BOOST_CHECK_EQUAL(result, true);
711 }
712
713 while (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0) {
714 s_mplexer->run(&now);
715 }
716
717 for (auto& query : queries) {
718 BOOST_CHECK_EQUAL(query.first->d_valid, true);
719 }
720}
721
722BOOST_FIXTURE_TEST_CASE(test_ConnectionReuse, TestFixture)
723{
690a9c40 724 auto local = getBackendAddress("1", 80);
c114cd18 725 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
726 auto tlsCtx = std::make_shared<MockupTLSCtx>();
727 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
728
729 struct timeval now;
730 gettimeofday(&now, nullptr);
731
db5fbb86 732 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 733 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
734 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
735 backend->d_config.d_dohPath = "/dns-query";
736 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
737
738 size_t numberOfQueries = 2;
739 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
740 for (size_t counter = 0; counter < numberOfQueries; counter++) {
741 DNSName name("powerdns.com.");
742 PacketBuffer query;
743 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
744 pwQ.getHeader()->rd = 1;
745 pwQ.getHeader()->id = htons(counter);
746
747 PacketBuffer response;
748 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
749 pwR.getHeader()->qr = 1;
750 pwR.getHeader()->rd = 1;
751 pwR.getHeader()->ra = 1;
752 pwR.getHeader()->id = htons(counter);
753 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
754 pwR.xfr32BitInt(0x01020304);
755 pwR.commit();
756
757 s_responses[counter] = {query, response};
758
759 auto sender = std::make_shared<MockupQuerySender>();
760 sender->d_id = counter;
592b1d99 761 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
762 queries.push_back({std::move(sender), std::move(internalQuery)});
763 }
764
becad613 765 bool firstQueryDone = false;
f05cd66c 766 s_steps = {
1226f653 767 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 768 /* opening */
1226f653 769 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 770 /* settings */
1226f653 771 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 772 /* headers */
1226f653 773 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 774 /* data */
4e82c08c 775 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
776 /* set the outgoing descriptor (backend connection) as ready */
777 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
778 }},
f05cd66c 779 /* read settings, headers and responses from the server */
1226f653 780 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 781 /* acknowledge settings */
4e82c08c 782 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [&firstQueryDone](int desc) {
ea090af9
RG
783 firstQueryDone = true;
784 }},
f05cd66c 785 /* headers */
4e82c08c 786 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
ea090af9 787 }},
f05cd66c 788 /* data */
4e82c08c 789 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
790 /* set the outgoing descriptor (backend connection) as ready */
791 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
792 }},
f05cd66c 793 /* read settings, headers and responses from the server */
1226f653 794 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
becad613 795 /* later the backend sends a go away frame */
4e82c08c 796 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
ea090af9 797 s_connectionBuffers.at(desc)->submitGoAway();
becad613 798 }},
1226f653 799 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
800 };
801
802 {
803 auto& query = queries.at(0);
804 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
805 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
806 BOOST_CHECK_EQUAL(result, true);
807
becad613 808 while (!firstQueryDone && (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0)) {
f05cd66c
RG
809 s_mplexer->run(&now);
810 }
811
812 BOOST_CHECK_EQUAL(query.first->d_valid, true);
becad613 813 BOOST_CHECK_EQUAL(firstQueryDone, true);
f05cd66c
RG
814 }
815
816 {
817 auto& query = queries.at(1);
818 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
819 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
820 BOOST_CHECK_EQUAL(result, true);
821
822 while (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0) {
823 s_mplexer->run(&now);
824 }
825
826 BOOST_CHECK_EQUAL(query.first->d_valid, true);
827 }
828}
829
830BOOST_FIXTURE_TEST_CASE(test_InvalidDNSAnswer, TestFixture)
831{
690a9c40 832 auto local = getBackendAddress("1", 80);
c114cd18 833 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
834 auto tlsCtx = std::make_shared<MockupTLSCtx>();
835 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
836
837 struct timeval now;
838 gettimeofday(&now, nullptr);
839
840 size_t counter = 1;
841 DNSName name("powerdns.com.");
842 PacketBuffer query;
843 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
844 pwQ.getHeader()->rd = 1;
845 pwQ.getHeader()->id = htons(counter);
846
847 PacketBuffer response;
848 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
849 pwR.getHeader()->qr = 1;
850 pwR.getHeader()->rd = 1;
851 pwR.getHeader()->ra = 1;
852 pwR.getHeader()->id = htons(counter);
853 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
854 pwR.xfr32BitInt(0x01020304);
855 pwR.commit();
856
857 /* TRUNCATE the answer */
858 response.resize(11);
859 s_responses[counter] = {query, response};
860
db5fbb86 861 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 862 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
863 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
864 backend->d_config.d_dohPath = "/dns-query";
865 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
866
867 auto sender = std::make_shared<MockupQuerySender>();
868 sender->d_id = counter;
869 sender->d_customHandler = [](uint16_t id, const struct timeval&, TCPResponse&& resp) {
870 BOOST_CHECK_EQUAL(resp.d_buffer.size(), 11U);
871 /* simulate an exception, since DoH and UDP frontends will process the query right away,
872 while TCP and DoT will first pass it back to the TCP worker thread */
873 throw std::runtime_error("Invalid response");
874 };
592b1d99 875 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
876
877 s_steps = {
1226f653 878 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 879 /* opening */
1226f653 880 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 881 /* settings */
1226f653 882 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 883 /* headers */
1226f653 884 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 885 /* data */
4e82c08c 886 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
887 /* set the outgoing descriptor (backend connection) as ready */
888 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
889 }},
f05cd66c 890 /* read settings, headers and response from the server */
1226f653 891 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 892 /* acknowledge settings */
1226f653 893 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
becad613 894 /* try to read, the backend says to go away */
4e82c08c 895 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
ea090af9 896 s_connectionBuffers.at(desc)->submitGoAway();
becad613 897 }},
1226f653 898 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
899 };
900
901 auto sliced = std::shared_ptr<TCPQuerySender>(sender);
902 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(internalQuery), false);
903 BOOST_CHECK_EQUAL(result, true);
904
905 while (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0) {
906 s_mplexer->run(&now);
907 }
908 BOOST_CHECK_EQUAL(sender->d_valid, false);
909}
910
911BOOST_FIXTURE_TEST_CASE(test_TimeoutWhileWriting, TestFixture)
912{
690a9c40 913 auto local = getBackendAddress("1", 80);
c114cd18 914 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
915 auto tlsCtx = std::make_shared<MockupTLSCtx>();
916 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
917
918 struct timeval now;
919 gettimeofday(&now, nullptr);
920
db5fbb86 921 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 922 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
923 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
924 backend->d_config.d_dohPath = "/dns-query";
925 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
926
927 size_t numberOfQueries = 2;
928 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
929 for (size_t counter = 0; counter < numberOfQueries; counter++) {
930 DNSName name("powerdns.com.");
931 PacketBuffer query;
932 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
933 pwQ.getHeader()->rd = 1;
934 pwQ.getHeader()->id = htons(counter);
935
936 PacketBuffer response;
937 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
938 pwR.getHeader()->qr = 1;
939 pwR.getHeader()->rd = 1;
940 pwR.getHeader()->ra = 1;
941 pwR.getHeader()->id = htons(counter);
942 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
943 pwR.xfr32BitInt(0x01020304);
944 pwR.commit();
945
946 s_responses[counter] = {query, response};
947
948 auto sender = std::make_shared<MockupQuerySender>();
949 sender->d_id = counter;
592b1d99 950 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
951 queries.push_back({std::move(sender), std::move(internalQuery)});
952 }
953
954 bool timeout = false;
955 s_steps = {
1226f653 956 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 957 /* opening */
1226f653 958 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 959 /* settings */
1226f653 960 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 961 /* headers */
1226f653 962 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 963 /* data */
1226f653 964 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 965 /* headers */
1226f653 966 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 967 /* data */
4e82c08c 968 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::NeedWrite, std::numeric_limits<size_t>::max(), [&timeout](int desc) {
1226f653
RG
969 timeout = true;
970 }},
971 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
972 };
973
974 for (auto& query : queries) {
975 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
976 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
977 BOOST_CHECK_EQUAL(result, true);
978 }
979
980 while (!timeout && (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0)) {
981 s_mplexer->run(&now);
982 }
983
984 struct timeval later = now;
8cf75ac2 985 later.tv_sec += backend->d_config.tcpSendTimeout + 1;
f05cd66c
RG
986
987 auto expiredConns = handleH2Timeouts(*s_mplexer, later);
988 BOOST_CHECK_EQUAL(expiredConns, 1U);
989
990 for (auto& query : queries) {
991 BOOST_CHECK_EQUAL(query.first->d_valid, false);
992 BOOST_CHECK_EQUAL(query.first->d_error, true);
993 }
994
995 BOOST_CHECK_EQUAL(clearH2Connections(), 0U);
996}
997
998BOOST_FIXTURE_TEST_CASE(test_TimeoutWhileReading, TestFixture)
999{
690a9c40 1000 auto local = getBackendAddress("1", 80);
c114cd18 1001 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
1002 auto tlsCtx = std::make_shared<MockupTLSCtx>();
1003 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
1004
1005 struct timeval now;
1006 gettimeofday(&now, nullptr);
1007
db5fbb86 1008 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 1009 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
1010 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
1011 backend->d_config.d_dohPath = "/dns-query";
1012 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
1013
1014 size_t numberOfQueries = 2;
1015 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
1016 for (size_t counter = 0; counter < numberOfQueries; counter++) {
1017 DNSName name("powerdns.com.");
1018 PacketBuffer query;
1019 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
1020 pwQ.getHeader()->rd = 1;
1021 pwQ.getHeader()->id = htons(counter);
1022
1023 PacketBuffer response;
1024 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
1025 pwR.getHeader()->qr = 1;
1026 pwR.getHeader()->rd = 1;
1027 pwR.getHeader()->ra = 1;
1028 pwR.getHeader()->id = htons(counter);
1029 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
1030 pwR.xfr32BitInt(0x01020304);
1031 pwR.commit();
1032
1033 s_responses[counter] = {query, response};
1034
1035 auto sender = std::make_shared<MockupQuerySender>();
1036 sender->d_id = counter;
592b1d99 1037 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
1038 queries.push_back({std::move(sender), std::move(internalQuery)});
1039 }
1040
1041 bool timeout = false;
1042 s_steps = {
1226f653 1043 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 1044 /* opening */
1226f653 1045 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1046 /* settings */
1226f653 1047 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1048 /* headers */
1226f653 1049 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1050 /* data */
1226f653 1051 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1052 /* headers */
1226f653 1053 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1054 /* data */
4e82c08c 1055 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [&timeout](int desc) {
1226f653
RG
1056 /* set the timeout flag now, since the timeout occurs while waiting for the descriptor to become readable */
1057 timeout = true;
1058 }},
1059 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
1060 };
f05cd66c
RG
1061
1062 for (auto& query : queries) {
1063 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
1064 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
1065 BOOST_CHECK_EQUAL(result, true);
1066 }
1067
1068 while (!timeout && (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0)) {
1069 s_mplexer->run(&now);
1070 }
1071
1072 struct timeval later = now;
8cf75ac2 1073 later.tv_sec += backend->d_config.tcpRecvTimeout + 1;
f05cd66c
RG
1074
1075 auto expiredConns = handleH2Timeouts(*s_mplexer, later);
1076 BOOST_CHECK_EQUAL(expiredConns, 1U);
1077
1078 for (auto& query : queries) {
1079 BOOST_CHECK_EQUAL(query.first->d_valid, false);
1080 BOOST_CHECK_EQUAL(query.first->d_error, true);
1081 }
1082 BOOST_CHECK_EQUAL(clearH2Connections(), 0U);
1083}
1084
1085BOOST_FIXTURE_TEST_CASE(test_ShortWrite, TestFixture)
1086{
690a9c40 1087 auto local = getBackendAddress("1", 80);
c114cd18 1088 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
1089 auto tlsCtx = std::make_shared<MockupTLSCtx>();
1090 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
1091
1092 struct timeval now;
1093 gettimeofday(&now, nullptr);
1094
db5fbb86 1095 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 1096 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
1097 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
1098 backend->d_config.d_dohPath = "/dns-query";
1099 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
1100
1101 size_t numberOfQueries = 2;
1102 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
1103 for (size_t counter = 0; counter < numberOfQueries; counter++) {
1104 DNSName name("powerdns.com.");
1105 PacketBuffer query;
1106 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
1107 pwQ.getHeader()->rd = 1;
1108 pwQ.getHeader()->id = htons(counter);
1109
1110 PacketBuffer response;
1111 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
1112 pwR.getHeader()->qr = 1;
1113 pwR.getHeader()->rd = 1;
1114 pwR.getHeader()->ra = 1;
1115 pwR.getHeader()->id = htons(counter);
1116 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
1117 pwR.xfr32BitInt(0x01020304);
1118 pwR.commit();
1119
1120 s_responses[counter] = {query, response};
1121
1122 auto sender = std::make_shared<MockupQuerySender>();
1123 sender->d_id = counter;
592b1d99 1124 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
1125 queries.push_back({std::move(sender), std::move(internalQuery)});
1126 }
1127
becad613 1128 bool done = false;
f05cd66c 1129 s_steps = {
1226f653 1130 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 1131 /* opening */
1226f653 1132 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1133 /* settings */
4e82c08c 1134 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::NeedWrite, 2, [](int desc) {
1226f653
RG
1135 /* set the outgoing descriptor (backend connection) as ready */
1136 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1137 }},
f05cd66c 1138 /* settings (second attempt) + headers + data + headers (second query) + data */
1226f653
RG
1139 {
1140 ExpectedStep::ExpectedRequest::writeToBackend,
1141 IOState::Done,
1142 std::numeric_limits<size_t>::max(),
1143 },
f05cd66c 1144 /* read settings, headers and responses from the server */
1226f653 1145 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1146 /* acknowledge settings */
4e82c08c 1147 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [&done](int desc) {
ea090af9
RG
1148 /* mark backend as not ready */
1149 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setNotReady(desc);
1150 done = true;
1151 }},
1226f653 1152 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
1153 };
1154
1155 for (auto& query : queries) {
1156 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
1157 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
1158 BOOST_CHECK_EQUAL(result, true);
1159 }
1160
becad613 1161 while (!done && (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0)) {
f05cd66c
RG
1162 s_mplexer->run(&now);
1163 }
1164
1165 for (auto& query : queries) {
1166 BOOST_CHECK_EQUAL(query.first->d_valid, true);
1167 }
1168
1169 BOOST_CHECK_EQUAL(clearH2Connections(), 1U);
1170}
1171
1172BOOST_FIXTURE_TEST_CASE(test_ShortRead, TestFixture)
1173{
690a9c40 1174 auto local = getBackendAddress("1", 80);
c114cd18 1175 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
1176 auto tlsCtx = std::make_shared<MockupTLSCtx>();
1177 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
1178
1179 struct timeval now;
1180 gettimeofday(&now, nullptr);
1181
db5fbb86 1182 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 1183 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
1184 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
1185 backend->d_config.d_dohPath = "/dns-query";
1186 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
1187
1188 size_t numberOfQueries = 2;
1189 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
1190 for (size_t counter = 0; counter < numberOfQueries; counter++) {
1191 DNSName name("powerdns.com.");
1192 PacketBuffer query;
1193 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
1194 pwQ.getHeader()->rd = 1;
1195 pwQ.getHeader()->id = htons(counter);
1196
1197 PacketBuffer response;
1198 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
1199 pwR.getHeader()->qr = 1;
1200 pwR.getHeader()->rd = 1;
1201 pwR.getHeader()->ra = 1;
1202 pwR.getHeader()->id = htons(counter);
1203 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
1204 pwR.xfr32BitInt(0x01020304);
1205 pwR.commit();
1206
1207 s_responses[counter] = {query, response};
1208
1209 auto sender = std::make_shared<MockupQuerySender>();
1210 sender->d_id = counter;
592b1d99 1211 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
1212 queries.push_back({std::move(sender), std::move(internalQuery)});
1213 }
1214
becad613 1215 bool done = false;
f05cd66c 1216 s_steps = {
1226f653 1217 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 1218 /* opening */
1226f653 1219 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1220 /* settings */
1226f653 1221 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1222 /* headers */
1226f653 1223 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1224 /* data */
4e82c08c 1225 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1226 /* set the outgoing descriptor (backend connection) as ready */
1227 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1228 }},
f05cd66c 1229 /* headers */
1226f653 1230 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1231 /* data */
4e82c08c 1232 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1233 /* set the outgoing descriptor (backend connection) as ready */
1234 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1235 }},
f05cd66c 1236 /* read settings, headers and responses from the server */
1226f653 1237 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 4},
f05cd66c 1238 /* read settings, headers and responses (second attempt) */
1226f653 1239 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1240 /* acknowledge settings */
4e82c08c 1241 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [&done](int desc) {
ea090af9
RG
1242 /* mark backend as not ready */
1243 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setNotReady(desc);
1244 done = true;
1245 }},
1226f653 1246 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
1247 };
1248
1249 for (auto& query : queries) {
1250 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
1251 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
1252 BOOST_CHECK_EQUAL(result, true);
1253 }
1254
becad613 1255 while (!done && (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0)) {
f05cd66c
RG
1256 s_mplexer->run(&now);
1257 }
1258
1259 for (auto& query : queries) {
1260 BOOST_CHECK_EQUAL(query.first->d_valid, true);
1261 }
1262
1263 BOOST_CHECK_EQUAL(clearH2Connections(), 1U);
1264}
1265
1266BOOST_FIXTURE_TEST_CASE(test_ConnectionClosedWhileReading, TestFixture)
1267{
690a9c40 1268 auto local = getBackendAddress("1", 80);
c114cd18 1269 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
1270 auto tlsCtx = std::make_shared<MockupTLSCtx>();
1271 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
1272
1273 struct timeval now;
1274 gettimeofday(&now, nullptr);
1275
db5fbb86 1276 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 1277 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
1278 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
1279 backend->d_config.d_dohPath = "/dns-query";
1280 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
1281
1282 size_t numberOfQueries = 2;
1283 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
1284 for (size_t counter = 0; counter < numberOfQueries; counter++) {
1285 DNSName name("powerdns.com.");
1286 PacketBuffer query;
1287 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
1288 pwQ.getHeader()->rd = 1;
1289 pwQ.getHeader()->id = htons(counter);
1290
1291 PacketBuffer response;
1292 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
1293 pwR.getHeader()->qr = 1;
1294 pwR.getHeader()->rd = 1;
1295 pwR.getHeader()->ra = 1;
1296 pwR.getHeader()->id = htons(counter);
1297 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
1298 pwR.xfr32BitInt(0x01020304);
1299 pwR.commit();
1300
1301 s_responses[counter] = {query, response};
1302
1303 auto sender = std::make_shared<MockupQuerySender>();
1304 sender->d_id = counter;
592b1d99 1305 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
1306 queries.push_back({std::move(sender), std::move(internalQuery)});
1307 }
1308
1309 s_steps = {
1226f653 1310 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 1311 /* opening */
1226f653 1312 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1313 /* settings */
1226f653 1314 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1315 /* headers */
1226f653 1316 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1317 /* data */
4e82c08c 1318 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1319 /* set the outgoing descriptor (backend connection) as ready */
1320 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1321 }},
f05cd66c 1322 /* headers */
1226f653 1323 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1324 /* data */
4e82c08c 1325 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1326 /* set the outgoing descriptor (backend connection) as ready */
1327 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1328 }},
f05cd66c 1329 /* read settings, headers and responses from the server */
1226f653
RG
1330 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, 0},
1331 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
1332 };
1333
1334 for (auto& query : queries) {
1335 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
1336 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
1337 BOOST_CHECK_EQUAL(result, true);
1338 }
1339
1340 while (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0) {
1341 s_mplexer->run(&now);
1342 }
1343
1344 for (auto& query : queries) {
1345 BOOST_CHECK_EQUAL(query.first->d_valid, false);
1346 BOOST_CHECK_EQUAL(query.first->d_error, true);
1347 }
1348
1349 BOOST_CHECK_EQUAL(clearH2Connections(), 0U);
1350}
1351
1352BOOST_FIXTURE_TEST_CASE(test_ConnectionClosedWhileWriting, TestFixture)
1353{
690a9c40 1354 auto local = getBackendAddress("1", 80);
c114cd18 1355 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
1356 auto tlsCtx = std::make_shared<MockupTLSCtx>();
1357 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
1358
1359 struct timeval now;
1360 gettimeofday(&now, nullptr);
1361
db5fbb86 1362 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 1363 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
1364 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
1365 backend->d_config.d_dohPath = "/dns-query";
1366 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
1367
1368 size_t numberOfQueries = 2;
1369 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
1370 for (size_t counter = 0; counter < numberOfQueries; counter++) {
1371 DNSName name("powerdns.com.");
1372 PacketBuffer query;
1373 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
1374 pwQ.getHeader()->rd = 1;
1375 pwQ.getHeader()->id = htons(counter);
1376
1377 PacketBuffer response;
1378 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
1379 pwR.getHeader()->qr = 1;
1380 pwR.getHeader()->rd = 1;
1381 pwR.getHeader()->ra = 1;
1382 pwR.getHeader()->id = htons(counter);
1383 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
1384 pwR.xfr32BitInt(0x01020304);
1385 pwR.commit();
1386
1387 s_responses[counter] = {query, response};
1388
1389 auto sender = std::make_shared<MockupQuerySender>();
1390 sender->d_id = counter;
592b1d99 1391 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
1392 queries.push_back({std::move(sender), std::move(internalQuery)});
1393 }
1394
becad613 1395 bool done = false;
f05cd66c 1396 s_steps = {
1226f653 1397 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 1398 /* opening */
1226f653 1399 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1400 /* settings */
1226f653 1401 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1402 /* headers, connection is closed by the backend */
1226f653
RG
1403 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, 0},
1404 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
1405 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 1406 /* opening */
1226f653 1407 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1408 /* settings */
1226f653 1409 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1410 /* headers */
1226f653 1411 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1412 /* data */
4e82c08c 1413 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1414 /* set the outgoing descriptor (backend connection) as ready */
1415 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1416 }},
f05cd66c 1417 /* read settings, headers and response from the server */
1226f653 1418 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1419 /* acknowledge settings */
4e82c08c 1420 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [&done](int desc) {
ea090af9
RG
1421 /* mark backend as not ready */
1422 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setNotReady(desc);
1423 done = true;
1424 }},
1226f653 1425 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
1426 };
1427
1428 for (auto& query : queries) {
1429 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
1430 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
1431 BOOST_CHECK_EQUAL(result, true);
1432 }
1433
becad613 1434 while (!done && (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0)) {
f05cd66c
RG
1435 s_mplexer->run(&now);
1436 }
1437
1438 BOOST_CHECK_EQUAL(queries.at(0).first->d_valid, false);
1439 BOOST_CHECK_EQUAL(queries.at(0).first->d_error, true);
1440 BOOST_CHECK_EQUAL(queries.at(1).first->d_valid, true);
1441 BOOST_CHECK_EQUAL(queries.at(1).first->d_error, false);
1442
1443 BOOST_CHECK_EQUAL(clearH2Connections(), 1U);
1444}
1445
1446BOOST_FIXTURE_TEST_CASE(test_GoAwayFromServer, TestFixture)
1447{
690a9c40 1448 auto local = getBackendAddress("1", 80);
c114cd18 1449 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
1450 auto tlsCtx = std::make_shared<MockupTLSCtx>();
1451 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
1452
1453 struct timeval now;
1454 gettimeofday(&now, nullptr);
1455
db5fbb86 1456 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 1457 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
1458 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
1459 backend->d_config.d_dohPath = "/dns-query";
1460 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c 1461 /* set the number of reconnection attempts to a low value to not waste time */
8cf75ac2 1462 backend->d_config.d_retries = 1;
f05cd66c
RG
1463
1464 size_t numberOfQueries = 2;
1465 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
1466 for (size_t counter = 0; counter < numberOfQueries; counter++) {
1467 DNSName name("goaway.powerdns.com.");
1468 PacketBuffer query;
1469 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
1470 pwQ.getHeader()->rd = 1;
1471 pwQ.getHeader()->id = htons(counter);
1472
1473 PacketBuffer response;
1474 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
1475 pwR.getHeader()->qr = 1;
1476 pwR.getHeader()->rd = 1;
1477 pwR.getHeader()->ra = 1;
1478 pwR.getHeader()->id = htons(counter);
1479 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
1480 pwR.xfr32BitInt(0x01020304);
1481 pwR.commit();
1482
1483 s_responses[counter] = {query, response};
1484
1485 auto sender = std::make_shared<MockupQuerySender>();
1486 sender->d_id = counter;
592b1d99 1487 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
1488 queries.push_back({std::move(sender), std::move(internalQuery)});
1489 }
1490
1491 s_steps = {
1226f653 1492 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 1493 /* opening */
1226f653 1494 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1495 /* settings */
1226f653 1496 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1497 /* headers */
1226f653 1498 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1499 /* data */
4e82c08c 1500 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1501 /* set the outgoing descriptor (backend connection) as ready */
1502 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1503 }},
f05cd66c 1504 /* headers */
1226f653 1505 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1506 /* data */
4e82c08c 1507 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1508 /* set the outgoing descriptor (backend connection) as ready */
1509 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1510 }},
f05cd66c 1511 /* read GO AWAY from the server (1) */
1226f653
RG
1512 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1513 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 1514 /* opening */
1226f653 1515 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1516 /* settings */
1226f653 1517 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1518 /* headers */
1226f653 1519 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1520 /* data */
4e82c08c 1521 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1522 /* set the outgoing descriptor (backend connection) as ready */
1523 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1524 }},
f05cd66c 1525 /* headers */
1226f653 1526 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1527 /* data */
4e82c08c 1528 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1529 /* set the outgoing descriptor (backend connection) as ready */
1530 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1531 }},
f05cd66c 1532 /* close the first connection. It happens now because the new connection was set up first, then that one destroyed */
1226f653 1533 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c 1534 /* read GO AWAY from the server (1) */
1226f653
RG
1535 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1536 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
1537 };
1538
1539 for (auto& query : queries) {
1540 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
1541 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
1542 BOOST_CHECK_EQUAL(result, true);
1543 }
1544
1545 while (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0) {
1546 s_mplexer->run(&now);
1547 }
1548
1549 for (auto& query : queries) {
1550 BOOST_CHECK_EQUAL(query.first->d_valid, false);
1551 BOOST_CHECK_EQUAL(query.first->d_error, true);
1552 }
1553
1554 BOOST_CHECK_EQUAL(clearH2Connections(), 0U);
1555}
1556
1557BOOST_FIXTURE_TEST_CASE(test_HTTP500FromServer, TestFixture)
1558{
690a9c40 1559 auto local = getBackendAddress("1", 80);
c114cd18 1560 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
1561 auto tlsCtx = std::make_shared<MockupTLSCtx>();
1562 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
1563
1564 struct timeval now;
1565 gettimeofday(&now, nullptr);
1566
db5fbb86 1567 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 1568 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
1569 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
1570 backend->d_config.d_dohPath = "/dns-query";
1571 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
1572
1573 size_t numberOfQueries = 2;
1574 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
1575 for (size_t counter = 0; counter < numberOfQueries; counter++) {
1576 DNSName name("500.powerdns.com.");
1577 PacketBuffer query;
1578 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
1579 pwQ.getHeader()->rd = 1;
1580 pwQ.getHeader()->id = htons(counter);
1581
1582 PacketBuffer response;
1583 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
1584 pwR.getHeader()->qr = 1;
1585 pwR.getHeader()->rd = 1;
1586 pwR.getHeader()->ra = 1;
1587 pwR.getHeader()->id = htons(counter);
1588 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
1589 pwR.xfr32BitInt(0x01020304);
1590 pwR.commit();
1591
1592 s_responses[counter] = {query, response};
1593
1594 auto sender = std::make_shared<MockupQuerySender>();
1595 sender->d_id = counter;
592b1d99 1596 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
1597 queries.push_back({std::move(sender), std::move(internalQuery)});
1598 }
1599
becad613 1600 bool done = false;
f05cd66c 1601 s_steps = {
1226f653 1602 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 1603 /* opening */
1226f653 1604 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1605 /* settings */
1226f653 1606 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1607 /* headers */
1226f653 1608 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1609 /* data */
4e82c08c 1610 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1611 /* set the outgoing descriptor (backend connection) as ready */
1612 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1613 }},
f05cd66c 1614 /* headers */
1226f653 1615 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1616 /* data */
4e82c08c 1617 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1618 /* set the outgoing descriptor (backend connection) as ready */
1619 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1620 }},
f05cd66c 1621 /* read settings, headers and responses from the server */
1226f653 1622 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1623 /* acknowledge settings */
4e82c08c 1624 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [&done](int desc) {
ea090af9
RG
1625 /* mark backend as not ready */
1626 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setNotReady(desc);
1627 done = true;
1628 }},
1226f653 1629 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
1630 };
1631
1632 for (auto& query : queries) {
1633 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
1634 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
1635 BOOST_CHECK_EQUAL(result, true);
1636 }
1637
becad613 1638 while (!done && (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0)) {
f05cd66c
RG
1639 s_mplexer->run(&now);
1640 }
1641
1642 BOOST_CHECK_EQUAL(queries.at(0).first->d_valid, false);
1643 BOOST_CHECK_EQUAL(queries.at(0).first->d_error, true);
1644 BOOST_CHECK_EQUAL(queries.at(1).first->d_valid, true);
1645 BOOST_CHECK_EQUAL(queries.at(1).first->d_error, false);
1646
1647 BOOST_CHECK_EQUAL(clearH2Connections(), 1U);
1648}
1649
1650BOOST_FIXTURE_TEST_CASE(test_WrongStreamID, TestFixture)
1651{
690a9c40 1652 auto local = getBackendAddress("1", 80);
c114cd18 1653 ClientState localCS(local, true, false, 0, "", {}, true);
f05cd66c
RG
1654 auto tlsCtx = std::make_shared<MockupTLSCtx>();
1655 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
1656
1657 struct timeval now;
1658 gettimeofday(&now, nullptr);
1659
db5fbb86 1660 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
f05cd66c 1661 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
1662 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
1663 backend->d_config.d_dohPath = "/dns-query";
1664 backend->d_config.d_addXForwardedHeaders = true;
f05cd66c
RG
1665
1666 size_t numberOfQueries = 2;
1667 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
1668 for (size_t counter = 0; counter < numberOfQueries; counter++) {
1669 DNSName name("wrong-stream-id.powerdns.com.");
1670 PacketBuffer query;
1671 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
1672 pwQ.getHeader()->rd = 1;
1673 pwQ.getHeader()->id = htons(counter);
1674
1675 PacketBuffer response;
1676 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
1677 pwR.getHeader()->qr = 1;
1678 pwR.getHeader()->rd = 1;
1679 pwR.getHeader()->ra = 1;
1680 pwR.getHeader()->id = htons(counter);
1681 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
1682 pwR.xfr32BitInt(0x01020304);
1683 pwR.commit();
1684
1685 s_responses[counter] = {query, response};
1686
1687 auto sender = std::make_shared<MockupQuerySender>();
1688 sender->d_id = counter;
592b1d99 1689 InternalQuery internalQuery(std::move(query), InternalQueryState());
f05cd66c
RG
1690 queries.push_back({std::move(sender), std::move(internalQuery)});
1691 }
1692
1693 bool timeout = false;
1694 s_steps = {
1226f653 1695 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
f05cd66c 1696 /* opening */
1226f653 1697 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1698 /* settings */
1226f653 1699 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1700 /* headers */
1226f653 1701 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1702 /* data */
4e82c08c 1703 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1704 /* set the outgoing descriptor (backend connection) as ready */
1705 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1706 }},
f05cd66c 1707 /* headers */
1226f653 1708 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1709 /* data */
4e82c08c 1710 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
1226f653
RG
1711 /* set the outgoing descriptor (backend connection) as ready */
1712 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1713 }},
f05cd66c 1714 /* read settings, headers and responses from the server */
1226f653 1715 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1716 /* acknowledge settings */
1226f653 1717 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
f05cd66c 1718 /* read ends up as a time out since nghttp2 filters the frame with the wrong stream ID */
4e82c08c 1719 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::NeedRead, 0, [&timeout](int desc) {
1226f653
RG
1720 /* set the timeout flag now, since the timeout occurs while waiting for the descriptor to become readable */
1721 timeout = true;
1722 }},
1723 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
f05cd66c
RG
1724 };
1725
1726 for (auto& query : queries) {
1727 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
1728 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
1729 BOOST_CHECK_EQUAL(result, true);
1730 }
1731
1732 while (!timeout && (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0)) {
1733 s_mplexer->run(&now);
1734 }
1735
1736 struct timeval later = now;
8cf75ac2 1737 later.tv_sec += backend->d_config.tcpRecvTimeout + 1;
f05cd66c
RG
1738
1739 auto expiredConns = handleH2Timeouts(*s_mplexer, later);
1740 BOOST_CHECK_EQUAL(expiredConns, 1U);
1741
1742 BOOST_CHECK_EQUAL(queries.at(0).first->d_valid, false);
1743 BOOST_CHECK_EQUAL(queries.at(0).first->d_error, true);
1744 BOOST_CHECK_EQUAL(queries.at(1).first->d_valid, false);
1745 BOOST_CHECK_EQUAL(queries.at(1).first->d_error, true);
1746
1747 BOOST_CHECK_EQUAL(clearH2Connections(), 0U);
1748}
1749
0e6892c6
RG
1750BOOST_FIXTURE_TEST_CASE(test_ProxyProtocol, TestFixture)
1751{
690a9c40 1752 auto local = getBackendAddress("1", 80);
c114cd18 1753 ClientState localCS(local, true, false, 0, "", {}, true);
0e6892c6
RG
1754 auto tlsCtx = std::make_shared<MockupTLSCtx>();
1755 tlsCtx->d_needProxyProtocol = true;
1756 localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
1757
1758 struct timeval now;
1759 gettimeofday(&now, nullptr);
1760
db5fbb86 1761 auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
0e6892c6 1762 backend->d_tlsCtx = tlsCtx;
8cf75ac2
RG
1763 backend->d_config.d_tlsSubjectName = "backend.powerdns.com";
1764 backend->d_config.d_dohPath = "/dns-query";
1765 backend->d_config.d_addXForwardedHeaders = true;
1766 backend->d_config.useProxyProtocol = true;
0e6892c6
RG
1767
1768 size_t numberOfQueries = 2;
1769 std::vector<std::pair<std::shared_ptr<MockupQuerySender>, InternalQuery>> queries;
1770 for (size_t counter = 0; counter < numberOfQueries; counter++) {
1771 DNSName name("powerdns.com.");
1772 PacketBuffer query;
1773 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
1774 pwQ.getHeader()->rd = 1;
1775 pwQ.getHeader()->id = htons(counter);
1776
1777 PacketBuffer response;
1778 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
1779 pwR.getHeader()->qr = 1;
1780 pwR.getHeader()->rd = 1;
1781 pwR.getHeader()->ra = 1;
1782 pwR.getHeader()->id = htons(counter);
1783 pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
1784 pwR.xfr32BitInt(0x01020304);
1785 pwR.commit();
1786
1787 s_responses[counter] = {query, response};
1788
1789 auto sender = std::make_shared<MockupQuerySender>();
1790 sender->d_id = counter;
1791 std::string payload = makeProxyHeader(counter % 2, local, local, {});
592b1d99 1792 InternalQuery internalQuery(std::move(query), InternalQueryState());
0e6892c6
RG
1793 internalQuery.d_proxyProtocolPayload = std::move(payload);
1794 queries.push_back({std::move(sender), std::move(internalQuery)});
1795 }
1796
1797 s_steps = {
1798 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
1799 /* proxy protocol data + opening */
1800 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1801 /* settings */
1802 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1803 /* headers */
1804 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1805 /* data */
4e82c08c 1806 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
0e6892c6
RG
1807 /* set the outgoing descriptor (backend connection) as ready */
1808 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1809 }},
1810 {ExpectedStep::ExpectedRequest::connectToBackend, IOState::Done},
1811 /* proxy protocol data + opening */
1812 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1813 /* settings */
1814 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1815 /* headers */
1816 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1817 /* data */
4e82c08c 1818 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max(), [](int desc) {
0e6892c6
RG
1819 /* set the outgoing descriptor (backend connection) as ready */
1820 dynamic_cast<MockupFDMultiplexer*>(s_mplexer.get())->setReady(desc);
1821 }},
1822 /* read settings, headers and responses from the server */
1823 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1824 /* acknowledge settings */
1825 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1826 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
1827 /* read settings, headers and responses from the server */
1828 {ExpectedStep::ExpectedRequest::readFromBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1829 /* acknowledge settings */
1830 {ExpectedStep::ExpectedRequest::writeToBackend, IOState::Done, std::numeric_limits<size_t>::max()},
1831 {ExpectedStep::ExpectedRequest::closeBackend, IOState::Done},
1832 };
1833
1834 for (auto& query : queries) {
1835 auto sliced = std::static_pointer_cast<TCPQuerySender>(query.first);
1836 bool result = sendH2Query(backend, s_mplexer, sliced, std::move(query.second), false);
1837 BOOST_CHECK_EQUAL(result, true);
1838 }
1839
1840 while (s_mplexer->getWatchedFDCount(false) != 0 || s_mplexer->getWatchedFDCount(true) != 0) {
1841 s_mplexer->run(&now);
1842 }
1843
1844 for (auto& query : queries) {
1845 BOOST_CHECK_EQUAL(query.first->d_valid, true);
1846 }
becad613
RG
1847
1848 BOOST_CHECK_EQUAL(clearH2Connections(), 0U);
0e6892c6
RG
1849}
1850
f05cd66c 1851BOOST_AUTO_TEST_SUITE_END();
cf25b82b 1852#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */