mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	The slot in the websocket client will now run through until there are no more data in the buffer
Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com>
This commit is contained in:
		| @@ -298,7 +298,7 @@ $(document).ready(function() { | ||||
|  | ||||
| 	createCP('cp2', cpcolor, function(rgbT,hex){ | ||||
| 		rgb = rgbT; | ||||
| 		sendColor() | ||||
| 		sendColor(); | ||||
| 		setStorage('rmcpcolor', hex); | ||||
| 	}); | ||||
|  | ||||
|   | ||||
| @@ -180,8 +180,6 @@ void LinearColorSmoothing::componentStateChange(const hyperion::Components compo | ||||
|  | ||||
| void LinearColorSmoothing::setEnable(bool enable) | ||||
| { | ||||
| 	LedDevice::setEnable(enable); | ||||
|  | ||||
| 	if (!enable) | ||||
| 	{ | ||||
| 		_timer->stop(); | ||||
|   | ||||
| @@ -27,93 +27,131 @@ QtHttpClientWrapper::QtHttpClientWrapper (QTcpSocket * sock, const bool& localCo | ||||
| 	, m_websocketClient(nullptr) | ||||
| 	, m_webJsonRpc     (nullptr) | ||||
| { | ||||
|     connect (m_sockClient, &QTcpSocket::readyRead, this, &QtHttpClientWrapper::onClientDataReceived); | ||||
| 	connect (m_sockClient, &QTcpSocket::readyRead, this, &QtHttpClientWrapper::onClientDataReceived); | ||||
| } | ||||
|  | ||||
| QString QtHttpClientWrapper::getGuid (void) { | ||||
|     if (m_guid.isEmpty ()) { | ||||
|         m_guid = QString::fromLocal8Bit ( | ||||
|                      QCryptographicHash::hash ( | ||||
|                          QByteArray::number ((quint64) (this)), | ||||
|                          QCryptographicHash::Md5 | ||||
|                          ).toHex () | ||||
|                      ); | ||||
|     } | ||||
|     return m_guid; | ||||
| QString QtHttpClientWrapper::getGuid (void) | ||||
| { | ||||
| 	if (m_guid.isEmpty ()) | ||||
| 	{ | ||||
| 		m_guid = QString::fromLocal8Bit ( | ||||
| 			QCryptographicHash::hash ( | ||||
| 			QByteArray::number ((quint64) (this)), | ||||
| 			QCryptographicHash::Md5 | ||||
| 			).toHex () | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| 	return m_guid; | ||||
| } | ||||
|  | ||||
| void QtHttpClientWrapper::onClientDataReceived (void) { | ||||
|     if (m_sockClient != Q_NULLPTR) { | ||||
|         while (m_sockClient->bytesAvailable ()) { | ||||
|             QByteArray line = m_sockClient->readLine (); | ||||
|             switch (m_parsingStatus) { // handle parsing steps | ||||
|                 case AwaitingRequest: { // "command url version" × 1 | ||||
|                     QString str = QString::fromUtf8 (line).trimmed (); | ||||
|                     QStringList parts = str.split (SPACE, QString::SkipEmptyParts); | ||||
|                     if (parts.size () == 3) { | ||||
|                         QString command = parts.at (0); | ||||
|                         QString url     = parts.at (1); | ||||
|                         QString version = parts.at (2); | ||||
|                         if (version == QtHttpServer::HTTP_VERSION) { | ||||
|                             m_currentRequest = new QtHttpRequest (this, m_serverHandle); | ||||
|                             m_currentRequest->setClientInfo(m_sockClient->localAddress(), m_sockClient->peerAddress()); | ||||
|                             m_currentRequest->setUrl     (QUrl (url)); | ||||
|                             m_currentRequest->setCommand (command); | ||||
|                             m_parsingStatus = AwaitingHeaders; | ||||
|                         } | ||||
|                         else { | ||||
|                             m_parsingStatus = ParsingError; | ||||
|                             //qWarning () << "Error : unhandled HTTP version :" << version; | ||||
|                         } | ||||
|                     } | ||||
|                     else { | ||||
|                         m_parsingStatus = ParsingError; | ||||
|                         //qWarning () << "Error : incorrect HTTP command line :" << line; | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
|                 case AwaitingHeaders: { // "header: value" × N (until empty line) | ||||
|                     QByteArray raw = line.trimmed (); | ||||
|                     if (!raw.isEmpty ()) { // parse headers | ||||
|                         int pos = raw.indexOf (COLON); | ||||
|                         if (pos > 0) { | ||||
|                             QByteArray header = raw.left (pos).trimmed (); | ||||
|                             QByteArray value  = raw.mid  (pos +1).trimmed (); | ||||
|                             m_currentRequest->addHeader (header, value); | ||||
|                             if (header == QtHttpHeader::ContentLength) { | ||||
|                                 bool ok  = false; | ||||
|                                 const int len = value.toInt (&ok, 10); | ||||
|                                 if (ok) { | ||||
|                                     m_currentRequest->addHeader (QtHttpHeader::ContentLength, QByteArray::number (len)); | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         else { | ||||
|                             m_parsingStatus = ParsingError; | ||||
|                             qWarning () << "Error : incorrect HTTP headers line :" << line; | ||||
|                         } | ||||
|                     } | ||||
|                     else { // end of headers | ||||
|                         if (m_currentRequest->getHeader (QtHttpHeader::ContentLength).toInt () > 0) { | ||||
|                             m_parsingStatus = AwaitingContent; | ||||
|                         } | ||||
|                         else { | ||||
|                             m_parsingStatus = RequestParsed; | ||||
|                         } | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
|                 case AwaitingContent: { // raw data × N (until EOF ??) | ||||
|                     m_currentRequest->appendRawData (line); | ||||
|                     if (m_currentRequest->getRawDataSize () == m_currentRequest->getHeader (QtHttpHeader::ContentLength).toInt ()) { | ||||
|                         m_parsingStatus = RequestParsed; | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
|                 default: { break; } | ||||
|             } | ||||
|             switch (m_parsingStatus) { // handle parsing status end/error | ||||
|                 case RequestParsed: { // a valid request has ben fully parsed | ||||
| void QtHttpClientWrapper::onClientDataReceived (void) | ||||
| { | ||||
| 	if (m_sockClient != Q_NULLPTR) | ||||
| 	{ | ||||
| 		while (m_sockClient->bytesAvailable ()) | ||||
| 		{ | ||||
| 			QByteArray line = m_sockClient->readLine (); | ||||
|  | ||||
| 			switch (m_parsingStatus) // handle parsing steps | ||||
| 			{ | ||||
| 				case AwaitingRequest: // "command url version" × 1 | ||||
| 				{ | ||||
| 					QString str = QString::fromUtf8 (line).trimmed (); | ||||
| 					QStringList parts = str.split (SPACE, QString::SkipEmptyParts); | ||||
|  | ||||
| 					if (parts.size () == 3) | ||||
| 					{ | ||||
| 						QString command = parts.at (0); | ||||
| 						QString url     = parts.at (1); | ||||
| 						QString version = parts.at (2); | ||||
|  | ||||
| 						if (version == QtHttpServer::HTTP_VERSION) | ||||
| 						{ | ||||
| 							m_currentRequest = new QtHttpRequest (this, m_serverHandle); | ||||
| 							m_currentRequest->setClientInfo(m_sockClient->localAddress(), m_sockClient->peerAddress()); | ||||
| 							m_currentRequest->setUrl (QUrl (url)); | ||||
| 							m_currentRequest->setCommand (command); | ||||
| 							m_parsingStatus = AwaitingHeaders; | ||||
| 						} | ||||
| 						else | ||||
| 						{ | ||||
| 						m_parsingStatus = ParsingError; | ||||
| 						//qWarning () << "Error : unhandled HTTP version :" << version; | ||||
| 						} | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						m_parsingStatus = ParsingError; | ||||
| 						//qWarning () << "Error : incorrect HTTP command line :" << line; | ||||
| 					} | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
| 				case AwaitingHeaders: // "header: value" × N (until empty line) | ||||
| 				{ | ||||
| 					QByteArray raw = line.trimmed (); | ||||
|  | ||||
| 					if (!raw.isEmpty ()) // parse headers | ||||
| 					{ | ||||
| 						int pos = raw.indexOf (COLON); | ||||
|  | ||||
| 						if (pos > 0) | ||||
| 						{ | ||||
| 							QByteArray header = raw.left (pos).trimmed (); | ||||
| 							QByteArray value  = raw.mid  (pos +1).trimmed (); | ||||
| 							m_currentRequest->addHeader (header, value); | ||||
| 							if (header == QtHttpHeader::ContentLength) | ||||
| 							{ | ||||
| 								bool ok  = false; | ||||
| 								const int len = value.toInt (&ok, 10); | ||||
| 								if (ok) | ||||
| 								{ | ||||
| 									m_currentRequest->addHeader (QtHttpHeader::ContentLength, QByteArray::number (len)); | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 						else | ||||
| 						{ | ||||
| 							m_parsingStatus = ParsingError; | ||||
| 							qWarning () << "Error : incorrect HTTP headers line :" << line; | ||||
| 						} | ||||
| 					} | ||||
| 					else // end of headers | ||||
| 					{ | ||||
| 						if (m_currentRequest->getHeader (QtHttpHeader::ContentLength).toInt () > 0) | ||||
| 						{ | ||||
| 							m_parsingStatus = AwaitingContent; | ||||
| 						} | ||||
| 						else | ||||
| 						{ | ||||
| 							m_parsingStatus = RequestParsed; | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
| 				case AwaitingContent: // raw data × N (until EOF ??) | ||||
| 				{ | ||||
| 					m_currentRequest->appendRawData (line); | ||||
|  | ||||
| 					if (m_currentRequest->getRawDataSize () == m_currentRequest->getHeader (QtHttpHeader::ContentLength).toInt ()) | ||||
| 					{ | ||||
| 						m_parsingStatus = RequestParsed; | ||||
| 					} | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
| 				default: | ||||
| 				{ | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			switch (m_parsingStatus) // handle parsing status end/error | ||||
| 			{ | ||||
| 				case RequestParsed: // a valid request has ben fully parsed | ||||
| 				{ | ||||
| 					// Catch websocket header "Upgrade" | ||||
| 					if(m_currentRequest->getHeader(QtHttpHeader::Upgrade) == "websocket") | ||||
| 					{ | ||||
| @@ -121,146 +159,184 @@ void QtHttpClientWrapper::onClientDataReceived (void) { | ||||
| 						{ | ||||
| 							// disconnect this slot from socket for further requests | ||||
| 							disconnect(m_sockClient, &QTcpSocket::readyRead, this, &QtHttpClientWrapper::onClientDataReceived); | ||||
| 							// disabling packet bunching | ||||
| 							m_sockClient->setSocketOption(QAbstractSocket::LowDelayOption, 1); | ||||
| 							m_sockClient->setSocketOption(QAbstractSocket::KeepAliveOption, 1); | ||||
| 							m_websocketClient = new WebSocketClient(m_currentRequest, m_sockClient, m_localConnection, this); | ||||
| 						} | ||||
|  | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					// add  post data to request and catch /jsonrpc subroute url | ||||
|                     if ( m_currentRequest->getCommand() == "POST") | ||||
|                     { | ||||
|                         QtHttpPostData  postData; | ||||
|                         QByteArray data = m_currentRequest->getRawData(); | ||||
|                         QList<QByteArray> parts = data.split('&'); | ||||
|                         for (int i = 0; i < parts.size(); ++i) | ||||
|                         { | ||||
|                             QList<QByteArray> keyValue = parts.at(i).split('='); | ||||
|                             QByteArray value; | ||||
|                             if (keyValue.size()>1) | ||||
|                             { | ||||
|                                 value = QByteArray::fromPercentEncoding(keyValue.at(1)); | ||||
|                             } | ||||
|                             postData.insert(QString::fromUtf8(keyValue.at(0)),value); | ||||
|                         } | ||||
|                         m_currentRequest->setPostData(postData); | ||||
| 					if ( m_currentRequest->getCommand() == "POST") | ||||
| 					{ | ||||
| 						QtHttpPostData  postData; | ||||
| 						QByteArray data = m_currentRequest->getRawData(); | ||||
| 						QList<QByteArray> parts = data.split('&'); | ||||
|  | ||||
| 						for (int i = 0; i < parts.size(); ++i) | ||||
| 						{ | ||||
| 							QList<QByteArray> keyValue = parts.at(i).split('='); | ||||
| 							QByteArray value; | ||||
|  | ||||
| 							if (keyValue.size()>1) | ||||
| 							{ | ||||
| 								value = QByteArray::fromPercentEncoding(keyValue.at(1)); | ||||
| 							} | ||||
|  | ||||
| 							postData.insert(QString::fromUtf8(keyValue.at(0)),value); | ||||
| 						} | ||||
|  | ||||
| 						m_currentRequest->setPostData(postData); | ||||
|  | ||||
| 						// catch /jsonrpc in url, we need async callback, StaticFileServing is sync | ||||
| 						QString path = m_currentRequest->getUrl ().path (); | ||||
| 						QStringList uri_parts = path.split('/', QString::SkipEmptyParts); | ||||
|  | ||||
| 						if ( ! uri_parts.empty() && uri_parts.at(0) == "json-rpc" ) | ||||
| 						{ | ||||
| 							if(m_webJsonRpc == Q_NULLPTR) | ||||
| 							{ | ||||
| 								m_webJsonRpc = new WebJsonRpc(m_currentRequest, m_serverHandle, m_localConnection, this); | ||||
| 							} | ||||
|  | ||||
| 							m_webJsonRpc->handleMessage(m_currentRequest); | ||||
| 							break; | ||||
| 						} | ||||
|                     } | ||||
| 					} | ||||
|  | ||||
|                     QtHttpReply reply (m_serverHandle); | ||||
|                     connect (&reply, &QtHttpReply::requestSendHeaders, | ||||
|                              this, &QtHttpClientWrapper::onReplySendHeadersRequested); | ||||
|                     connect (&reply, &QtHttpReply::requestSendData, | ||||
|                              this, &QtHttpClientWrapper::onReplySendDataRequested); | ||||
|                     emit m_serverHandle->requestNeedsReply (m_currentRequest, &reply); // allow app to handle request | ||||
| 					QtHttpReply reply (m_serverHandle); | ||||
| 					connect (&reply, &QtHttpReply::requestSendHeaders, this, &QtHttpClientWrapper::onReplySendHeadersRequested); | ||||
| 					connect (&reply, &QtHttpReply::requestSendData, this, &QtHttpClientWrapper::onReplySendDataRequested); | ||||
| 					emit m_serverHandle->requestNeedsReply (m_currentRequest, &reply); // allow app to handle request | ||||
| 					m_parsingStatus = sendReplyToClient (&reply); | ||||
|                     break; | ||||
|                 } | ||||
|                 case ParsingError: { // there was an error durin one of parsing steps | ||||
|                     m_sockClient->readAll (); // clear remaining buffer to ignore content | ||||
|                     QtHttpReply reply (m_serverHandle); | ||||
|                     reply.setStatusCode (QtHttpReply::BadRequest); | ||||
|                     reply.appendRawData (QByteArrayLiteral ("<h1>Bad Request (HTTP parsing error) !</h1>")); | ||||
|                     reply.appendRawData (CRLF); | ||||
|                     m_parsingStatus = sendReplyToClient (&reply); | ||||
|                     break; | ||||
|                 } | ||||
|                 default: { break; } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
| 				case ParsingError: // there was an error durin one of parsing steps | ||||
| 				{ | ||||
| 					m_sockClient->readAll (); // clear remaining buffer to ignore content | ||||
| 					QtHttpReply reply (m_serverHandle); | ||||
| 					reply.setStatusCode (QtHttpReply::BadRequest); | ||||
| 					reply.appendRawData (QByteArrayLiteral ("<h1>Bad Request (HTTP parsing error) !</h1>")); | ||||
| 					reply.appendRawData (CRLF); | ||||
| 					m_parsingStatus = sendReplyToClient (&reply); | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
| 				default: | ||||
| 				{ | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void QtHttpClientWrapper::onReplySendHeadersRequested (void) { | ||||
|     QtHttpReply * reply = qobject_cast<QtHttpReply *> (sender ()); | ||||
|     if (reply != Q_NULLPTR) { | ||||
|         QByteArray data; | ||||
|         // HTTP Version + Status Code + Status Msg | ||||
|         data.append (QtHttpServer::HTTP_VERSION); | ||||
|         data.append (SPACE); | ||||
|         data.append (QByteArray::number (reply->getStatusCode ())); | ||||
|         data.append (SPACE); | ||||
|         data.append (QtHttpReply::getStatusTextForCode (reply->getStatusCode ())); | ||||
|         data.append (CRLF); | ||||
|         // Header name: header value | ||||
|         if (reply->useChunked ()) { | ||||
|             static const QByteArray & CHUNKED = QByteArrayLiteral ("chunked"); | ||||
|             reply->addHeader (QtHttpHeader::TransferEncoding, CHUNKED); | ||||
|         } | ||||
|         else { | ||||
|             reply->addHeader (QtHttpHeader::ContentLength, QByteArray::number (reply->getRawDataSize ())); | ||||
|         } | ||||
|         const QList<QByteArray> & headersList = reply->getHeadersList (); | ||||
|         foreach (const QByteArray & header, headersList) { | ||||
|             data.append (header); | ||||
|             data.append (COLON); | ||||
|             data.append (SPACE); | ||||
|             data.append (reply->getHeader (header)); | ||||
|             data.append (CRLF); | ||||
|         } | ||||
|         // empty line | ||||
|         data.append (CRLF); | ||||
|         m_sockClient->write (data); | ||||
|         m_sockClient->flush (); | ||||
|     } | ||||
| void QtHttpClientWrapper::onReplySendHeadersRequested (void) | ||||
| { | ||||
| 	QtHttpReply * reply = qobject_cast<QtHttpReply *> (sender ()); | ||||
|  | ||||
| 	if (reply != Q_NULLPTR) | ||||
| 	{ | ||||
| 		QByteArray data; | ||||
| 		// HTTP Version + Status Code + Status Msg | ||||
| 		data.append (QtHttpServer::HTTP_VERSION); | ||||
| 		data.append (SPACE); | ||||
| 		data.append (QByteArray::number (reply->getStatusCode ())); | ||||
| 		data.append (SPACE); | ||||
| 		data.append (QtHttpReply::getStatusTextForCode (reply->getStatusCode ())); | ||||
| 		data.append (CRLF); | ||||
|  | ||||
| 		if (reply->useChunked ()) // Header name: header value | ||||
| 		{ | ||||
| 			static const QByteArray & CHUNKED = QByteArrayLiteral ("chunked"); | ||||
| 			reply->addHeader (QtHttpHeader::TransferEncoding, CHUNKED); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			reply->addHeader (QtHttpHeader::ContentLength, QByteArray::number (reply->getRawDataSize ())); | ||||
| 		} | ||||
|  | ||||
| 		const QList<QByteArray> & headersList = reply->getHeadersList (); | ||||
|  | ||||
| 		foreach (const QByteArray & header, headersList) | ||||
| 		{ | ||||
| 			data.append (header); | ||||
| 			data.append (COLON); | ||||
| 			data.append (SPACE); | ||||
| 			data.append (reply->getHeader (header)); | ||||
| 			data.append (CRLF); | ||||
| 		} | ||||
|  | ||||
| 		// empty line | ||||
| 		data.append (CRLF); | ||||
| 		m_sockClient->write (data); | ||||
| 		m_sockClient->flush (); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void QtHttpClientWrapper::onReplySendDataRequested (void) { | ||||
|     QtHttpReply * reply = qobject_cast<QtHttpReply *> (sender ()); | ||||
|     if (reply != Q_NULLPTR) { | ||||
|         // content raw data | ||||
|         QByteArray data = reply->getRawData (); | ||||
|         if (reply->useChunked ()) { | ||||
|             data.prepend (QByteArray::number (data.size (), 16) % CRLF); | ||||
|             data.append (CRLF); | ||||
|             reply->resetRawData (); | ||||
|         } | ||||
|         // write to socket | ||||
|         m_sockClient->write (data); | ||||
|         m_sockClient->flush (); | ||||
|     } | ||||
| void QtHttpClientWrapper::onReplySendDataRequested (void) | ||||
| { | ||||
| 	QtHttpReply * reply = qobject_cast<QtHttpReply *> (sender ()); | ||||
| 	if (reply != Q_NULLPTR) | ||||
| 	{ | ||||
| 		// content raw data | ||||
| 		QByteArray data = reply->getRawData (); | ||||
|  | ||||
| 		if (reply->useChunked ()) | ||||
| 		{ | ||||
| 			data.prepend (QByteArray::number (data.size (), 16) % CRLF); | ||||
| 			data.append (CRLF); | ||||
| 			reply->resetRawData (); | ||||
| 		} | ||||
|  | ||||
| 		// write to socket | ||||
| 		m_sockClient->write (data); | ||||
| 		m_sockClient->flush (); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void QtHttpClientWrapper::sendToClientWithReply(QtHttpReply * reply) { | ||||
| 	connect (reply, &QtHttpReply::requestSendHeaders, | ||||
| 			 this, &QtHttpClientWrapper::onReplySendHeadersRequested); | ||||
| 	connect (reply, &QtHttpReply::requestSendData, | ||||
| 			 this, &QtHttpClientWrapper::onReplySendDataRequested); | ||||
| void QtHttpClientWrapper::sendToClientWithReply(QtHttpReply * reply) | ||||
| { | ||||
| 	connect (reply, &QtHttpReply::requestSendHeaders, this, &QtHttpClientWrapper::onReplySendHeadersRequested); | ||||
| 	connect (reply, &QtHttpReply::requestSendData, this, &QtHttpClientWrapper::onReplySendDataRequested); | ||||
| 	m_parsingStatus = sendReplyToClient (reply); | ||||
| } | ||||
|  | ||||
| QtHttpClientWrapper::ParsingStatus QtHttpClientWrapper::sendReplyToClient (QtHttpReply * reply) { | ||||
| 	if (reply != Q_NULLPTR) { | ||||
|         if (!reply->useChunked ()) { | ||||
|             //reply->appendRawData (CRLF); | ||||
|             // send all headers and all data in one shot | ||||
|             reply->requestSendHeaders (); | ||||
|             reply->requestSendData (); | ||||
|         } | ||||
|         else { | ||||
|             // last chunk | ||||
|             m_sockClient->write ("0" % CRLF % CRLF); | ||||
|             m_sockClient->flush (); | ||||
|         } | ||||
|         if (m_currentRequest != Q_NULLPTR) { | ||||
|             static const QByteArray & CLOSE = QByteArrayLiteral ("close"); | ||||
|             if (m_currentRequest->getHeader (QtHttpHeader::Connection).toLower () == CLOSE) { | ||||
|                 // must close connection after this request | ||||
|                 m_sockClient->close (); | ||||
|             } | ||||
|             m_currentRequest->deleteLater (); | ||||
|             m_currentRequest = Q_NULLPTR; | ||||
|         } | ||||
|     } | ||||
|     return AwaitingRequest; | ||||
| QtHttpClientWrapper::ParsingStatus QtHttpClientWrapper::sendReplyToClient (QtHttpReply * reply) | ||||
| { | ||||
| 	if (reply != Q_NULLPTR) | ||||
| 	{ | ||||
| 		if (!reply->useChunked ()) | ||||
| 		{ | ||||
| 			//reply->appendRawData (CRLF); | ||||
| 			// send all headers and all data in one shot | ||||
| 			reply->requestSendHeaders (); | ||||
| 			reply->requestSendData (); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			// last chunk | ||||
| 			m_sockClient->write ("0" % CRLF % CRLF); | ||||
| 			m_sockClient->flush (); | ||||
| 		} | ||||
|  | ||||
| 		if (m_currentRequest != Q_NULLPTR) | ||||
| 		{ | ||||
| 			static const QByteArray & CLOSE = QByteArrayLiteral ("close"); | ||||
|  | ||||
| 			if (m_currentRequest->getHeader (QtHttpHeader::Connection).toLower () == CLOSE) | ||||
| 			{ | ||||
| 				// must close connection after this request | ||||
| 				m_sockClient->close (); | ||||
| 			} | ||||
|  | ||||
| 			m_currentRequest->deleteLater (); | ||||
| 			m_currentRequest = Q_NULLPTR; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return AwaitingRequest; | ||||
| } | ||||
|   | ||||
| @@ -3,35 +3,36 @@ | ||||
|  | ||||
| class QByteArray; | ||||
|  | ||||
| class QtHttpHeader { | ||||
| class QtHttpHeader | ||||
| { | ||||
| public: | ||||
|     static const QByteArray & Server; | ||||
|     static const QByteArray & Date; | ||||
|     static const QByteArray & Host; | ||||
|     static const QByteArray & Accept; | ||||
|     static const QByteArray & ContentType; | ||||
|     static const QByteArray & ContentLength; | ||||
|     static const QByteArray & Connection; | ||||
|     static const QByteArray & Cookie; | ||||
|     static const QByteArray & UserAgent; | ||||
|     static const QByteArray & AcceptCharset; | ||||
|     static const QByteArray & AcceptEncoding; | ||||
|     static const QByteArray & AcceptLanguage; | ||||
|     static const QByteArray & Authorization; | ||||
|     static const QByteArray & CacheControl; | ||||
|     static const QByteArray & ContentMD5; | ||||
|     static const QByteArray & ProxyAuthorization; | ||||
|     static const QByteArray & Range; | ||||
|     static const QByteArray & ContentEncoding; | ||||
|     static const QByteArray & ContentLanguage; | ||||
|     static const QByteArray & ContentLocation; | ||||
|     static const QByteArray & ContentRange; | ||||
|     static const QByteArray & Expires; | ||||
|     static const QByteArray & LastModified; | ||||
|     static const QByteArray & Location; | ||||
|     static const QByteArray & SetCookie; | ||||
|     static const QByteArray & TransferEncoding; | ||||
|     static const QByteArray & ContentDisposition; | ||||
| 	static const QByteArray & Server; | ||||
| 	static const QByteArray & Date; | ||||
| 	static const QByteArray & Host; | ||||
| 	static const QByteArray & Accept; | ||||
| 	static const QByteArray & ContentType; | ||||
| 	static const QByteArray & ContentLength; | ||||
| 	static const QByteArray & Connection; | ||||
| 	static const QByteArray & Cookie; | ||||
| 	static const QByteArray & UserAgent; | ||||
| 	static const QByteArray & AcceptCharset; | ||||
| 	static const QByteArray & AcceptEncoding; | ||||
| 	static const QByteArray & AcceptLanguage; | ||||
| 	static const QByteArray & Authorization; | ||||
| 	static const QByteArray & CacheControl; | ||||
| 	static const QByteArray & ContentMD5; | ||||
| 	static const QByteArray & ProxyAuthorization; | ||||
| 	static const QByteArray & Range; | ||||
| 	static const QByteArray & ContentEncoding; | ||||
| 	static const QByteArray & ContentLanguage; | ||||
| 	static const QByteArray & ContentLocation; | ||||
| 	static const QByteArray & ContentRange; | ||||
| 	static const QByteArray & Expires; | ||||
| 	static const QByteArray & LastModified; | ||||
| 	static const QByteArray & Location; | ||||
| 	static const QByteArray & SetCookie; | ||||
| 	static const QByteArray & TransferEncoding; | ||||
| 	static const QByteArray & ContentDisposition; | ||||
| 	static const QByteArray & AccessControlAllow; | ||||
| 	// Websocket specific headers | ||||
| 	static const QByteArray & Upgrade; | ||||
|   | ||||
| @@ -6,70 +6,35 @@ | ||||
| #include <QDateTime> | ||||
|  | ||||
| QtHttpReply::QtHttpReply (QtHttpServer * parent) | ||||
|     : QObject        (parent) | ||||
|     , m_useChunked   (false) | ||||
|     , m_statusCode   (Ok) | ||||
|     , m_data         (QByteArray ()) | ||||
|     , m_serverHandle (parent) | ||||
| 	: QObject        (parent) | ||||
| 	, m_useChunked   (false) | ||||
| 	, m_statusCode   (Ok) | ||||
| 	, m_data         (QByteArray ()) | ||||
| 	, m_serverHandle (parent) | ||||
| { | ||||
|     // set some additional headers | ||||
|     addHeader (QtHttpHeader::Date,   QDateTime::currentDateTimeUtc ().toString ("ddd, dd MMM yyyy hh:mm:ss t").toUtf8 ()); | ||||
|     addHeader (QtHttpHeader::Server, m_serverHandle->getServerName ().toUtf8 ()); | ||||
| 	// set some additional headers | ||||
| 	addHeader (QtHttpHeader::Date,   QDateTime::currentDateTimeUtc ().toString ("ddd, dd MMM yyyy hh:mm:ss t").toUtf8 ()); | ||||
| 	addHeader (QtHttpHeader::Server, m_serverHandle->getServerName ().toUtf8 ()); | ||||
| } | ||||
|  | ||||
| int QtHttpReply::getRawDataSize (void) const { | ||||
|     return m_data.size (); | ||||
| const QByteArray QtHttpReply::getStatusTextForCode (QtHttpReply::StatusCode statusCode) | ||||
| { | ||||
| 	switch (statusCode) | ||||
| 	{ | ||||
| 		case Ok:         return QByteArrayLiteral ("OK."); | ||||
| 		case BadRequest: return QByteArrayLiteral ("Bad request !"); | ||||
| 		case Forbidden:  return QByteArrayLiteral ("Forbidden !"); | ||||
| 		case NotFound:   return QByteArrayLiteral ("Not found !"); | ||||
| 		default:         return QByteArrayLiteral (""); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool QtHttpReply::useChunked (void) const { | ||||
|     return m_useChunked; | ||||
| } | ||||
| void QtHttpReply::addHeader (const QByteArray & header, const QByteArray & value) | ||||
| { | ||||
| 	QByteArray key = header.trimmed (); | ||||
|  | ||||
| QtHttpReply::StatusCode QtHttpReply::getStatusCode (void) const { | ||||
|     return m_statusCode; | ||||
| } | ||||
|  | ||||
| QByteArray QtHttpReply::getRawData (void) const { | ||||
|     return m_data; | ||||
| } | ||||
|  | ||||
| QList<QByteArray> QtHttpReply::getHeadersList (void) const { | ||||
|     return m_headersHash.keys (); | ||||
| } | ||||
|  | ||||
| QByteArray QtHttpReply::getHeader (const QByteArray & header) const { | ||||
|     return m_headersHash.value (header, QByteArray ()); | ||||
| } | ||||
|  | ||||
| const QByteArray QtHttpReply::getStatusTextForCode (QtHttpReply::StatusCode statusCode) { | ||||
|     switch (statusCode) { | ||||
|         case Ok:         return QByteArrayLiteral ("OK."); | ||||
|         case BadRequest: return QByteArrayLiteral ("Bad request !"); | ||||
|         case Forbidden:  return QByteArrayLiteral ("Forbidden !"); | ||||
|         case NotFound:   return QByteArrayLiteral ("Not found !"); | ||||
|         default:         return QByteArrayLiteral (""); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void QtHttpReply::setUseChunked (bool chunked){ | ||||
|     m_useChunked = chunked; | ||||
| } | ||||
|  | ||||
| void QtHttpReply::setStatusCode (QtHttpReply::StatusCode statusCode) { | ||||
|     m_statusCode = statusCode; | ||||
| } | ||||
|  | ||||
| void QtHttpReply::appendRawData (const QByteArray & data) { | ||||
|     m_data.append (data); | ||||
| } | ||||
|  | ||||
| void QtHttpReply::addHeader (const QByteArray & header, const QByteArray & value) { | ||||
|     QByteArray key = header.trimmed (); | ||||
|     if (!key.isEmpty ()) { | ||||
|         m_headersHash.insert (key, value); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void QtHttpReply::resetRawData (void) { | ||||
|     m_data.clear (); | ||||
| 	if (!key.isEmpty ()) | ||||
| 	{ | ||||
| 		m_headersHash.insert (key, value); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -8,53 +8,58 @@ | ||||
|  | ||||
| class QtHttpServer; | ||||
|  | ||||
| class QtHttpReply : public QObject { | ||||
|     Q_OBJECT | ||||
|     Q_ENUMS (StatusCode) | ||||
| class QtHttpReply : public QObject | ||||
| { | ||||
| 	Q_OBJECT | ||||
| 	Q_ENUMS (StatusCode) | ||||
|  | ||||
| public: | ||||
|     explicit QtHttpReply (QtHttpServer * parent); | ||||
| 	explicit QtHttpReply (QtHttpServer * parent); | ||||
|  | ||||
|     enum StatusCode { | ||||
|         Ok                 = 200, | ||||
|         SeeOther           = 303, | ||||
|         BadRequest         = 400, | ||||
|         Forbidden          = 403, | ||||
|         NotFound           = 404, | ||||
|         MethodNotAllowed   = 405, | ||||
|         InternalError      = 500, | ||||
|         NotImplemented     = 501, | ||||
|         BadGateway         = 502, | ||||
|         ServiceUnavailable = 503, | ||||
|     }; | ||||
| 	enum StatusCode | ||||
| 	{ | ||||
| 		Ok                 = 200, | ||||
| 		SeeOther           = 303, | ||||
| 		BadRequest         = 400, | ||||
| 		Forbidden          = 403, | ||||
| 		NotFound           = 404, | ||||
| 		MethodNotAllowed   = 405, | ||||
| 		InternalError      = 500, | ||||
| 		NotImplemented     = 501, | ||||
| 		BadGateway         = 502, | ||||
| 		ServiceUnavailable = 503, | ||||
| 	}; | ||||
|  | ||||
|     int               getRawDataSize (void) const; | ||||
|     bool              useChunked     (void) const; | ||||
|     StatusCode        getStatusCode  (void) const; | ||||
|     QByteArray        getRawData     (void) const; | ||||
|     QList<QByteArray> getHeadersList (void) const; | ||||
| 	int               getRawDataSize (void) const { return m_data.size();         }; | ||||
| 	bool              useChunked     (void) const { return m_useChunked;          }; | ||||
| 	StatusCode        getStatusCode  (void) const { return m_statusCode;          }; | ||||
| 	QByteArray        getRawData     (void) const { return m_data;                }; | ||||
| 	QList<QByteArray> getHeadersList (void) const { return m_headersHash.keys (); }; | ||||
|  | ||||
|     QByteArray getHeader (const QByteArray & header) const; | ||||
| 	QByteArray getHeader (const QByteArray & header) const | ||||
| 	{ | ||||
| 		return m_headersHash.value (header, QByteArray ()); | ||||
| 	}; | ||||
|  | ||||
|     static const QByteArray getStatusTextForCode (StatusCode statusCode); | ||||
| 	static const QByteArray getStatusTextForCode (StatusCode statusCode); | ||||
|  | ||||
| public slots: | ||||
|     void setUseChunked (bool chunked = false); | ||||
|     void setStatusCode (StatusCode statusCode); | ||||
|     void appendRawData (const QByteArray & data); | ||||
|     void addHeader     (const QByteArray & header, const QByteArray & value); | ||||
|     void resetRawData  (void); | ||||
| 	void setUseChunked (bool chunked = false)    { m_useChunked = chunked;    }; | ||||
| 	void setStatusCode (StatusCode statusCode)   { m_statusCode = statusCode; }; | ||||
| 	void appendRawData (const QByteArray & data) { m_data.append(data);       }; | ||||
| 	void addHeader     (const QByteArray & header, const QByteArray & value); | ||||
| 	void resetRawData  (void) { m_data.clear (); }; | ||||
|  | ||||
| signals: | ||||
|     void requestSendHeaders (void); | ||||
|     void requestSendData    (void); | ||||
| 	void requestSendHeaders (void); | ||||
| 	void requestSendData    (void); | ||||
|  | ||||
| private: | ||||
|     bool                          m_useChunked; | ||||
|     StatusCode                    m_statusCode; | ||||
|     QByteArray                    m_data; | ||||
|     QtHttpServer *                m_serverHandle; | ||||
|     QHash<QByteArray, QByteArray> m_headersHash; | ||||
| 	bool                          m_useChunked; | ||||
| 	StatusCode                    m_statusCode; | ||||
| 	QByteArray                    m_data; | ||||
| 	QtHttpServer *                m_serverHandle; | ||||
| 	QHash<QByteArray, QByteArray> m_headersHash; | ||||
| }; | ||||
|  | ||||
| #endif // QTHTTPREPLY_H | ||||
|   | ||||
| @@ -4,80 +4,31 @@ | ||||
| #include "QtHttpServer.h" | ||||
|  | ||||
| QtHttpRequest::QtHttpRequest (QtHttpClientWrapper * client, QtHttpServer * parent) | ||||
|     : QObject         (parent) | ||||
|     , m_url           (QUrl ()) | ||||
|     , m_command       (QString ()) | ||||
|     , m_data          (QByteArray ()) | ||||
|     , m_serverHandle  (parent) | ||||
|     , m_clientHandle  (client) | ||||
|     , m_postData      (QtHttpPostData()) | ||||
| 	: QObject         (parent) | ||||
| 	, m_url           (QUrl ()) | ||||
| 	, m_command       (QString ()) | ||||
| 	, m_data          (QByteArray ()) | ||||
| 	, m_serverHandle  (parent) | ||||
| 	, m_clientHandle  (client) | ||||
| 	, m_postData      (QtHttpPostData()) | ||||
| { | ||||
|     // set some additional headers | ||||
|     addHeader (QtHttpHeader::ContentLength, QByteArrayLiteral ("0")); | ||||
|     addHeader (QtHttpHeader::Connection,    QByteArrayLiteral ("Keep-Alive")); | ||||
| 	// set some additional headers | ||||
| 	addHeader (QtHttpHeader::ContentLength, QByteArrayLiteral ("0")); | ||||
| 	addHeader (QtHttpHeader::Connection,    QByteArrayLiteral ("Keep-Alive")); | ||||
| } | ||||
|  | ||||
| QUrl QtHttpRequest::getUrl (void) const { | ||||
|     return m_url; | ||||
| void QtHttpRequest::setClientInfo (const QHostAddress & server, const QHostAddress & client) | ||||
| { | ||||
| 	m_clientInfo.serverAddress = server; | ||||
| 	m_clientInfo.clientAddress = client; | ||||
| } | ||||
|  | ||||
| QString QtHttpRequest::getCommand (void) const { | ||||
|     return m_command; | ||||
| } | ||||
| void QtHttpRequest::addHeader (const QByteArray & header, const QByteArray & value) | ||||
| { | ||||
| 	QByteArray key = header.trimmed (); | ||||
|  | ||||
| QtHttpRequest::ClientInfo QtHttpRequest::getClientInfo (void) const { | ||||
|     return m_clientInfo; | ||||
| } | ||||
|  | ||||
| int QtHttpRequest::getRawDataSize (void) const { | ||||
|     return m_data.size (); | ||||
| } | ||||
|  | ||||
|  | ||||
| QByteArray QtHttpRequest::getRawData (void) const { | ||||
|     return m_data; | ||||
| } | ||||
|  | ||||
| QtHttpPostData QtHttpRequest::getPostData (void) const { | ||||
|     return m_postData; | ||||
| } | ||||
|  | ||||
| QList<QByteArray> QtHttpRequest::getHeadersList (void) const { | ||||
|     return m_headersHash.keys (); | ||||
| } | ||||
|  | ||||
| QtHttpClientWrapper * QtHttpRequest::getClient (void) const { | ||||
|     return m_clientHandle; | ||||
| } | ||||
|  | ||||
| QByteArray QtHttpRequest::getHeader (const QByteArray & header) const { | ||||
|     return m_headersHash.value (header, QByteArray ()); | ||||
| } | ||||
|  | ||||
| void QtHttpRequest::setUrl (const QUrl & url) { | ||||
|     m_url = url; | ||||
| } | ||||
|  | ||||
| void QtHttpRequest::setCommand (const QString & command) { | ||||
|     m_command = command; | ||||
| } | ||||
|  | ||||
| void QtHttpRequest::setClientInfo (const QHostAddress & server, const QHostAddress & client) { | ||||
|     m_clientInfo.serverAddress = server; | ||||
|     m_clientInfo.clientAddress = client; | ||||
| } | ||||
|  | ||||
| void QtHttpRequest::addHeader (const QByteArray & header, const QByteArray & value) { | ||||
|     QByteArray key = header.trimmed (); | ||||
|     if (!key.isEmpty ()) { | ||||
|         m_headersHash.insert (key, value); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void QtHttpRequest::appendRawData (const QByteArray & data) { | ||||
|     m_data.append (data); | ||||
| } | ||||
|  | ||||
| void QtHttpRequest::setPostData (const QtHttpPostData & data) { | ||||
|     m_postData = data; | ||||
| 	if (!key.isEmpty ()) | ||||
| 	{ | ||||
| 		m_headersHash.insert (key, value); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -14,45 +14,50 @@ class QtHttpClientWrapper; | ||||
|  | ||||
| using QtHttpPostData = QMap<QString,QByteArray>; | ||||
|  | ||||
| class QtHttpRequest : public QObject { | ||||
|     Q_OBJECT | ||||
| class QtHttpRequest : public QObject | ||||
| { | ||||
| 	Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     explicit QtHttpRequest (QtHttpClientWrapper * client, QtHttpServer * parent); | ||||
| 	explicit QtHttpRequest (QtHttpClientWrapper * client, QtHttpServer * parent); | ||||
|  | ||||
|     struct ClientInfo { | ||||
|         QHostAddress serverAddress; | ||||
|         QHostAddress clientAddress; | ||||
|     }; | ||||
| 	struct ClientInfo | ||||
| 	{ | ||||
| 		QHostAddress serverAddress; | ||||
| 		QHostAddress clientAddress; | ||||
| 	}; | ||||
|  | ||||
|     int                   getRawDataSize (void) const; | ||||
|     QUrl                  getUrl         (void) const; | ||||
|     QString               getCommand     (void) const; | ||||
|     QByteArray            getRawData     (void) const; | ||||
|     QList<QByteArray>     getHeadersList (void) const; | ||||
|     QtHttpClientWrapper * getClient      (void) const; | ||||
| 	int                   getRawDataSize (void) const { return m_data.size ();        }; | ||||
| 	QUrl                  getUrl         (void) const { return m_url;                 }; | ||||
| 	QString               getCommand     (void) const { return m_command;             }; | ||||
| 	QByteArray            getRawData     (void) const { return m_data;                }; | ||||
| 	QList<QByteArray>     getHeadersList (void) const { return m_headersHash.keys (); }; | ||||
| 	QtHttpClientWrapper * getClient      (void) const { return m_clientHandle;        }; | ||||
| 	QtHttpPostData        getPostData    (void) const { return m_postData;            }; | ||||
| 	ClientInfo            getClientInfo  (void) const { return m_clientInfo;          }; | ||||
|  | ||||
|     QByteArray getHeader (const QByteArray & header) const; | ||||
|     QtHttpPostData       getPostData    (void) const; | ||||
|  | ||||
|     ClientInfo getClientInfo (void) const; | ||||
| 	QByteArray            getHeader      (const QByteArray & header) const | ||||
| 	{ | ||||
| 		return m_headersHash.value (header, QByteArray ()); | ||||
| 	}; | ||||
|  | ||||
| public slots: | ||||
|     void setUrl        (const QUrl & url); | ||||
|     void setCommand    (const QString & command); | ||||
|     void setClientInfo (const QHostAddress & server, const QHostAddress & client); | ||||
|     void addHeader     (const QByteArray & header, const QByteArray & value); | ||||
|     void appendRawData (const QByteArray & data); | ||||
|     void setPostData   (const QtHttpPostData & data); | ||||
| 	void setUrl        (const QUrl & url)            { m_url = url;          }; | ||||
| 	void setCommand    (const QString & command)     { m_command = command;  }; | ||||
| 	void appendRawData (const QByteArray & data)     { m_data.append (data); }; | ||||
| 	void setPostData   (const QtHttpPostData & data) { m_postData = data;    }; | ||||
|  | ||||
| 	void setClientInfo (const QHostAddress & server, const QHostAddress & client); | ||||
| 	void addHeader     (const QByteArray & header, const QByteArray & value); | ||||
|  | ||||
| private: | ||||
|     QUrl                          m_url; | ||||
|     QString                       m_command; | ||||
|     QByteArray                    m_data; | ||||
|     QtHttpServer *                m_serverHandle; | ||||
|     QtHttpClientWrapper *         m_clientHandle; | ||||
|     QHash<QByteArray, QByteArray> m_headersHash; | ||||
|     ClientInfo                    m_clientInfo; | ||||
| 	QUrl                          m_url; | ||||
| 	QString                       m_command; | ||||
| 	QByteArray                    m_data; | ||||
| 	QtHttpServer *                m_serverHandle; | ||||
| 	QtHttpClientWrapper *         m_clientHandle; | ||||
| 	QHash<QByteArray, QByteArray> m_headersHash; | ||||
| 	ClientInfo                    m_clientInfo; | ||||
| 	QtHttpPostData                m_postData; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -11,142 +11,116 @@ | ||||
| const QString & QtHttpServer::HTTP_VERSION = QStringLiteral ("HTTP/1.1"); | ||||
|  | ||||
| QtHttpServerWrapper::QtHttpServerWrapper (QObject * parent) | ||||
|     : QTcpServer (parent) | ||||
|     , m_useSsl   (false) | ||||
| { } | ||||
| 	: QTcpServer (parent) | ||||
| 	, m_useSsl   (false) | ||||
| { | ||||
|  | ||||
| QtHttpServerWrapper::~QtHttpServerWrapper (void) { } | ||||
|  | ||||
| void QtHttpServerWrapper::setUseSecure (const bool ssl) { | ||||
|     m_useSsl = ssl; | ||||
| } | ||||
|  | ||||
| void QtHttpServerWrapper::incomingConnection (qintptr handle) { | ||||
|     QTcpSocket * sock = (m_useSsl | ||||
|                          ? new QSslSocket (this) | ||||
|                          : new QTcpSocket (this)); | ||||
|     if (sock->setSocketDescriptor (handle)) { | ||||
|         addPendingConnection (sock); | ||||
|     } | ||||
|     else { | ||||
|         delete sock; | ||||
|     } | ||||
| QtHttpServerWrapper::~QtHttpServerWrapper (void) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| void QtHttpServerWrapper::setUseSecure (const bool ssl) | ||||
| { | ||||
| 	m_useSsl = ssl; | ||||
| } | ||||
|  | ||||
| void QtHttpServerWrapper::incomingConnection (qintptr handle) | ||||
| { | ||||
| 	QTcpSocket * sock = (m_useSsl ? new QSslSocket (this) : new QTcpSocket (this)); | ||||
| 	sock->setSocketDescriptor(handle) ? addPendingConnection (sock) : delete sock; | ||||
| } | ||||
|  | ||||
| QtHttpServer::QtHttpServer (QObject * parent) | ||||
|     : QObject      (parent) | ||||
|     , m_useSsl     (false) | ||||
|     , m_serverName (QStringLiteral ("The Qt5 HTTP Server")) | ||||
| 	: QObject      (parent) | ||||
| 	, m_useSsl     (false) | ||||
| 	, m_serverName (QStringLiteral ("The Qt5 HTTP Server")) | ||||
| 	, m_netOrigin  (NetOrigin::getInstance()) | ||||
| { | ||||
|     m_sockServer = new QtHttpServerWrapper (this); | ||||
|     connect (m_sockServer, &QtHttpServerWrapper::newConnection, this, &QtHttpServer::onClientConnected); | ||||
| 	m_sockServer = new QtHttpServerWrapper (this); | ||||
| 	connect (m_sockServer, &QtHttpServerWrapper::newConnection, this, &QtHttpServer::onClientConnected); | ||||
| } | ||||
|  | ||||
| const QString & QtHttpServer::getServerName (void) const { | ||||
|     return m_serverName; | ||||
| } | ||||
|  | ||||
| quint16 QtHttpServer::getServerPort (void) const { | ||||
|     return m_sockServer->serverPort (); | ||||
| } | ||||
|  | ||||
| QString QtHttpServer::getErrorString (void) const { | ||||
|     return m_sockServer->errorString (); | ||||
| } | ||||
|  | ||||
| void QtHttpServer::start (quint16 port) { | ||||
| void QtHttpServer::start (quint16 port) | ||||
| { | ||||
| 	if(!m_sockServer->isListening()) | ||||
| 	{ | ||||
| 		if (m_sockServer->listen (QHostAddress::Any, port)) { | ||||
| 			emit started (m_sockServer->serverPort ()); | ||||
| 		} | ||||
| 		else { | ||||
| 			emit error (m_sockServer->errorString ()); | ||||
| 		} | ||||
| 		m_sockServer->listen (QHostAddress::Any, port) | ||||
| 			? emit started (m_sockServer->serverPort ()) | ||||
| 			: emit error (m_sockServer->errorString ()); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void QtHttpServer::stop (void) { | ||||
|     if (m_sockServer->isListening ()) { | ||||
|         m_sockServer->close (); | ||||
| void QtHttpServer::stop (void) | ||||
| { | ||||
| 	if (m_sockServer->isListening ()) | ||||
| 	{ | ||||
| 		m_sockServer->close (); | ||||
| 		// disconnect clients | ||||
| 		const QList<QTcpSocket*> socks = m_socksClientsHash.keys(); | ||||
| 		for(auto sock : socks) | ||||
| 		{ | ||||
| 			sock->close(); | ||||
| 		} | ||||
|         emit stopped (); | ||||
|     } | ||||
|  | ||||
| 		emit stopped (); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void QtHttpServer::setServerName (const QString & serverName) { | ||||
|     m_serverName = serverName; | ||||
| void QtHttpServer::setUseSecure (const bool ssl) | ||||
| { | ||||
| 	m_useSsl = ssl; | ||||
| 	m_sockServer->setUseSecure (m_useSsl); | ||||
| } | ||||
|  | ||||
| void QtHttpServer::setUseSecure (const bool ssl) { | ||||
|     m_useSsl = ssl; | ||||
|     m_sockServer->setUseSecure (m_useSsl); | ||||
| } | ||||
|  | ||||
| void QtHttpServer::setPrivateKey (const QSslKey & key) { | ||||
|     m_sslKey = key; | ||||
| } | ||||
|  | ||||
| void QtHttpServer::setCertificates (const QList<QSslCertificate> & certs) { | ||||
|     m_sslCerts = certs; | ||||
| } | ||||
|  | ||||
| void QtHttpServer::onClientConnected (void) { | ||||
|     while (m_sockServer->hasPendingConnections ()) { | ||||
|         if (QTcpSocket * sock = m_sockServer->nextPendingConnection ()) { | ||||
| void QtHttpServer::onClientConnected (void) | ||||
| { | ||||
| 	while (m_sockServer->hasPendingConnections ()) | ||||
| 	{ | ||||
| 		if (QTcpSocket * sock = m_sockServer->nextPendingConnection ()) | ||||
| 		{ | ||||
| 			if(m_netOrigin->accessAllowed(sock->peerAddress(), sock->localAddress())) | ||||
| 			{ | ||||
| 	            connect (sock, &QTcpSocket::disconnected, this, &QtHttpServer::onClientDisconnected); | ||||
| 	            if (m_useSsl) { | ||||
| 	                if (QSslSocket * ssl = qobject_cast<QSslSocket *> (sock)) { | ||||
| 	                    connect (ssl, SslErrorSignal (&QSslSocket::sslErrors), this, &QtHttpServer::onClientSslErrors); | ||||
| 	                    connect (ssl, &QSslSocket::encrypted,                  this, &QtHttpServer::onClientSslEncrypted); | ||||
| 	                    connect (ssl, &QSslSocket::peerVerifyError,            this, &QtHttpServer::onClientSslPeerVerifyError); | ||||
| 	                    connect (ssl, &QSslSocket::modeChanged,                this, &QtHttpServer::onClientSslModeChanged); | ||||
| 	                    ssl->setLocalCertificateChain (m_sslCerts); | ||||
| 	                    ssl->setPrivateKey (m_sslKey); | ||||
| 	                    ssl->setPeerVerifyMode (QSslSocket::AutoVerifyPeer); | ||||
| 	                    ssl->startServerEncryption (); | ||||
| 	                } | ||||
| 	            } | ||||
| 	            QtHttpClientWrapper * wrapper = new QtHttpClientWrapper (sock, m_netOrigin->isLocalAddress(sock->peerAddress(), sock->localAddress()), this); | ||||
| 	            m_socksClientsHash.insert (sock, wrapper); | ||||
| 	            emit clientConnected (wrapper->getGuid ()); | ||||
| 				connect (sock, &QTcpSocket::disconnected, this, &QtHttpServer::onClientDisconnected); | ||||
|  | ||||
| 				if (m_useSsl) | ||||
| 				{ | ||||
| 					if (QSslSocket * ssl = qobject_cast<QSslSocket *> (sock)) | ||||
| 					{ | ||||
| 						connect (ssl, SslErrorSignal (&QSslSocket::sslErrors), this, &QtHttpServer::onClientSslErrors); | ||||
| 						connect (ssl, &QSslSocket::encrypted,                  this, &QtHttpServer::onClientSslEncrypted); | ||||
| 						connect (ssl, &QSslSocket::peerVerifyError,            this, &QtHttpServer::onClientSslPeerVerifyError); | ||||
| 						connect (ssl, &QSslSocket::modeChanged,                this, &QtHttpServer::onClientSslModeChanged); | ||||
| 						ssl->setLocalCertificateChain (m_sslCerts); | ||||
| 						ssl->setPrivateKey (m_sslKey); | ||||
| 						ssl->setPeerVerifyMode (QSslSocket::AutoVerifyPeer); | ||||
| 						ssl->startServerEncryption (); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				QtHttpClientWrapper * wrapper = new QtHttpClientWrapper (sock, m_netOrigin->isLocalAddress(sock->peerAddress(), sock->localAddress()), this); | ||||
| 				m_socksClientsHash.insert (sock, wrapper); | ||||
| 				emit clientConnected (wrapper->getGuid ()); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				sock->close(); | ||||
| 			} | ||||
|         } | ||||
|     } | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void QtHttpServer::onClientSslEncrypted (void) { } | ||||
|  | ||||
| void QtHttpServer::onClientSslPeerVerifyError (const QSslError & err) { | ||||
|     Q_UNUSED (err) | ||||
| } | ||||
|  | ||||
| void QtHttpServer::onClientSslErrors (const QList<QSslError> & errors) { | ||||
|     Q_UNUSED (errors) | ||||
| } | ||||
|  | ||||
| void QtHttpServer::onClientSslModeChanged (QSslSocket::SslMode mode) { | ||||
|     Q_UNUSED (mode) | ||||
| } | ||||
|  | ||||
| void QtHttpServer::onClientDisconnected (void) { | ||||
|     if (QTcpSocket * sockClient = qobject_cast<QTcpSocket *> (sender ())) { | ||||
|         if (QtHttpClientWrapper * wrapper = m_socksClientsHash.value (sockClient, Q_NULLPTR)) { | ||||
|             emit clientDisconnected (wrapper->getGuid ()); | ||||
|             wrapper->deleteLater (); | ||||
|             m_socksClientsHash.remove (sockClient); | ||||
|         } | ||||
|     } | ||||
| void QtHttpServer::onClientDisconnected (void) | ||||
| { | ||||
| 	if (QTcpSocket * sockClient = qobject_cast<QTcpSocket *> (sender ())) | ||||
| 	{ | ||||
| 		if (QtHttpClientWrapper * wrapper = m_socksClientsHash.value (sockClient, Q_NULLPTR)) | ||||
| 		{ | ||||
| 			emit clientDisconnected (wrapper->getGuid ()); | ||||
| 			wrapper->deleteLater (); | ||||
| 			m_socksClientsHash.remove (sockClient); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -13,76 +13,77 @@ | ||||
|  | ||||
| class QTcpSocket; | ||||
| class QTcpServer; | ||||
|  | ||||
| class QtHttpRequest; | ||||
| class QtHttpReply; | ||||
| class QtHttpClientWrapper; | ||||
| class NetOrigin; | ||||
|  | ||||
| class QtHttpServerWrapper : public QTcpServer { | ||||
|     Q_OBJECT | ||||
| class QtHttpServerWrapper : public QTcpServer | ||||
| { | ||||
| 	Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     explicit QtHttpServerWrapper (QObject * parent = Q_NULLPTR); | ||||
|     virtual ~QtHttpServerWrapper (void); | ||||
| 	explicit QtHttpServerWrapper (QObject * parent = Q_NULLPTR); | ||||
| 	virtual ~QtHttpServerWrapper (void); | ||||
|  | ||||
|     void setUseSecure (const bool ssl = true); | ||||
| 	void setUseSecure (const bool ssl = true); | ||||
|  | ||||
| protected: | ||||
|     void incomingConnection (qintptr handle) Q_DECL_OVERRIDE; | ||||
| 	void incomingConnection (qintptr handle) Q_DECL_OVERRIDE; | ||||
|  | ||||
| private: | ||||
|     bool m_useSsl; | ||||
| 	bool m_useSsl; | ||||
| }; | ||||
|  | ||||
| class QtHttpServer : public QObject { | ||||
|     Q_OBJECT | ||||
| class QtHttpServer : public QObject | ||||
| { | ||||
| 	Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     explicit QtHttpServer (QObject * parent = Q_NULLPTR); | ||||
| 	explicit QtHttpServer (QObject * parent = Q_NULLPTR); | ||||
|  | ||||
|     static const QString & HTTP_VERSION; | ||||
| 	static const QString & HTTP_VERSION; | ||||
|  | ||||
|     typedef void (QSslSocket::* SslErrorSignal) (const QList<QSslError> &); | ||||
| 	typedef void (QSslSocket::* SslErrorSignal) (const QList<QSslError> &); | ||||
|  | ||||
|     const QString & getServerName (void) const; | ||||
| 	const QString & getServerName (void) const { return m_serverName; }; | ||||
|  | ||||
|     quint16 getServerPort    (void) const; | ||||
|     QString getErrorString   (void) const; | ||||
| 	bool isListening() { return m_sockServer->isListening(); }; | ||||
| 	quint16 getServerPort  (void) const { return m_sockServer->serverPort();  }; | ||||
| 	QString getErrorString (void) const { return m_sockServer->errorString(); }; | ||||
| 	bool    isListening()               { return m_sockServer->isListening(); }; | ||||
|  | ||||
| public slots: | ||||
|     void start           (quint16 port = 0); | ||||
|     void stop            (void); | ||||
|     void setServerName   (const QString & serverName); | ||||
|     void setUseSecure    (const bool ssl = true); | ||||
|     void setPrivateKey   (const QSslKey & key); | ||||
|     void setCertificates (const QList<QSslCertificate> & certs); | ||||
| 	void start           (quint16 port = 0); | ||||
| 	void stop            (void); | ||||
| 	void setUseSecure    (const bool ssl = true); | ||||
| 	void setServerName   (const QString & serverName)           { m_serverName = serverName; }; | ||||
| 	void setPrivateKey   (const QSslKey & key)                  { m_sslKey = key; }; | ||||
| 	void setCertificates (const QList<QSslCertificate> & certs) { m_sslCerts = certs; }; | ||||
|  | ||||
| signals: | ||||
|     void started            (quint16 port); | ||||
|     void stopped            (void); | ||||
|     void error              (const QString & msg); | ||||
|     void clientConnected    (const QString & guid); | ||||
|     void clientDisconnected (const QString & guid); | ||||
|     void requestNeedsReply  (QtHttpRequest * request, QtHttpReply * reply); | ||||
| 	void started            (quint16 port); | ||||
| 	void stopped            (void); | ||||
| 	void error              (const QString & msg); | ||||
| 	void clientConnected    (const QString & guid); | ||||
| 	void clientDisconnected (const QString & guid); | ||||
| 	void requestNeedsReply  (QtHttpRequest * request, QtHttpReply * reply); | ||||
|  | ||||
| private slots: | ||||
|     void onClientConnected          (void); | ||||
|     void onClientDisconnected       (void); | ||||
|     void onClientSslEncrypted       (void); | ||||
|     void onClientSslPeerVerifyError (const QSslError & err); | ||||
|     void onClientSslErrors          (const QList<QSslError> & errors); | ||||
|     void onClientSslModeChanged     (QSslSocket::SslMode mode); | ||||
| 	void onClientConnected          (void); | ||||
| 	void onClientDisconnected       (void); | ||||
| 	void onClientSslEncrypted       (void)                            {                   }; | ||||
| 	void onClientSslPeerVerifyError (const QSslError & err)           { Q_UNUSED (err)    }; | ||||
| 	void onClientSslErrors          (const QList<QSslError> & errors) { Q_UNUSED (errors) }; | ||||
| 	void onClientSslModeChanged     (QSslSocket::SslMode mode)        { Q_UNUSED (mode)   }; | ||||
|  | ||||
| private: | ||||
|     bool                                       m_useSsl; | ||||
|     QSslKey                                    m_sslKey; | ||||
|     QList<QSslCertificate>                     m_sslCerts; | ||||
|     QString                                    m_serverName; | ||||
| 	bool                                       m_useSsl; | ||||
| 	QSslKey                                    m_sslKey; | ||||
| 	QList<QSslCertificate>                     m_sslCerts; | ||||
| 	QString                                    m_serverName; | ||||
| 	NetOrigin*                                 m_netOrigin; | ||||
|     QtHttpServerWrapper *                      m_sockServer; | ||||
|     QHash<QTcpSocket *, QtHttpClientWrapper *> m_socksClientsHash; | ||||
| 	QtHttpServerWrapper *                      m_sockServer; | ||||
| 	QHash<QTcpSocket *, QtHttpClientWrapper *> m_socksClientsHash; | ||||
| }; | ||||
|  | ||||
| #endif // QTHTTPSERVER_H | ||||
|   | ||||
| @@ -63,7 +63,8 @@ void WebServer::onServerStarted (quint16 port) | ||||
| 	emit stateChange(true); | ||||
| } | ||||
|  | ||||
| void WebServer::onServerStopped () { | ||||
| void WebServer::onServerStopped () | ||||
| { | ||||
| 	Info(_log, "Stopped %s", _server->getServerName().toStdString().c_str()); | ||||
| 	emit stateChange(false); | ||||
| } | ||||
|   | ||||
| @@ -14,7 +14,6 @@ WebSocketClient::WebSocketClient(QtHttpRequest* request, QTcpSocket* sock, const | ||||
| 	: QObject(parent) | ||||
| 	, _socket(sock) | ||||
| 	, _log(Logger::getInstance("WEBSOCKET")) | ||||
| //	, _hyperion(Hyperion::getInstance()) | ||||
| { | ||||
| 	// connect socket; disconnect handled from QtHttpServer | ||||
| 	connect(_socket, &QTcpSocket::readyRead , this, &WebSocketClient::handleWebSocketFrame); | ||||
| @@ -45,107 +44,113 @@ WebSocketClient::WebSocketClient(QtHttpRequest* request, QTcpSocket* sock, const | ||||
|  | ||||
| void WebSocketClient::handleWebSocketFrame(void) | ||||
| { | ||||
| 	// we are on no continious reading from socket from call before | ||||
| 	if (!_notEnoughData) | ||||
| 	while (_socket->bytesAvailable()) | ||||
| 	{ | ||||
| 		getWsFrameHeader(&_wsh); | ||||
| 	} | ||||
|  | ||||
| 	if(_socket->bytesAvailable() < (qint64)_wsh.payloadLength) | ||||
| 	{ | ||||
| 		//printf("not enough data %llu %llu\n", _socket->bytesAvailable(),  _wsh.payloadLength); | ||||
| 		_notEnoughData=true; | ||||
| 		return; | ||||
| 	} | ||||
| 	_notEnoughData = false; | ||||
|  | ||||
| 	QByteArray buf = _socket->read(_wsh.payloadLength); | ||||
| 	//printf("opcode %x payload bytes %llu avail: %llu\n", _wsh.opCode, _wsh.payloadLength, _socket->bytesAvailable()); | ||||
|  | ||||
| 	if (OPCODE::invalid((OPCODE::value)_wsh.opCode)) | ||||
| 	{ | ||||
| 		sendClose(CLOSECODE::INV_TYPE, "invalid opcode"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// check the type of data frame | ||||
| 	bool isContinuation=false; | ||||
| 	switch (_wsh.opCode) | ||||
| 	{ | ||||
| 		case OPCODE::CONTINUATION: | ||||
| 			isContinuation = true; | ||||
| 			// no break here, just jump over to opcode text | ||||
|  | ||||
| 		case OPCODE::BINARY: | ||||
| 		case OPCODE::TEXT: | ||||
| 		// we are on no continious reading from socket from call before | ||||
| 		if (!_notEnoughData) | ||||
| 		{ | ||||
| 			// check for protocal violations | ||||
| 			if (_onContinuation && !isContinuation) | ||||
| 			{ | ||||
| 				sendClose(CLOSECODE::VIOLATION, "protocol violation, somebody sends frames in between continued frames"); | ||||
| 				return; | ||||
| 			} | ||||
| 			getWsFrameHeader(&_wsh); | ||||
| 		} | ||||
|  | ||||
| 			if (!_wsh.masked && _wsh.opCode == OPCODE::TEXT) | ||||
| 			{ | ||||
| 				sendClose(CLOSECODE::VIOLATION, "protocol violation, unmasked text frames not allowed"); | ||||
| 				return; | ||||
| 			} | ||||
| 		if(_socket->bytesAvailable() < (qint64)_wsh.payloadLength) | ||||
| 		{ | ||||
| 			//printf("not enough data %llu %llu\n", _socket->bytesAvailable(),  _wsh.payloadLength); | ||||
| 			_notEnoughData=true; | ||||
| 			return; | ||||
| 		} | ||||
| 		_notEnoughData = false; | ||||
|  | ||||
| 			// unmask data | ||||
| 			for (int i=0; i < buf.size(); i++) | ||||
| 			{ | ||||
| 				buf[i] = buf[i] ^ _wsh.key[i % 4]; | ||||
| 			} | ||||
| 		QByteArray buf = _socket->read(_wsh.payloadLength); | ||||
| 		//printf("opcode %x payload bytes %llu avail: %llu\n", _wsh.opCode, _wsh.payloadLength, _socket->bytesAvailable()); | ||||
|  | ||||
| 			_onContinuation = !_wsh.fin || isContinuation; | ||||
| 		if (OPCODE::invalid((OPCODE::value)_wsh.opCode)) | ||||
| 		{ | ||||
| 			sendClose(CLOSECODE::INV_TYPE, "invalid opcode"); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 			// frame contains text, extract it, append data if this is a continuation | ||||
| 			if (_wsh.fin && ! isContinuation) // one frame | ||||
| 			{ | ||||
| 				_wsReceiveBuffer.clear(); | ||||
| 			} | ||||
| 			_wsReceiveBuffer.append(buf); | ||||
| 		// check the type of data frame | ||||
| 		bool isContinuation=false; | ||||
|  | ||||
| 			// this is the final frame, decode and handle data | ||||
| 			if (_wsh.fin) | ||||
| 		switch (_wsh.opCode) | ||||
| 		{ | ||||
| 			case OPCODE::CONTINUATION: | ||||
| 				isContinuation = true; | ||||
| 				// no break here, just jump over to opcode text | ||||
|  | ||||
| 			case OPCODE::BINARY: | ||||
| 			case OPCODE::TEXT: | ||||
| 			{ | ||||
| 				_onContinuation = false; | ||||
| 				// check for protocol violations | ||||
| 				if (_onContinuation && !isContinuation) | ||||
| 				{ | ||||
| 					sendClose(CLOSECODE::VIOLATION, "protocol violation, somebody sends frames in between continued frames"); | ||||
| 					return; | ||||
| 				} | ||||
|  | ||||
| 				if (!_wsh.masked && _wsh.opCode == OPCODE::TEXT) | ||||
| 				{ | ||||
| 					sendClose(CLOSECODE::VIOLATION, "protocol violation, unmasked text frames not allowed"); | ||||
| 					return; | ||||
| 				} | ||||
|  | ||||
| 				// unmask data | ||||
| 				for (int i=0; i < buf.size(); i++) | ||||
| 				{ | ||||
| 					buf[i] = buf[i] ^ _wsh.key[i % 4]; | ||||
| 				} | ||||
|  | ||||
| 				_onContinuation = !_wsh.fin || isContinuation; | ||||
|  | ||||
| 				// frame contains text, extract it, append data if this is a continuation | ||||
| 				if (_wsh.fin && ! isContinuation) // one frame | ||||
| 				{ | ||||
| 					_wsReceiveBuffer.clear(); | ||||
| 				} | ||||
| 				_wsReceiveBuffer.append(buf); | ||||
|  | ||||
| 				// this is the final frame, decode and handle data | ||||
| 				if (_wsh.fin) | ||||
| 				{ | ||||
| 					_onContinuation = false; | ||||
| 				if (_wsh.opCode == OPCODE::TEXT) | ||||
| 				{ | ||||
| 					_jsonAPI->handleMessage(QString(_wsReceiveBuffer)); | ||||
|  | ||||
| 						_jsonAPI->handleMessage(QString(_wsReceiveBuffer)); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					handleBinaryMessage(_wsReceiveBuffer); | ||||
| 				} | ||||
| 				_wsReceiveBuffer.clear(); | ||||
| 					_wsReceiveBuffer.clear(); | ||||
| 					 | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 			case OPCODE::CLOSE: | ||||
| 				{ | ||||
| 					sendClose(CLOSECODE::NORMAL); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 			case OPCODE::PING: | ||||
| 				{ | ||||
| 					// ping received, send pong | ||||
| 					quint8 pong[] = {OPCODE::PONG, 0}; | ||||
| 					_socket->write((const char*)pong, 2); | ||||
| 					_socket->flush(); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 			case OPCODE::PONG: | ||||
| 				{ | ||||
| 					Error(_log, "pong received, protocol violation!"); | ||||
| 				} | ||||
|  | ||||
| 			default: | ||||
| 				Warning(_log, "strange %d\n%s\n",  _wsh.opCode, QSTRING_CSTR(QString(buf))); | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 		case OPCODE::CLOSE: | ||||
| 			{ | ||||
| 				sendClose(CLOSECODE::NORMAL); | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 		case OPCODE::PING: | ||||
| 			{ | ||||
| 				// ping received, send pong | ||||
| 				quint8 pong[] = {OPCODE::PONG, 0}; | ||||
| 				_socket->write((const char*)pong, 2); | ||||
| 				_socket->flush(); | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 		case OPCODE::PONG: | ||||
| 			{ | ||||
| 				Error(_log, "pong received, protocol violation!"); | ||||
| 			} | ||||
|  | ||||
| 		default: | ||||
| 			Warning(_log, "strange %d\n%s\n",  _wsh.opCode, QSTRING_CSTR(QString(buf))); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -221,6 +226,7 @@ void WebSocketClient::sendClose(int status, QString reason) | ||||
| 	_socket->close(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void WebSocketClient::handleBinaryMessage(QByteArray &data) | ||||
| { | ||||
| 	//uint8_t  priority   = data.at(0); | ||||
| @@ -243,6 +249,7 @@ void WebSocketClient::handleBinaryMessage(QByteArray &data) | ||||
| 	//_hyperion->setInputImage(priority, image, duration_s*1000); | ||||
| } | ||||
|  | ||||
|  | ||||
| qint64 WebSocketClient::sendMessage(QJsonObject obj) | ||||
| { | ||||
| 	QJsonDocument writer(obj); | ||||
|   | ||||
| @@ -17,7 +17,7 @@ public: | ||||
| 	struct WebSocketHeader | ||||
| 	{ | ||||
| 		bool          fin; | ||||
| 		quint8 opCode; | ||||
| 		quint8        opCode; | ||||
| 		bool          masked; | ||||
| 		quint64       payloadLength; | ||||
| 		char          key[4]; | ||||
|   | ||||
| @@ -4,8 +4,10 @@ | ||||
| /** | ||||
|  * WebSocket Opcodes are 4 bits. See RFC6455 section 5.2. | ||||
|  */ | ||||
| namespace OPCODE { | ||||
| 	enum value { | ||||
| namespace OPCODE | ||||
| { | ||||
| 	enum value | ||||
| 	{ | ||||
| 		CONTINUATION = 0x0, | ||||
| 		TEXT = 0x1, | ||||
| 		BINARY = 0x2, | ||||
| @@ -29,7 +31,8 @@ namespace OPCODE { | ||||
| 	 * @param v The opcode to test. | ||||
| 	 * @return Whether or not the opcode is reserved. | ||||
| 	 */ | ||||
| 	inline bool reserved(value v) { | ||||
| 	inline bool reserved(value v) | ||||
| 	{ | ||||
| 		return (v >= RSV3 && v <= RSV7) || (v >= CONTROL_RSVB && v <= CONTROL_RSVF); | ||||
| 	} | ||||
|  | ||||
| @@ -40,7 +43,8 @@ namespace OPCODE { | ||||
| 	 * @param v The opcode to test. | ||||
| 	 * @return Whether or not the opcode is invalid. | ||||
| 	 */ | ||||
| 	inline bool invalid(value v) { | ||||
| 	inline bool invalid(value v) | ||||
| 	{ | ||||
| 		return (v > 0xF || v < 0); | ||||
| 	} | ||||
|  | ||||
| @@ -49,13 +53,16 @@ namespace OPCODE { | ||||
| 	 * @param v The opcode to test. | ||||
| 	 * @return Whether or not the opcode is a control opcode. | ||||
| 	*/ | ||||
| 	inline bool is_control(value v) { | ||||
| 	inline bool is_control(value v) | ||||
| 	{ | ||||
| 		return v >= 0x8; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| namespace CLOSECODE { | ||||
| 	enum value { | ||||
| namespace CLOSECODE | ||||
| { | ||||
| 	enum value | ||||
| 	{ | ||||
| 		NORMAL    = 1000, | ||||
| 		AWAY      = 1001, | ||||
| 		TERM      = 1002, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user