diff --git a/src/WebSocket.h b/src/WebSocket.h index 00da7812d..d864fb05c 100644 --- a/src/WebSocket.h +++ b/src/WebSocket.h @@ -115,15 +115,22 @@ struct WebSocket : AsyncSocket { WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) ); + WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); + + /* Once closing due to backpressure, never send another frame */ + if (webSocketData->isClosingDueToBackpressure) { + return DROPPED; + } - /* Skip sending and report success if we are over the limit of maxBackpressure */ + /* Skip sending if we are over the limit of maxBackpressure */ if (webSocketContextData->maxBackpressure && webSocketContextData->maxBackpressure < getBufferedAmount()) { /* Also defer a close if we should */ if (webSocketContextData->closeOnBackpressureLimit) { + webSocketData->isClosingDueToBackpressure = true; us_socket_shutdown_read(SSL, (us_socket_t *) this); } - /* It is okay to call send again from within this callback since we immediately return with DROPPED afterwards */ + /* Inform the application about the triggering dropped message */ if (webSocketContextData->droppedHandler) { webSocketContextData->droppedHandler(this, message, opCode); } @@ -131,9 +138,6 @@ struct WebSocket : AsyncSocket { return DROPPED; } - /* If we are subscribers and have messages to drain we need to drain them here to stay synced */ - WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); - /* Special path for long sends of non-compressed, non-SSL messages */ if (message.length() >= 16 * 1024 && !compress && !SSL && !webSocketData->subscriber && getBufferedAmount() == 0 && Super::getLoopData()->corkOffset == 0) { char header[10]; @@ -156,6 +160,7 @@ struct WebSocket : AsyncSocket { } } else { + /* If we are subscribers and have messages to drain we need to drain them here to stay synced */ if (webSocketData->subscriber) { /* This will call back into us, send. */ webSocketContextData->topicTree->drain(webSocketData->subscriber); diff --git a/src/WebSocketContext.h b/src/WebSocketContext.h index d8b3fd035..2d5594dbe 100644 --- a/src/WebSocketContext.h +++ b/src/WebSocketContext.h @@ -392,7 +392,7 @@ struct WebSocketContext { auto *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s)); auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); - if (webSocketContextData->sendPingsAutomatically && !webSocketData->isShuttingDown && !webSocketData->hasTimedOut) { + if (webSocketContextData->sendPingsAutomatically && !webSocketData->isShuttingDown && !webSocketData->isClosingDueToBackpressure && !webSocketData->hasTimedOut) { webSocketData->hasTimedOut = true; us_socket_timeout(SSL, s, webSocketContextData->idleTimeoutComponents.second); /* Send ping without being corked */ diff --git a/src/WebSocketData.h b/src/WebSocketData.h index 21e96a72d..4eaa943b2 100644 --- a/src/WebSocketData.h +++ b/src/WebSocketData.h @@ -37,6 +37,7 @@ struct WebSocketData : AsyncSocketData, WebSocketState { std::string fragmentBuffer; unsigned int controlTipLength = 0; bool isShuttingDown = 0; + bool isClosingDueToBackpressure = false; bool hasTimedOut = false; enum CompressionStatus : char { DISABLED,