summaryrefslogtreecommitdiffhomepage
path: root/tests/webserverprocess.cpp
blob: 31c976647dee02362988bffa82c91d05c72cf205 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#include "webserverprocess.h"

#include <boost/test/data/dataset.hpp>
#include <boost/test/data/monomorphic.hpp>
#include <boost/test/data/test_case.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/buffers_iterator.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

#include <fmt/core.h>

#include <chrono>
#include <exception>
#include <filesystem>
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
#include <stdexcept>
#include <string>
#include <thread>

#include <ext/stdio_filebuf.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>

#include <libreichwein/file.h>
#include <libreichwein/process.h>

#include "webserver.h"
#include "helper.h"

using namespace std::string_literals;
namespace fs = std::filesystem;
namespace pt = boost::property_tree;
using namespace boost::unit_test;
using namespace Reichwein;

void WebserverProcess::init(const std::string& config)
{
 m_config = config;
 File::setFile(testConfigFilename, config);

 // test self signed certificate
 File::setFile(testCertFilename, R"(-----BEGIN CERTIFICATE-----
MIIC4zCCAcugAwIBAgIUeS9y+EsFWxf+foEx6SJ/R56rmX8wDQYJKoZIhvcNAQEL
BQAwADAgFw0yMzAxMDYxNzIwNTFaGA8yMDUwMDUyNDE3MjA1MVowADCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALiZSICAcXng9j7zAb873U4TpuzvRVfh
xS3gEhxqNPs6+ZQ43nAxDSdafzfGxpTkElTt/REj4oEOLw+QWI/jfbe4gDRDzf6V
ij0fVuzp02JtJSS+dNrLv17NufBydOyD8oDrPehVrPlrZQhhkYMvLHAim+wikT2O
s0es2R+avixxAZvx5EYgHba9T7R/pC/lA4BI3lEbVKjDA83hZvjPH1YdK+RYQS2g
Jygdhe8qOSswXIwFAF3MMBpwRD3mz+vAJZP3lpBGsn+asO6Xd/5cjC8msgomS8Ji
c9DMMNlrE1WU73wVG9n0OJcke2XEtzARVKJLlBPsug4oxDev6O4GakkCAwEAAaNT
MFEwHQYDVR0OBBYEFE4i7Gtyn30qpIkH6f0/wuFA45pjMB8GA1UdIwQYMBaAFE4i
7Gtyn30qpIkH6f0/wuFA45pjMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
BQADggEBAIlGv4b2yLmTOrXOPNst2y3J+GiRvuMKoAfDt5KLxUhbCmPgJzGDWn0l
60xXBX/t2uo3dQa9yAIW64RqhEQX7uja/7B3PmJZlgF7+owvT8OZA4+UN1lLUvY4
V7mUzuKuqo5jcX8EmZnHrJ4TGZ0dXbT1hAUgqIjnDChjWyvs4B9zZL5FTisPUic7
MU+FcpKJ5M6iJ150d9hzLiwmJyPLkW5Grq0Jh22njUQwWW2vIMn4cA3CyS64+oi2
DNnDgde3mYxXL8Oki7CbeCTpmUXcBHmQtWOvKZPCsOzMF4moTLC4DdElvOpwKCAK
ABd6rubkarwvDV7wEo1eSuAHPZ/KhGo=
-----END CERTIFICATE-----
)");
 File::setFile(testKeyFilename, R"(-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC4mUiAgHF54PY+
8wG/O91OE6bs70VX4cUt4BIcajT7OvmUON5wMQ0nWn83xsaU5BJU7f0RI+KBDi8P
kFiP4323uIA0Q83+lYo9H1bs6dNibSUkvnTay79ezbnwcnTsg/KA6z3oVaz5a2UI
YZGDLyxwIpvsIpE9jrNHrNkfmr4scQGb8eRGIB22vU+0f6Qv5QOASN5RG1SowwPN
4Wb4zx9WHSvkWEEtoCcoHYXvKjkrMFyMBQBdzDAacEQ95s/rwCWT95aQRrJ/mrDu
l3f+XIwvJrIKJkvCYnPQzDDZaxNVlO98FRvZ9DiXJHtlxLcwEVSiS5QT7LoOKMQ3
r+juBmpJAgMBAAECggEACjs5suCbmYAb2d2VZlRitdP+Q6HX37D0YTBrBI7o6JdK
U7oqrwBy/JBGHpDqewBgmTs3FGr/H/zJpDTRickXs9X6qhrreQ2wA6b/5gHoPMt0
nHKfbqyOCuq/YGmxnBXMnDNdoynTfGAE0af5vRIBZiYu6vG4B9fHzURR5O/qVDNn
WqJ+2Y8AAf4mJDCBEvJz2RaZwSq788i/d8oTSeCk93TDF+GHhUq6ymkORACj76ws
8ohfoNQIG1VhdcTK2GOQjqctEFUm54t9N1nxD6VavMu5DlSSVsPTDbYuE5U4cy3T
ThDtoYJgwz5KRflklwl3xoDJVx3B5wMUaqviRp6l0QKBgQC6MPG+EV2drsHwG0Wg
gnP4uCSuFAfWBlHAQyZv5PMQBNfM8YjyMyL+O7cggGNJSOZr/X30EqoBe+LXrL3X
Gtix8F1Ed0fbAarAgxIwq8MktzmastDq4XS+zwYPZ7UTbmbqvT3VYPga4Sh90fyY
nPJpqZvhvGzQX22yeHS7vTSQOQKBgQD9z36EIYMuLl0HJK6gfjGHsy/Rx7bw1TmP
aHmuF8Ra7rpDSOym0ImKWTOLEoLlQUsMz/FuVLCGP/ACjMFKsqh3Zy/0hVJOMDMR
Z+ODT28Hcz4AMcTYDvcTYd70HhhZL+/eFCVk8Nk164saMuhifAkOgvwfaYs0m3ue
S9jxlZKKkQKBgHgBzf6k8MMOfaAF4/XVv2wDPFkbPgW74vtaDK84UVX02ScWUx9Q
yHA3Cwye09/LZgEazREA6qS0NfyvMVkwy5S9CVB01VKam3UjxhiqzMegdTd5o+CQ
WpAVnaFWRcb1dM4+FVmv+5pPn6qhKv8uwaxLDtcLfNM9ftX2f77176g5AoGADWtQ
DBpdfi6TWpJU7UVexwbxS00c3gTYAz4J2OuGxSwECxSq9nLmIrtunza+VvKpziac
ZDH0F1UAEpJwkct6Xr3E6k+2N04TFSOCAupLO4CbUZVQDABWjd7J0+xXaze+neZA
x+J4CYLHmv4ADVzzeaHxRJPm+UQTOB5YfQVkdxECgYBv3QuUMiBGKWgeheP4nAFU
SVgqGBQwAtqb5DR1YVJ4LFPt+jyrQMby6mqSlzENYcidSP3Ogn22CvST+bAjbf6D
D/ae1zeOHBls00ILHANv1Z/hXcEkiKnZdeP6O43xBfCS+Lps5daXgUbC0kw2R09S
VZTqPHmb+db0rFA3XlAg2A==
-----END PRIVATE KEY-----
)");
 start();
}

WebserverProcess::WebserverProcess(const std::string& config, bool wait_for_listener):
 m_pid{}, m_wait_for_listener{wait_for_listener}
{
 init(config);
}

WebserverProcess::WebserverProcess(bool wait_for_listener):
 m_pid{}, m_wait_for_listener{wait_for_listener}
{
 std::string config{R"CONFIG(<webserver>
 <user>www-data</user>
 <group>www-data</group>
 <threads>10</threads>
 <statisticspath>stats.db</statisticspath>
 <plugin-directory>../plugins</plugin-directory>
 <sites>
  <site>
   <name>localhost</name>
   <host>ip6-localhost</host>
   <host>localhost</host>
   <host>127.0.0.1</host>
   <host>[::1]</host>
   <path requested="/">
    <plugin>static-files</plugin>
    <target>.</target>
   </path>
   <certpath>testchain.pem</certpath>
   <keypath>testkey.pem</keypath>
  </site>
 </sites>
 <sockets>
  <socket>
   <address>127.0.0.1</address>
   <port>8080</port>
   <protocol>http</protocol>
   <site>localhost</site>
  </socket>
  <socket>
   <address>::1</address>
   <port>8080</port>
   <protocol>http</protocol>
   <site>localhost</site>
  </socket>
  <socket>
   <address>127.0.0.1</address>
   <port>8081</port>
   <protocol>https</protocol>
   <site>localhost</site>
  </socket>
  <socket>
   <address>::1</address>
   <port>8081</port>
   <protocol>https</protocol>
   <site>localhost</site>
  </socket>
 </sockets>
</webserver>
)CONFIG"};
 init(config);
}

WebserverProcess::~WebserverProcess()
{
 stop();
 fs::remove(testConfigFilename);
 fs::remove(testCertFilename);
 fs::remove(testKeyFilename);
}

void WebserverProcess::start()
{
 if (m_pid != 0)
  throw std::runtime_error("Process already running, so it can't be started");

 m_pid = fork();
 if (m_pid < 0)
  throw std::runtime_error("Fork unsuccessful.");

 if (m_pid == 0) { // child process branch
  char* argv[] = {(char*)"webserver", (char*)"-c", (char*)"./webserver.conf"};
  webserver(sizeof(argv) / sizeof(char*), argv);
  exit(0);
 }
 
 if (m_wait_for_listener) {
  // wait for server to start up
  if (int port{port_from_config(m_config)}; port >= 0)
   Process::wait_for_pid_listening_on(m_pid, port);
 }
 std::this_thread::sleep_for(std::chrono::milliseconds(20));
}

void WebserverProcess::stop()
{
 if (m_pid == 0)
  throw std::runtime_error("Process not running, so it can't be stopped");
 
 if (kill(m_pid, SIGTERM) != 0)
  throw std::runtime_error("Unable to kill process");

 if (int result = waitpid(m_pid, NULL, 0); result != m_pid)
  throw std::runtime_error("waitpid returned "s + std::to_string(result));

 m_pid = 0;
}

bool WebserverProcess::is_running()
{
 if (m_pid == 0)
  return false;

 return Reichwein::Process::is_running(m_pid);
}