1//
2// HTTPSTestServer.cpp
3//
4// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
5// and Contributors.
6//
7// SPDX-License-Identifier: BSL-1.0
8//
9
10
11#include "HTTPSTestServer.h"
12#include "Poco/Net/SecureStreamSocket.h"
13#include "Poco/Net/SocketAddress.h"
14#include "Poco/Net/SecureStreamSocketImpl.h"
15#include "Poco/Timespan.h"
16#include "Poco/NumberFormatter.h"
17#include <iostream>
18
19
20using Poco::Net::Socket;
21using Poco::Net::StreamSocket;
22using Poco::Net::SecureStreamSocket;
23using Poco::Net::SecureServerSocket;
24using Poco::Net::SocketAddress;
25using Poco::Net::SecureStreamSocketImpl;
26using Poco::NumberFormatter;
27
28
29const std::string HTTPSTestServer::SMALL_BODY("This is some random text data returned by the server");
30const std::string HTTPSTestServer::LARGE_BODY(4000, 'x');
31
32
33HTTPSTestServer::HTTPSTestServer():
34 _socket(SocketAddress()),
35 _thread("HTTPSTestServer"),
36 _stop(false)
37{
38 _thread.start(*this);
39 _ready.wait();
40 _lastRequest.reserve(4000);
41}
42
43
44HTTPSTestServer::HTTPSTestServer(Poco::Net::Context::Ptr pContext):
45 _socket(SocketAddress(), 64, pContext),
46 _thread("HTTPSTestServer"),
47 _stop(false)
48{
49 _thread.start(*this);
50 _ready.wait();
51 _lastRequest.reserve(4000);
52}
53
54
55HTTPSTestServer::~HTTPSTestServer()
56{
57 _stop = true;
58 _thread.join();
59}
60
61
62Poco::UInt16 HTTPSTestServer::port() const
63{
64 return _socket.address().port();
65}
66
67
68const std::string& HTTPSTestServer::lastRequest() const
69{
70 return _lastRequest;
71}
72
73
74void HTTPSTestServer::run()
75{
76 _ready.set();
77 Poco::Timespan span(250000);
78 while (!_stop)
79 {
80 if (_socket.poll(span, Socket::SELECT_READ))
81 {
82 StreamSocket ss = _socket.acceptConnection();
83 try
84 {
85 _lastRequest.clear();
86 char buffer[256];
87 int n = ss.receiveBytes(buffer, sizeof(buffer));
88 while (n > 0 && !_stop)
89 {
90 _lastRequest.append(buffer, n);
91 if (!requestComplete())
92 n = ss.receiveBytes(buffer, sizeof(buffer));
93 else
94 n = 0;
95 }
96 std::string response = handleRequest();
97 ss.sendBytes(response.data(), (int) response.size());
98 if(_lastRequest.find("/connection/abort")!=std::string::npos) {
99 SecureStreamSocketImpl* sss = dynamic_cast<SecureStreamSocketImpl*>(ss.impl());
100 if(sss!=NULL) sss->abort();
101 }
102 Poco::Thread::sleep(1000);
103 }
104 catch (Poco::Exception& exc)
105 {
106 std::cerr << "HTTPSTestServer: " << exc.displayText() << std::endl;
107 }
108 }
109 }
110}
111
112
113bool HTTPSTestServer::requestComplete() const
114{
115 return ((_lastRequest.substr(0, 3) == "GET" || _lastRequest.substr(0, 4) == "HEAD") &&
116 (_lastRequest.find("\r\n\r\n") != std::string::npos)) ||
117 (_lastRequest.find("\r\n0\r\n") != std::string::npos);
118}
119
120
121std::string HTTPSTestServer::handleRequest() const
122{
123 std::string response;
124 response.reserve(16000);
125 if (_lastRequest.substr(0, 10) == "GET /small" ||
126 _lastRequest.substr(0, 11) == "HEAD /small")
127 {
128 std::string body(SMALL_BODY);
129 response.append("HTTP/1.0 200 OK\r\n");
130 response.append("Content-Type: text/plain\r\n");
131 response.append("Content-Length: ");
132 response.append(NumberFormatter::format((int) body.size()));
133 response.append("\r\n");
134 response.append("Connection: Close\r\n");
135 response.append("\r\n");
136 if (_lastRequest.substr(0, 3) == "GET")
137 response.append(body);
138 }
139 else if (_lastRequest.substr(0, 10) == "GET /large" ||
140 _lastRequest.substr(0, 11) == "HEAD /large" ||
141 _lastRequest.substr(0, 36) == "GET http://www.somehost.com:80/large")
142 {
143 std::string body(LARGE_BODY);
144 response.append("HTTP/1.0 200 OK\r\n");
145 response.append("Content-Type: text/plain\r\n");
146 response.append("Content-Length: ");
147 response.append(NumberFormatter::format((int) body.size()));
148 response.append("\r\n");
149 response.append("Connection: Close\r\n");
150 response.append("\r\n");
151 if (_lastRequest.substr(0, 3) == "GET")
152 response.append(body);
153 }
154 else if (_lastRequest.substr(0, 13) == "GET /nolength" ||
155 _lastRequest.substr(0, 14) == "HEAD /nolength")
156 {
157 std::string body(SMALL_BODY);
158 response.append("HTTP/1.0 200 OK\r\n");
159 response.append("Content-Type: text/plain\r\n");
160 response.append("Connection: Close\r\n");
161 response.append("\r\n");
162 if (_lastRequest.substr(0, 3) == "GET")
163 response.append(body);
164 }
165 else if (_lastRequest.substr(0, 4) == "POST")
166 {
167 std::string::size_type pos = _lastRequest.find("\r\n\r\n");
168 pos += 4;
169 std::string body = _lastRequest.substr(pos);
170 response.append("HTTP/1.0 200 OK\r\n");
171 response.append("Content-Type: text/plain\r\n");
172 if (_lastRequest.find("Content-Length") != std::string::npos)
173 {
174 response.append("Content-Length: ");
175 response.append(NumberFormatter::format((int) body.size()));
176 response.append("\r\n");
177 }
178 else if (_lastRequest.find("chunked") != std::string::npos)
179 {
180 response.append("Transfer-Encoding: chunked\r\n");
181 }
182 if (_lastRequest.substr(0,15) == "POST /keepAlive")
183 response.append("Connection: keep-alive\r\n");
184 else
185 response.append("Connection: Close\r\n");
186 response.append("\r\n");
187 response.append(body);
188 }
189 else if (_lastRequest.substr(0, 15) == "HEAD /keepAlive")
190 {
191 std::string body(SMALL_BODY);
192 response.append("HTTP/1.1 200 OK\r\n");
193 response.append("Connection: keep-alive\r\n");
194 response.append("Content-Type: text/plain\r\n");
195 response.append("Content-Length: ");
196 response.append(NumberFormatter::format((int) body.size()));
197 response.append("\r\n\r\n");
198 response.append("HTTP/1.1 200 OK\r\n");
199 response.append("Connection: Keep-Alive\r\n");
200 response.append("Content-Type: text/plain\r\n");
201 response.append("Content-Length: ");
202 response.append(NumberFormatter::format((int) body.size()));
203 response.append("\r\n\r\n");
204 response.append(body);
205 body = LARGE_BODY;
206 response.append("HTTP/1.1 200 OK\r\n");
207 response.append("Connection: keep-alive\r\n");
208 response.append("Content-Type: text/plain\r\n");
209 response.append("Transfer-Encoding: chunked\r\n\r\n");
210 response.append(NumberFormatter::formatHex((unsigned) body.length()));
211 response.append("\r\n");
212 response.append(body);
213 response.append("\r\n0\r\n\r\n");
214 response.append("HTTP/1.1 200 OK\r\n");
215 response.append("Connection: close\r\n");
216 response.append("Content-Type: text/plain\r\n");
217 response.append("Content-Length: ");
218 response.append(NumberFormatter::format((int) body.size()));
219 response.append("\r\n\r\n");
220 }
221 else if (_lastRequest.substr(0, 13) == "GET /redirect")
222 {
223 response.append("HTTP/1.0 302 Found\r\n");
224 response.append("Location: /large\r\n");
225 response.append("\r\n");
226 }
227 else if (_lastRequest.substr(0, 13) == "GET /notfound")
228 {
229 response.append("HTTP/1.0 404 Not Found\r\n");
230 response.append("\r\n");
231 }
232 else if (_lastRequest.substr(0, 5) == "GET /" ||
233 _lastRequest.substr(0, 6) == "HEAD /")
234 {
235 std::string body(SMALL_BODY);
236 response.append("HTTP/1.0 200 OK\r\n");
237 response.append("Content-Type: text/plain\r\n");
238 response.append("Content-Length: ");
239 response.append(NumberFormatter::format((int) body.size()));
240 response.append("\r\n");
241 response.append("Connection: Close\r\n");
242 response.append("\r\n");
243 if (_lastRequest.substr(0, 3) == "GET")
244 response.append(body);
245 }
246 return response;
247}
248