11#include " HTTPConnection.hpp"
2+ #include " Websocket.hpp"
3+ #include < hwcrypto/sha.h>
24
35namespace httpsserver {
46
@@ -18,6 +20,7 @@ HTTPConnection::HTTPConnection(ResourceResolver * resResolver):
1820 _isKeepAlive = false ;
1921 _lastTransmissionTS = millis ();
2022 _shutdownTS = 0 ;
23+ _websocket = nullptr ;
2124}
2225
2326HTTPConnection::~HTTPConnection () {
@@ -121,6 +124,7 @@ void HTTPConnection::closeConnection() {
121124 }
122125
123126 if (_httpHeaders != NULL ) {
127+ HTTPS_DLOG (" [ ] Free headers" );
124128 delete _httpHeaders;
125129 _httpHeaders = NULL ;
126130 }
@@ -327,6 +331,10 @@ size_t HTTPConnection::getCacheSize() {
327331 return (_isKeepAlive ? HTTPS_KEEPALIVE_CACHESIZE : 0 );
328332}
329333
334+ void HTTPConnection::setWebsocketHandler (WebsocketHandler *wsHandler) {
335+ _wsHandler = wsHandler;
336+ }
337+
330338void HTTPConnection::loop () {
331339 // First, update the buffer
332340 // newByteCount will contain the number of new bytes that have to be processed
@@ -397,6 +405,7 @@ void HTTPConnection::loop() {
397405 _parserLine.text .substr (0 , idxColon),
398406 _parserLine.text .substr (idxColon+2 )
399407 ));
408+ HTTPS_DLOG ((" [ ] Header: " + _parserLine.text .substr (0 , idxColon) + " :" + _parserLine.text .substr (idxColon+2 )).c_str ());
400409 } else {
401410 HTTPS_DLOG (" Malformed header line detected. Client error." );
402411 HTTPS_DLOG (_parserLine.text .c_str ());
@@ -427,6 +436,36 @@ void HTTPConnection::loop() {
427436 _isKeepAlive = false ;
428437 }
429438
439+ // do we have a websocket connection?
440+ if (checkWebsocket ()) {
441+ // Create response
442+ HTTPResponse res = HTTPResponse (this );
443+ // Add default headers to the response
444+ auto allDefaultHeaders = _defaultHeaders->getAll ();
445+ for (std::vector<HTTPHeader*>::iterator header = allDefaultHeaders->begin (); header != allDefaultHeaders->end (); ++header) {
446+ res.setHeader ((*header)->_name , (*header)->_value );
447+ }
448+ // Set the response status
449+ res.setStatusCode (101 );
450+ res.setStatusText (" Switching Protocols" );
451+ res.setHeader (" Upgrade" , " websocket" );
452+ res.setHeader (" Connection" , " Upgrade" );
453+ res.setHeader (" Sec-WebSocket-Accept" , websocketKeyResponseHash (_httpHeaders->getValue (" Sec-WebSocket-Key" )));
454+ res.print (" " );
455+
456+ // Callback for the actual resource
457+ HTTPSCallbackFunction * resourceCallback = resolvedResource.getMatchingNode ()->_callback ;
458+ // persistent request for websocket. To be destroyed when connection closes.
459+ HTTPRequest *req = new HTTPRequest (this , _httpHeaders, resolvedResource.getParams (), _httpResource, _httpMethod, " " );
460+ // bind function call to the actual resource
461+ std::function<void ()> next = std::function<void ()>(std::bind (resourceCallback, req, nullptr ));
462+ _websocket = new Websocket (this ); // make websocket with this connection
463+ next (); // call callback
464+ delete req;
465+ _connectionState = STATE_WEBSOCKET;
466+ break ;
467+ }
468+
430469 // Create request context
431470 HTTPRequest req = HTTPRequest (this , _httpHeaders, resolvedResource.getParams (), _httpResource, _httpMethod, resolvedResource.getMatchingNode ()->_tag );
432471 HTTPResponse res = HTTPResponse (this );
@@ -507,12 +546,54 @@ void HTTPConnection::loop() {
507546 closeConnection ();
508547 break ;
509548 case STATE_WEBSOCKET: // Do handling of the websocket
510-
549+ refreshTimeout (); // don't timeout websocket connection
550+ if (pendingBufferSize () > 0 ) {
551+ HTTPS_DLOG (" [ ] websocket handler" );
552+ if (_websocket->read () < 0 ) {
553+ _websocket->close ();
554+ delete _websocket;
555+ _httpHeaders->clearAll ();
556+ _connectionState = STATE_CLOSING;
557+ }
558+ }
559+ // readBuffer();
511560 break ;
512561 default :;
513562 }
514563 }
515564
516565}
517566
567+
568+ bool HTTPConnection::checkWebsocket () {
569+ // check criteria according to RFC6455
570+ // HTTPS_DLOG(("[ ] Method:" + _httpMethod).c_str());
571+ // HTTPS_DLOG(("[ ] Header Host:" + _httpHeaders->getValue("Host")).c_str());
572+ // HTTPS_DLOG(("[ ] Header Upgrade:" + _httpHeaders->getValue("Upgrade")).c_str());
573+ // HTTPS_DLOG(("[ ] Header Connection:" + _httpHeaders->getValue("Connection")).c_str());
574+ // HTTPS_DLOG(("[ ] Header Sec-WebSocket-Key:" + _httpHeaders->getValue("Sec-WebSocket-Key")).c_str());
575+ // HTTPS_DLOG(("[ ] Header Sec-WebSocket-Version:" + _httpHeaders->getValue("Sec-WebSocket-Version")).c_str());
576+ if (_httpMethod == " GET" &&
577+ !_httpHeaders->getValue (" Host" ).empty () &&
578+ _httpHeaders->getValue (" Upgrade" ) == " websocket" &&
579+ _httpHeaders->getValue (" Connection" ).find (" Upgrade" ) != std::string::npos &&
580+ !_httpHeaders->getValue (" Sec-WebSocket-Key" ).empty () &&
581+ _httpHeaders->getValue (" Sec-WebSocket-Version" ) == " 13" ) {
582+
583+ HTTPS_DLOG (" [-->] Websocket detected" );
584+ return true ;
585+ } else
586+ return false ;
587+ }
588+
589+ std::string HTTPConnection::websocketKeyResponseHash (std::string key) {
590+ std::string newKey = key + " 258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ;
591+ uint8_t shaData[20 ];
592+ esp_sha (SHA1, (uint8_t *)newKey.data (), newKey.length (), shaData);
593+ // GeneralUtils::hexDump(shaData, 20);
594+ std::string retStr;
595+ base64Encode (std::string ((char *)shaData, sizeof (shaData)), &retStr);
596+ return retStr;
597+ } // WebsocketKeyResponseHash
598+
518599} /* namespace httpsserver */
0 commit comments