void HttpError::Throw(const char* msg,HttpServerConnection& client) { client.dump_context(stderr); client.async_write("HTTP/1.0 "); client.async_write(msg); client.async_write("\r\nConnection: close\r\n\r\n"); ThrowGracefulClose(msg); };
bool HttpServer::initWebSocket(HttpServerConnection& connection, HttpRequest& request, HttpResponse& response) { if (!wsEnabled) return false; WebSocket *sock = new WebSocket(&connection); if (!sock->initialize(request, response)) return false; connection.setTimeOut(USHRT_MAX); //Disable disconnection on connection idle (no rx/tx) connection.setDisconnectionHandler(HttpServerConnectionDelegate(&HttpServer::onCloseWebSocket, this)); // auto remove on close response.sendHeader(connection); // Will push header before user data wsocks.addElement(sock); if (wsConnect) wsConnect(*sock); if (wsCommandEnabled && (request.getQueryParameter(wsCommandRequestParam) == "true")) { #if ENABLE_CMD_EXECUTOR debugf("WebSocket Commandprocessor started"); #else debugf("WebSocket Commandprocessor support DISABLED via ENABLE_CMD_EXECUTOR"); #endif sock->enableCommand(); } }
void HttpResponse::sendHeader(HttpServerConnection &connection) { if (headerSent) return; String top = "HTTP/1.1 " + status + "\r\n"; connection.writeString(top.c_str(), TCP_WRITE_FLAG_MORE | TCP_WRITE_FLAG_COPY); for (int i = 0; i < responseHeaders.count(); i++) { String write = responseHeaders.keyAt(i) + ": " + responseHeaders.valueAt(i) + "\r\n"; connection.writeString(write.c_str(), TCP_WRITE_FLAG_MORE | TCP_WRITE_FLAG_COPY); } connection.writeString("\r\n"); headerSent = true; }
void HttpServer::processWebSocketFrame(pbuf *buf, HttpServerConnection& connection) { //TODO: process splitted payload uint8_t* data; size_t size; wsFrameType frameType = wsParseInputFrame((uint8_t*)buf->payload, buf->len, &data, &size); WebSocket* sock = getWebSocket(connection); if (frameType == WS_TEXT_FRAME) { String msg; msg.setString((char*)data, size); debugf("WS: %s", msg.c_str()); if (sock && wsMessage) wsMessage(*sock, msg); } if (frameType == WS_BINARY_FRAME) { if (sock && wsMessage) wsBinary(*sock, data, size); } else if (frameType == WS_CLOSING_FRAME) { connection.close(); // it will be processed automatically in onCloseWebSocket callback } else if (frameType == WS_INCOMPLETE_FRAME || frameType == WS_ERROR_FRAME) debugf("WS error reading frame: %X", frameType); else debugf("WS frame type: %X", frameType); }
bool HttpResponse::sendBody(HttpServerConnection &connection) { if (!headerSent) sendHeader(connection); if (stream == NULL) return true; connection.write(stream); if (stream->isFinished()) { connection.flush(); bodySent = true; debugf("Stream completed"); delete stream; // Free memory now! stream = NULL; return true; } else return false; }
bool HttpServer::initWebSocket(HttpServerConnection& connection, HttpRequest& request, HttpResponse& response) { if (!wsEnabled) return false; auto sock = WebSocket(&connection); if (!sock.initialize(request, response)) return false; connection.setDisconnectionHandler(HttpServerConnectionDelegate(&HttpServer::onCloseWebSocket, this)); // auto remove on close response.sendHeader(connection); // Will push header before user data wsocks.add(sock); if (wsConnect) wsConnect(sock); return true; }
void HttpServer::processWebSocketFrame(pbuf *buf, HttpServerConnection& connection) { //TODO: process splitted payload uint8_t* data; size_t size; wsFrameType frameType = (wsFrameType) 0x01; uint8_t payloadFieldExtraBytes = 0; size_t payloadLength = 0; size_t payloadShift = 0; do { payloadLength = getPayloadLength((uint8_t*)buf->payload + payloadShift, buf->len, &payloadFieldExtraBytes, &frameType); // debugf("payloadLength: %u, payLoadShift: %u, payloadFieldExtraBytes: %u\n", payloadLength, payloadShift, payloadFieldExtraBytes); wsFrameType frameType = wsParseInputFrame((uint8_t*)buf->payload + payloadShift, (payloadLength + 6 + payloadFieldExtraBytes), &data, &size); WebSocket* sock = getWebSocket(connection); if (frameType == WS_TEXT_FRAME) { String msg; msg.setString((char*)data, size); debugf("WS: %s", msg.c_str()); if (sock && wsMessage) wsMessage(*sock, msg); #if ENABLE_CMD_EXECUTOR if (sock && sock->commandExecutor) sock->commandExecutor->executorReceive(msg+"\r"); #endif } else if (frameType == WS_BINARY_FRAME) { if (sock && wsMessage) wsBinary(*sock, data, size); } else if (frameType == WS_CLOSING_FRAME) { connection.close(); // it will be processed automatically in onCloseWebSocket callback } else if (frameType == WS_INCOMPLETE_FRAME || frameType == WS_ERROR_FRAME) debugf("WS error reading frame: %X", frameType); else debugf("WS frame type: %X", frameType); payloadShift += payloadLength + 6 + payloadFieldExtraBytes; } while (buf->len > payloadShift); }
bool EventsHandler::HandleRequest( AsioTlsStream& stream, const ApiUser::Ptr& user, boost::beast::http::request<boost::beast::http::string_body>& request, const Url::Ptr& url, boost::beast::http::response<boost::beast::http::string_body>& response, const Dictionary::Ptr& params, boost::asio::yield_context& yc, HttpServerConnection& server ) { namespace asio = boost::asio; namespace http = boost::beast::http; if (url->GetPath().size() != 2) return false; if (request.method() != http::verb::post) return false; if (request.version() == 10) { HttpUtility::SendJsonError(response, params, 400, "HTTP/1.0 not supported for event streams."); return true; } Array::Ptr types = params->Get("types"); if (!types) { HttpUtility::SendJsonError(response, params, 400, "'types' query parameter is required."); return true; } { ObjectLock olock(types); for (const String& type : types) { FilterUtility::CheckPermission(user, "events/" + type); } } String queueName = HttpUtility::GetLastParameter(params, "queue"); if (queueName.IsEmpty()) { HttpUtility::SendJsonError(response, params, 400, "'queue' query parameter is required."); return true; } std::set<EventType> eventTypes; { ObjectLock olock(types); for (const String& type : types) { auto typeId (l_EventTypes.find(type)); if (typeId != l_EventTypes.end()) { eventTypes.emplace(typeId->second); } } } EventsSubscriber subscriber (std::move(eventTypes), HttpUtility::GetLastParameter(params, "filter"), l_ApiQuery); server.StartStreaming(); response.result(http::status::ok); response.set(http::field::content_type, "application/json"); IoBoundWorkSlot dontLockTheIoThread (yc); http::async_write(stream, response, yc); stream.async_flush(yc); asio::const_buffer newLine ("\n", 1); for (;;) { auto event (subscriber.GetInbox()->Shift(yc)); if (event) { CpuBoundWork buildingResponse (yc); String body = JsonEncode(event); boost::algorithm::replace_all(body, "\n", ""); asio::const_buffer payload (body.CStr(), body.GetLength()); buildingResponse.Done(); asio::async_write(stream, payload, yc); asio::async_write(stream, newLine, yc); stream.async_flush(yc); } else if (server.Disconnected()) { return true; } } }