libhttppp ..
Loading...
Searching...
No Matches
checksum_common.h
1/*******************************************************************************
2Copyright (c) 2026, Jan Koester jan.koester@gmx.net
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the <organization> nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*******************************************************************************/
27
28// Shared checksum/random-payload helpers and request handler for the
29// HTTP/1.1, HTTP/2 and HTTP/3 checksum integrity tests
30// (http1_checksum_test.cpp, http2_checksum_test.cpp, http3_checksum_test.cpp).
31//
32// The three protocol tests each drive a real client<->server exchange over
33// their own wire format, but they all exercise the SAME server-side
34// RequestEvent, because HttpEvent::RequestEvent() gets the request body in
35// curreq.RecvData and lets a response header be attached via
36// setHeaderData() identically regardless of protocol -- HTTP/2 and HTTP/3
37// forward extra HttpResponse headers to the wire via the library's internal
38// ":res-*" pseudo-header convention (see HttpResponse::_storeResponseInfo /
39// httpd.cpp's _finishH2Dispatch), so a single handler genuinely covers all
40// three protocols.
41
42#pragma once
43
44#include <cstdint>
45#include <iostream>
46#include <string>
47#include <thread>
48#include <vector>
49
50#include <netplus/crypto/sha.h>
51#include <netplus/random.h>
52
53#include "http.h"
54#include "httpd.h"
55
56namespace checksumtest {
57
58inline std::string sha256Hex(const char *data, size_t len) {
59 std::vector<uint8_t> buf(reinterpret_cast<const uint8_t *>(data),
60 reinterpret_cast<const uint8_t *>(data) + len);
61 std::vector<uint8_t> digest = netplus::sha256_hash(buf);
62 static const char *hexd = "0123456789abcdef";
63 std::string out;
64 out.reserve(digest.size() * 2);
65 for (uint8_t b : digest) {
66 out.push_back(hexd[b >> 4]);
67 out.push_back(hexd[b & 0x0f]);
68 }
69 return out;
70}
71
72inline std::string sha256Hex(const std::vector<char> &data) {
73 return sha256Hex(data.data(), data.size());
74}
75
76inline std::vector<char> randomBuffer(size_t len) {
77 std::vector<char> buf(len);
78 if (len)
79 netplus::fillRandomBytes(reinterpret_cast<uint8_t *>(buf.data()), len);
80 return buf;
81}
82
83// Small-to-large sweep: an empty body, a single byte, a few KB, one that
84// spans several TCP/TLS records or H2/H3 frames (64KB) and one that is
85// guaranteed to exhaust the HTTP/2 64KB-ish default flow-control window and
86// force multiple round trips (1MB).
87inline const std::vector<size_t> &sweepSizes() {
88 static const std::vector<size_t> sizes = {0, 1, 4096, 65536, 1048576};
89 return sizes;
90}
91
92// GET /gen/<n> -> <n> random bytes, with X-Sha256 holding their checksum.
93// POST /echo -> echoes the request body back, with X-Sha256 holding the
94// checksum of what the server actually received (so
95// upload integrity is verified independently of what the
96// client remembers sending, and download integrity is
97// verified by the client comparing the echoed bytes to
98// its own copy).
100public:
101 explicit ChecksumEvent(std::vector<netplus::socket *> serversocket)
102 : libhttppp::HttpEvent(serversocket) {}
103
104 void RequestEvent(libhttppp::HttpRequest &req, const int, ULONG_PTR) override {
105 try {
106 const std::string &url = req.getRequestURL();
107
108 if (url.rfind("/gen/", 0) == 0) {
109 size_t len = 0;
110 try { len = static_cast<size_t>(std::stoull(url.substr(5))); }
111 catch (...) { len = 0; }
112
113 std::vector<char> body = randomBuffer(len);
114 std::string hash = sha256Hex(body);
115
117 res.setContentType("application/octet-stream");
118 res.setHeaderData("x-sha256")->push_back(hash);
119 res.send(req, body, static_cast<int>(body.size()));
120 return;
121 }
122
123 if (url == "/echo") {
124 std::vector<char> body(req.RecvData.data(),
125 req.RecvData.data() + req.RecvData.size());
126 std::string hash = sha256Hex(body);
127
129 res.setContentType("application/octet-stream");
130 res.setHeaderData("x-sha256")->push_back(hash);
131 res.send(req, body, static_cast<int>(body.size()));
132 return;
133 }
134
136 res.setState("404 Not Found");
137 res.send(req, std::string("not found"), 9);
138 } catch (libhttppp::HTTPException &e) {
139 std::cerr << "[ChecksumEvent] " << e.what() << std::endl;
140 }
141 }
142};
143
144// RAII stop/join for a server thread running HttpEvent::runEventloop().
145// Letting such a thread outlive its netplus::event/socket objects (e.g. via
146// detach()) races epoll teardown (netplus::poll's CloseEventHandler)
147// against object/process teardown and can segfault; joining it -- on every
148// exit path, including exceptions -- avoids that race. Declare this AFTER
149// the socket/event objects it targets so it destructs (and joins) BEFORE
150// them, in a scope that has already started the thread.
152 std::thread *t;
154 if (t && t->joinable()) {
155 netplus::event::Running = false;
156 t->join();
157 }
158 }
159};
160
161} // namespace checksumtest
Definition checksum_common.h:99
Definition exception.h:43
Definition httpd.h:51
Definition http.h:435
Definition http.h:370
Definition checksum_common.h:151