Skip to content

Commit 5565d57

Browse files
author
Ivan Kostoski
committed
Independent workers using FreeRTOS tasks
1 parent 7cb01b0 commit 5565d57

14 files changed

+631
-131
lines changed

src/HTTPConnection.cpp

+69-29
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,28 @@ HTTPConnection::~HTTPConnection() {
2626
}
2727

2828
/**
29-
* Initializes the connection from a server socket.
29+
* Initializes the connection
30+
*/
31+
void HTTPConnection::initialize(int serverSocketID, HTTPHeaders *defaultHeaders) {
32+
_defaultHeaders = defaultHeaders;
33+
_serverSocket = serverSocketID;
34+
}
35+
36+
/**
37+
* Accepts the connection from a server socket.
3038
*
3139
* The call WILL BLOCK if accept(serverSocketID) blocks. So use select() to check for that in advance.
3240
*/
33-
int HTTPConnection::initialize(int serverSocketID, HTTPHeaders *defaultHeaders) {
41+
int HTTPConnection::initialAccept() {
3442
if (_connectionState == STATE_UNDEFINED) {
35-
_defaultHeaders = defaultHeaders;
36-
_socket = accept(serverSocketID, (struct sockaddr * )&_sockAddr, &_addrLen);
43+
_socket = accept(_serverSocket, (struct sockaddr * )&_sockAddr, &_addrLen);
3744

38-
// Build up SSL Connection context if the socket has been created successfully
3945
if (_socket >= 0) {
4046
HTTPS_LOGI("New connection. Socket FID=%d", _socket);
41-
_connectionState = STATE_INITIAL;
47+
_connectionState = STATE_ACCEPTED;
4248
_httpHeaders = new HTTPHeaders();
4349
refreshTimeout();
4450
return _socket;
45-
4651
}
4752

4853
HTTPS_LOGE("Could not accept() new connection");
@@ -58,6 +63,23 @@ int HTTPConnection::initialize(int serverSocketID, HTTPHeaders *defaultHeaders)
5863
return -1;
5964
}
6065

66+
int HTTPConnection::fullyAccept() {
67+
if (_connectionState == STATE_UNDEFINED) {
68+
initialAccept();
69+
}
70+
if (_connectionState == STATE_ACCEPTED) {
71+
_connectionState = STATE_INITIAL;
72+
return _socket;
73+
}
74+
return -1;
75+
}
76+
77+
/**
78+
* Get connection socket
79+
*/
80+
int HTTPConnection::getSocket() {
81+
return _socket;
82+
}
6183

6284
/**
6385
* True if the connection is timed out.
@@ -68,6 +90,17 @@ bool HTTPConnection::isTimeoutExceeded() {
6890
return _lastTransmissionTS + HTTPS_CONNECTION_TIMEOUT < millis();
6991
}
7092

93+
/**
94+
* Return remaining milliseconds until timeout
95+
*
96+
* (Should return 0 or negative value if connection is timed-out or closed)
97+
*/
98+
long int HTTPConnection::remainingMsUntilTimeout() {
99+
if (isClosed()) return -1;
100+
unsigned long remain = _lastTransmissionTS + HTTPS_CONNECTION_TIMEOUT - millis();
101+
return (long int)remain;
102+
}
103+
71104
/**
72105
* Resets the timeout to allow again the full HTTPS_CONNECTION_TIMEOUT milliseconds
73106
*/
@@ -89,6 +122,14 @@ bool HTTPConnection::isError() {
89122
return (_connectionState == STATE_ERROR);
90123
}
91124

125+
bool HTTPConnection::isIdle() {
126+
if (_connectionState == STATE_INITIAL) {
127+
uint32_t delta = millis() - _lastTransmissionTS;
128+
return (int32_t)delta > HTTPS_CONNECTION_IDLE_TIMEOUT;
129+
}
130+
return false;
131+
}
132+
92133
bool HTTPConnection::isSecure() {
93134
return false;
94135
}
@@ -129,6 +170,7 @@ void HTTPConnection::closeConnection() {
129170
if (_wsHandler != nullptr) {
130171
HTTPS_LOGD("Free WS Handler");
131172
delete _wsHandler;
173+
_wsHandler = NULL;
132174
}
133175
}
134176

@@ -258,20 +300,19 @@ size_t HTTPConnection::readBytesToBuffer(byte* buffer, size_t length) {
258300
return recv(_socket, buffer, length, MSG_WAITALL | MSG_DONTWAIT);
259301
}
260302

261-
void HTTPConnection::serverError() {
303+
void HTTPConnection::raiseError(uint16_t code, std::string reason) {
262304
_connectionState = STATE_ERROR;
263-
264-
char staticResponse[] = "HTTP/1.1 500 Internal Server Error\r\nServer: esp32https\r\nConnection:close\r\nContent-Type: text/html\r\nContent-Length:34\r\n\r\n<h1>500 Internal Server Error</h1>";
265-
writeBuffer((byte*)staticResponse, strlen(staticResponse));
266-
closeConnection();
267-
}
268-
269-
270-
void HTTPConnection::clientError() {
271-
_connectionState = STATE_ERROR;
272-
273-
char staticResponse[] = "HTTP/1.1 400 Bad Request\r\nServer: esp32https\r\nConnection:close\r\nContent-Type: text/html\r\nContent-Length:26\r\n\r\n<h1>400 Bad Request</h1>";
274-
writeBuffer((byte*)staticResponse, strlen(staticResponse));
305+
std::string sCode = intToString(code);
306+
307+
char headers[] = "\r\nConnection: close\r\nContent-Type: text/plain;charset=utf8\r\n\r\n";
308+
writeBuffer((byte*)"HTTP/1.1 ", 9);
309+
writeBuffer((byte*)sCode.c_str(), sCode.length());
310+
writeBuffer((byte*)" ", 1);
311+
writeBuffer((byte*)(reason.c_str()), reason.length());
312+
writeBuffer((byte*)headers, strlen(headers));
313+
writeBuffer((byte*)sCode.c_str(), sCode.length());
314+
writeBuffer((byte*)" ", 1);
315+
writeBuffer((byte*)(reason.c_str()), reason.length());
275316
closeConnection();
276317
}
277318

@@ -289,7 +330,7 @@ void HTTPConnection::readLine(int lengthLimit) {
289330
} else {
290331
// Line has not been terminated by \r\n
291332
HTTPS_LOGW("Line without \\r\\n (got only \\r). FID=%d", _socket);
292-
clientError();
333+
raiseError(400, "Bad Request");
293334
return;
294335
}
295336
}
@@ -301,7 +342,7 @@ void HTTPConnection::readLine(int lengthLimit) {
301342
// Check that the max request string size is not exceeded
302343
if (_parserLine.text.length() > lengthLimit) {
303344
HTTPS_LOGW("Header length exceeded. FID=%d", _socket);
304-
serverError();
345+
raiseError(431, "Request Header Fields Too Large");
305346
return;
306347
}
307348
}
@@ -319,7 +360,7 @@ void HTTPConnection::signalClientClose() {
319360
*/
320361
void HTTPConnection::signalRequestError() {
321362
// TODO: Check that no response has been transmitted yet
322-
serverError();
363+
raiseError(400, "Bad Request");
323364
}
324365

325366
/**
@@ -365,7 +406,7 @@ bool HTTPConnection::loop() {
365406
size_t spaceAfterMethodIdx = _parserLine.text.find(' ');
366407
if (spaceAfterMethodIdx == std::string::npos) {
367408
HTTPS_LOGW("Missing space after method");
368-
clientError();
409+
raiseError(400, "Bad Request");
369410
break;
370411
}
371412
_httpMethod = _parserLine.text.substr(0, spaceAfterMethodIdx);
@@ -374,14 +415,14 @@ bool HTTPConnection::loop() {
374415
size_t spaceAfterResourceIdx = _parserLine.text.find(' ', spaceAfterMethodIdx + 1);
375416
if (spaceAfterResourceIdx == std::string::npos) {
376417
HTTPS_LOGW("Missing space after resource");
377-
clientError();
418+
raiseError(400, "Bad Request");
378419
break;
379420
}
380421
_httpResource = _parserLine.text.substr(spaceAfterMethodIdx + 1, spaceAfterResourceIdx - _httpMethod.length() - 1);
381422

382423
_parserLine.parsingFinished = false;
383424
_parserLine.text = "";
384-
HTTPS_LOGI("Request: %s %s (FID=%d)", _httpMethod.c_str(), _httpResource.c_str(), _socket);
425+
HTTPS_LOGI("Request: %s %s (FID=%d, T=%p)", _httpMethod.c_str(), _httpResource.c_str(), _socket, xTaskGetCurrentTaskHandle());
385426
_connectionState = STATE_REQUEST_FINISHED;
386427
}
387428

@@ -411,7 +452,7 @@ bool HTTPConnection::loop() {
411452
HTTPS_LOGD("Header: %s = %s (FID=%d)", _parserLine.text.substr(0, idxColon).c_str(), _parserLine.text.substr(idxColon+2).c_str(), _socket);
412453
} else {
413454
HTTPS_LOGW("Malformed request header: %s", _parserLine.text.c_str());
414-
clientError();
455+
raiseError(400, "Bad Request");
415456
break;
416457
}
417458
}
@@ -558,7 +599,7 @@ bool HTTPConnection::loop() {
558599
} else {
559600
// No match (no default route configured, nothing does match)
560601
HTTPS_LOGW("Could not find a matching resource");
561-
serverError();
602+
raiseError(404, "Not Found");
562603
}
563604

564605
}
@@ -594,7 +635,6 @@ bool HTTPConnection::loop() {
594635
return (!isClosed() && ((_bufferProcessed < _bufferUnusedIdx) || canReadData()));
595636
}
596637

597-
598638
bool HTTPConnection::checkWebsocket() {
599639
if(_httpMethod == "GET" &&
600640
!_httpHeaders->getValue("Host").empty() &&

src/HTTPConnection.hpp

+14-6
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,18 @@ class HTTPConnection : private ConnectionContext {
3939
HTTPConnection(ResourceResolver * resResolver);
4040
virtual ~HTTPConnection();
4141

42-
virtual int initialize(int serverSocketID, HTTPHeaders *defaultHeaders);
42+
virtual void initialize(int serverSocketID, HTTPHeaders *defaultHeaders);
43+
virtual int initialAccept();
44+
virtual int fullyAccept();
4345
virtual void closeConnection();
4446
virtual bool isSecure();
4547

4648
bool loop();
4749
bool isClosed();
4850
bool isError();
51+
bool isIdle();
52+
long int remainingMsUntilTimeout();
53+
int getSocket();
4954

5055
protected:
5156
friend class HTTPRequest;
@@ -57,6 +62,9 @@ class HTTPConnection : private ConnectionContext {
5762
virtual bool canReadData();
5863
virtual size_t pendingByteCount();
5964

65+
// Connection socket (LWIP)
66+
int _socket;
67+
6068
// Timestamp of the last transmission action
6169
unsigned long _lastTransmissionTS;
6270

@@ -82,6 +90,8 @@ class HTTPConnection : private ConnectionContext {
8290

8391
// The connection has not been established yet
8492
STATE_UNDEFINED,
93+
// The connection fully established (i.e. TLS)
94+
STATE_ACCEPTED,
8595
// The connection has just been created
8696
STATE_INITIAL,
8797
// The request line has been parsed
@@ -107,8 +117,7 @@ class HTTPConnection : private ConnectionContext {
107117
} _clientState;
108118

109119
private:
110-
void serverError();
111-
void clientError();
120+
void raiseError(uint16_t code, std::string reason);
112121
void readLine(int lengthLimit);
113122

114123
bool isTimeoutExceeded();
@@ -134,8 +143,8 @@ class HTTPConnection : private ConnectionContext {
134143
// Socket address, length etc for the connection
135144
struct sockaddr _sockAddr;
136145
socklen_t _addrLen;
137-
int _socket;
138-
146+
int _serverSocket;
147+
139148
// Resource resolver used to resolve resources
140149
ResourceResolver * _resResolver;
141150

@@ -158,7 +167,6 @@ class HTTPConnection : private ConnectionContext {
158167

159168
//Websocket connection
160169
WebsocketHandler * _wsHandler;
161-
162170
};
163171

164172
void handleWebsocketHandshake(HTTPRequest * req, HTTPResponse * res);

src/HTTPSConnection.cpp

+24-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace httpsserver {
55

66
HTTPSConnection::HTTPSConnection(ResourceResolver * resResolver):
77
HTTPConnection(resResolver) {
8+
_sslCtx = NULL;
89
_ssl = NULL;
910
_TLSTickets = NULL;
1011
}
@@ -19,19 +20,33 @@ bool HTTPSConnection::isSecure() {
1920
}
2021

2122
/**
22-
* Initializes the connection from a server socket.
23+
* Initializes the connection with SSL context
24+
*/
25+
void HTTPSConnection::initialize(int serverSocketID, HTTPHeaders *defaultHeaders, SSL_CTX * sslCtx, TLSTickets * tickets) {
26+
HTTPConnection::initialize(serverSocketID, defaultHeaders);
27+
_sslCtx = sslCtx;
28+
_TLSTickets = tickets;
29+
}
30+
31+
/**
32+
* Accepts the connection from a server socket.
2333
*
2434
* The call WILL BLOCK if accept(serverSocketID) blocks. So use select() to check for that in advance.
2535
*/
26-
int HTTPSConnection::initialize(int serverSocketID, SSL_CTX * sslCtx, HTTPHeaders *defaultHeaders) {
36+
int HTTPSConnection::fullyAccept() {
37+
2738
if (_connectionState == STATE_UNDEFINED) {
28-
// Let the base class connect the plain tcp socket
29-
int resSocket = HTTPConnection::initialize(serverSocketID, defaultHeaders);
39+
initialAccept();
40+
}
41+
42+
if (_connectionState == STATE_ACCEPTED) {
43+
int resSocket = _socket;
3044

3145
// Build up SSL Connection context if the socket has been created successfully
3246
if (resSocket >= 0) {
47+
HTTPS_LOGV("Before SSL accept free:%u, lfb:%u\n", heap_caps_get_free_size(MALLOC_CAP_8BIT), heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
48+
_ssl = SSL_new(_sslCtx);
3349

34-
_ssl = SSL_new(sslCtx);
3550
if (_TLSTickets != NULL) _TLSTickets->enable(_ssl);
3651

3752
if (_ssl) {
@@ -42,9 +57,13 @@ int HTTPSConnection::initialize(int serverSocketID, SSL_CTX * sslCtx, HTTPHeader
4257
// Perform the handshake
4358
success = SSL_accept(_ssl);
4459
if (success) {
60+
HTTPS_LOGD("SSL accepted (FID=%d)", resSocket);
61+
HTTPS_LOGV("After SSL accept free:%u, lfb:%u", heap_caps_get_free_size(MALLOC_CAP_8BIT), heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
62+
_connectionState = STATE_INITIAL;
4563
return resSocket;
4664
} else {
4765
HTTPS_LOGE("SSL_accept failed. Aborting handshake. FID=%d", resSocket);
66+
HTTPS_LOGV("After fail free:%u, lfb:%u", heap_caps_get_free_size(MALLOC_CAP_8BIT), heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
4867
}
4968
} else {
5069
HTTPS_LOGE("SSL_set_fd failed. Aborting handshake. FID=%d", resSocket);

src/HTTPSConnection.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class HTTPSConnection : public HTTPConnection {
3535
HTTPSConnection(ResourceResolver * resResolver);
3636
virtual ~HTTPSConnection();
3737

38-
virtual int initialize(int serverSocketID, SSL_CTX * sslCtx, HTTPHeaders *defaultHeaders);
38+
virtual void initialize(int serverSocketID, HTTPHeaders *defaultHeaders, SSL_CTX * sslCtx, TLSTickets * tickets);
39+
virtual int fullyAccept() override;
3940
virtual void closeConnection();
4041
virtual bool isSecure();
4142

@@ -50,6 +51,7 @@ class HTTPSConnection : public HTTPConnection {
5051

5152
private:
5253
// SSL context for this connection
54+
SSL_CTX * _sslCtx;
5355
SSL * _ssl;
5456
TLSTickets * _TLSTickets;
5557

src/HTTPSServer.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ void HTTPSServer::teardownSocket() {
5959
_sslctx = NULL;
6060
}
6161

62-
int HTTPSServer::createConnection(int idx) {
62+
HTTPSConnection * HTTPSServer::createConnection() {
6363
HTTPSConnection * newConnection = new HTTPSConnection(this);
64-
_connections[idx] = newConnection;
65-
return newConnection->initialize(_socket, _sslctx, &_defaultHeaders);
64+
newConnection->initialize(_socket, &_defaultHeaders, _sslctx, _TLSTickets);
65+
return newConnection;
6666
}
6767

6868
/**

src/HTTPSServer.hpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class HTTPSServer : public HTTPServer {
3636
// RFC 5077 TLS session tickets
3737
void enableTLSTickets(uint32_t liftimeSeconds = 86400, bool useHardwareRNG = false);
3838

39+
virtual HTTPSConnection * createConnection() override;
40+
3941
private:
4042
// Static configuration. Port, keys, etc. ====================
4143
// Certificate that should be used (includes private key)
@@ -51,9 +53,6 @@ class HTTPSServer : public HTTPServer {
5153
virtual void teardownSocket();
5254
uint8_t setupSSLCTX();
5355
uint8_t setupCert();
54-
55-
// Helper functions
56-
virtual int createConnection(int idx);
5756
};
5857

5958
} /* namespace httpsserver */

0 commit comments

Comments
 (0)