Search in sources :

Example 1 with SendHandler

use of jakarta.websocket.SendHandler in project tomcat by apache.

the class WsRemoteEndpointImplServer method clearHandler.

/**
 * @param t             The throwable associated with any error that
 *                      occurred
 * @param useDispatch   Should {@link SendHandler#onResult(SendResult)} be
 *                      called from a new thread, keeping in mind the
 *                      requirements of
 *                      {@link jakarta.websocket.RemoteEndpoint.Async}
 */
private void clearHandler(Throwable t, boolean useDispatch) {
    // Setting the result marks this (partial) message as
    // complete which means the next one may be sent which
    // could update the value of the handler. Therefore, keep a
    // local copy before signalling the end of the (partial)
    // message.
    SendHandler sh = handler;
    handler = null;
    buffers = null;
    if (sh != null) {
        if (useDispatch) {
            OnResultRunnable r = new OnResultRunnable(sh, t);
            try {
                socketWrapper.execute(r);
            } catch (RejectedExecutionException ree) {
                // Can't use the executor so call the runnable directly.
                // This may not be strictly specification compliant in all
                // cases but during shutdown only close messages are going
                // to be sent so there should not be the issue of nested
                // calls leading to stack overflow as described in bug
                // 55715. The issues with nested calls was the reason for
                // the separate thread requirement in the specification.
                r.run();
            }
        } else {
            if (t == null) {
                sh.onResult(new SendResult());
            } else {
                sh.onResult(new SendResult(t));
            }
        }
    }
}
Also used : SendHandler(jakarta.websocket.SendHandler) SendResult(jakarta.websocket.SendResult) RejectedExecutionException(java.util.concurrent.RejectedExecutionException)

Example 2 with SendHandler

use of jakarta.websocket.SendHandler in project tomcat by apache.

the class PerMessageDeflate method sendMessagePart.

@Override
public List<MessagePart> sendMessagePart(List<MessagePart> uncompressedParts) throws IOException {
    List<MessagePart> allCompressedParts = new ArrayList<>();
    for (MessagePart uncompressedPart : uncompressedParts) {
        byte opCode = uncompressedPart.getOpCode();
        boolean emptyPart = uncompressedPart.getPayload().limit() == 0;
        emptyMessage = emptyMessage && emptyPart;
        if (Util.isControl(opCode)) {
            // Control messages can appear in the middle of other messages
            // and must not be compressed. Pass it straight through
            allCompressedParts.add(uncompressedPart);
        } else if (emptyMessage && uncompressedPart.isFin()) {
            // Zero length messages can't be compressed so pass the
            // final (empty) part straight through.
            allCompressedParts.add(uncompressedPart);
        } else {
            List<MessagePart> compressedParts = new ArrayList<>();
            ByteBuffer uncompressedPayload = uncompressedPart.getPayload();
            SendHandler uncompressedIntermediateHandler = uncompressedPart.getIntermediateHandler();
            deflater.setInput(uncompressedPayload.array(), uncompressedPayload.arrayOffset() + uncompressedPayload.position(), uncompressedPayload.remaining());
            int flush = (uncompressedPart.isFin() ? Deflater.SYNC_FLUSH : Deflater.NO_FLUSH);
            boolean deflateRequired = true;
            while (deflateRequired) {
                ByteBuffer compressedPayload = writeBuffer;
                try {
                    int written = deflater.deflate(compressedPayload.array(), compressedPayload.arrayOffset() + compressedPayload.position(), compressedPayload.remaining(), flush);
                    compressedPayload.position(compressedPayload.position() + written);
                } catch (NullPointerException e) {
                    throw new IOException(sm.getString("perMessageDeflate.alreadyClosed"), e);
                }
                if (!uncompressedPart.isFin() && compressedPayload.hasRemaining() && deflater.needsInput()) {
                    // and move on to the next message part.
                    break;
                }
                // If this point is reached, a new compressed message part
                // will be created...
                MessagePart compressedPart;
                // .. and a new writeBuffer will be required.
                writeBuffer = ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE);
                // Flip the compressed payload ready for writing
                compressedPayload.flip();
                boolean fin = uncompressedPart.isFin();
                boolean full = compressedPayload.limit() == compressedPayload.capacity();
                boolean needsInput = deflater.needsInput();
                long blockingWriteTimeoutExpiry = uncompressedPart.getBlockingWriteTimeoutExpiry();
                if (fin && !full && needsInput) {
                    // End of compressed message. Drop EOM bytes and output.
                    compressedPayload.limit(compressedPayload.limit() - EOM_BYTES.length);
                    compressedPart = new MessagePart(true, getRsv(uncompressedPart), opCode, compressedPayload, uncompressedIntermediateHandler, uncompressedIntermediateHandler, blockingWriteTimeoutExpiry);
                    deflateRequired = false;
                    startNewMessage();
                } else if (full && !needsInput) {
                    // Write buffer full and input message not fully read.
                    // Output and start new compressed part.
                    compressedPart = new MessagePart(false, getRsv(uncompressedPart), opCode, compressedPayload, uncompressedIntermediateHandler, uncompressedIntermediateHandler, blockingWriteTimeoutExpiry);
                } else if (!fin && full && needsInput) {
                    // Write buffer full and input message not fully read.
                    // Output and get more data.
                    compressedPart = new MessagePart(false, getRsv(uncompressedPart), opCode, compressedPayload, uncompressedIntermediateHandler, uncompressedIntermediateHandler, blockingWriteTimeoutExpiry);
                    deflateRequired = false;
                } else if (fin && full && needsInput) {
                    // Write buffer full. Input fully read. Deflater may be
                    // in one of four states:
                    // - output complete (just happened to align with end of
                    // buffer
                    // - in middle of EOM bytes
                    // - about to write EOM bytes
                    // - more data to write
                    int eomBufferWritten;
                    try {
                        eomBufferWritten = deflater.deflate(EOM_BUFFER, 0, EOM_BUFFER.length, Deflater.SYNC_FLUSH);
                    } catch (NullPointerException e) {
                        throw new IOException(sm.getString("perMessageDeflate.alreadyClosed"), e);
                    }
                    if (eomBufferWritten < EOM_BUFFER.length) {
                        // EOM has just been completed
                        compressedPayload.limit(compressedPayload.limit() - EOM_BYTES.length + eomBufferWritten);
                        compressedPart = new MessagePart(true, getRsv(uncompressedPart), opCode, compressedPayload, uncompressedIntermediateHandler, uncompressedIntermediateHandler, blockingWriteTimeoutExpiry);
                        deflateRequired = false;
                        startNewMessage();
                    } else {
                        // More data to write
                        // Copy bytes to new write buffer
                        writeBuffer.put(EOM_BUFFER, 0, eomBufferWritten);
                        compressedPart = new MessagePart(false, getRsv(uncompressedPart), opCode, compressedPayload, uncompressedIntermediateHandler, uncompressedIntermediateHandler, blockingWriteTimeoutExpiry);
                    }
                } else {
                    throw new IllegalStateException(sm.getString("perMessageDeflate.invalidState"));
                }
                // Add the newly created compressed part to the set of parts
                // to pass on to the next transformation.
                compressedParts.add(compressedPart);
            }
            SendHandler uncompressedEndHandler = uncompressedPart.getEndHandler();
            int size = compressedParts.size();
            if (size > 0) {
                compressedParts.get(size - 1).setEndHandler(uncompressedEndHandler);
            }
            allCompressedParts.addAll(compressedParts);
        }
    }
    if (next == null) {
        return allCompressedParts;
    } else {
        return next.sendMessagePart(allCompressedParts);
    }
}
Also used : SendHandler(jakarta.websocket.SendHandler) ArrayList(java.util.ArrayList) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) List(java.util.List) ArrayList(java.util.ArrayList)

Example 3 with SendHandler

use of jakarta.websocket.SendHandler in project tomcat by apache.

the class WsRemoteEndpointImplBase method writeMessagePart.

void writeMessagePart(MessagePart mp) {
    if (closed) {
        throw new IllegalStateException(sm.getString("wsRemoteEndpoint.closed"));
    }
    if (Constants.INTERNAL_OPCODE_FLUSH == mp.getOpCode()) {
        nextFragmented = fragmented;
        nextText = text;
        outputBuffer.flip();
        SendHandler flushHandler = new OutputBufferFlushSendHandler(outputBuffer, mp.getEndHandler());
        doWrite(flushHandler, mp.getBlockingWriteTimeoutExpiry(), outputBuffer);
        return;
    }
    // Control messages may be sent in the middle of fragmented message
    // so they have no effect on the fragmented or text flags
    boolean first;
    if (Util.isControl(mp.getOpCode())) {
        nextFragmented = fragmented;
        nextText = text;
        if (mp.getOpCode() == Constants.OPCODE_CLOSE) {
            closed = true;
        }
        first = true;
    } else {
        boolean isText = Util.isText(mp.getOpCode());
        if (fragmented) {
            // Currently fragmented
            if (text != isText) {
                throw new IllegalStateException(sm.getString("wsRemoteEndpoint.changeType"));
            }
            nextText = text;
            nextFragmented = !mp.isFin();
            first = false;
        } else {
            // Wasn't fragmented. Might be now
            if (mp.isFin()) {
                nextFragmented = false;
            } else {
                nextFragmented = true;
                nextText = isText;
            }
            first = true;
        }
    }
    byte[] mask;
    if (isMasked()) {
        mask = Util.generateMask();
    } else {
        mask = null;
    }
    int payloadSize = mp.getPayload().remaining();
    headerBuffer.clear();
    writeHeader(headerBuffer, mp.isFin(), mp.getRsv(), mp.getOpCode(), isMasked(), mp.getPayload(), mask, first);
    headerBuffer.flip();
    if (getBatchingAllowed() || isMasked()) {
        // Need to write via output buffer
        OutputBufferSendHandler obsh = new OutputBufferSendHandler(mp.getEndHandler(), mp.getBlockingWriteTimeoutExpiry(), headerBuffer, mp.getPayload(), mask, outputBuffer, !getBatchingAllowed(), this);
        obsh.write();
    } else {
        // Can write directly
        doWrite(mp.getEndHandler(), mp.getBlockingWriteTimeoutExpiry(), headerBuffer, mp.getPayload());
    }
    updateStats(payloadSize);
}
Also used : SendHandler(jakarta.websocket.SendHandler) RemoteEndpoint(jakarta.websocket.RemoteEndpoint)

Aggregations

SendHandler (jakarta.websocket.SendHandler)3 RemoteEndpoint (jakarta.websocket.RemoteEndpoint)1 SendResult (jakarta.websocket.SendResult)1 IOException (java.io.IOException)1 ByteBuffer (java.nio.ByteBuffer)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 RejectedExecutionException (java.util.concurrent.RejectedExecutionException)1