Search in sources :

Example 51 with PooledByteBuffer

use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.

the class BlockingSenderImpl method performTransfer.

private void performTransfer(FileChannel source, IoCallback callback) {
    if (outputStream instanceof BufferWritableOutputStream) {
        try {
            ((BufferWritableOutputStream) outputStream).transferFrom(source);
        } catch (IOException e) {
            callback.onException(exchange, this, e);
        }
    } else {
        try (PooledByteBuffer pooled = exchange.getConnection().getByteBufferPool().getArrayBackedPool().allocate()) {
            ByteBuffer buffer = pooled.getBuffer();
            long pos = source.position();
            long size = source.size();
            while (size - pos > 0) {
                int ret = source.read(buffer);
                if (ret <= 0) {
                    break;
                }
                pos += ret;
                outputStream.write(buffer.array(), buffer.arrayOffset(), ret);
                buffer.clear();
            }
            if (pos != size) {
                throw new EOFException("Unexpected EOF reading file");
            }
        } catch (IOException e) {
            callback.onException(exchange, this, e);
        }
    }
}
Also used : PooledByteBuffer(io.undertow.connector.PooledByteBuffer) EOFException(java.io.EOFException) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer)

Example 52 with PooledByteBuffer

use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.

the class ChunkedStreamSinkConduit method createLastChunk.

private void createLastChunk(final boolean writeFinal) throws UnsupportedEncodingException {
    PooledByteBuffer lastChunkBufferPooled = bufferPool.allocate();
    ByteBuffer lastChunkBuffer = lastChunkBufferPooled.getBuffer();
    if (writeFinal) {
        lastChunkBuffer.put(CRLF);
    } else if (chunkingSepBuffer.hasRemaining()) {
        // the end of chunk /r/n has not been written yet
        // just add it to this buffer to make managing state easier
        lastChunkBuffer.put(chunkingSepBuffer);
    }
    lastChunkBuffer.put(LAST_CHUNK);
    // we just assume it will fit
    HeaderMap attachment = attachable.getAttachment(HttpAttachments.RESPONSE_TRAILERS);
    final HeaderMap trailers;
    Supplier<HeaderMap> supplier = attachable.getAttachment(HttpAttachments.RESPONSE_TRAILER_SUPPLIER);
    if (attachment != null && supplier == null) {
        trailers = attachment;
    } else if (attachment == null && supplier != null) {
        trailers = supplier.get();
    } else if (attachment != null) {
        HeaderMap supplied = supplier.get();
        for (HeaderValues k : supplied) {
            attachment.putAll(k.getHeaderName(), k);
        }
        trailers = attachment;
    } else {
        trailers = null;
    }
    if (trailers != null && trailers.size() != 0) {
        for (HeaderValues trailer : trailers) {
            for (String val : trailer) {
                trailer.getHeaderName().appendTo(lastChunkBuffer);
                lastChunkBuffer.put((byte) ':');
                lastChunkBuffer.put((byte) ' ');
                lastChunkBuffer.put(val.getBytes(StandardCharsets.US_ASCII));
                lastChunkBuffer.put(CRLF);
            }
        }
        lastChunkBuffer.put(CRLF);
    } else {
        lastChunkBuffer.put(CRLF);
    }
    // horrible hack
    // there is a situation where we can get a buffer leak here if the connection is terminated abnormaly
    // this should be fixed once this channel has its lifecycle tied to the connection, same as fixed length
    lastChunkBuffer.flip();
    ByteBuffer data = ByteBuffer.allocate(lastChunkBuffer.remaining());
    data.put(lastChunkBuffer);
    data.flip();
    this.lastChunkBuffer = new ImmediatePooledByteBuffer(data);
    lastChunkBufferPooled.close();
}
Also used : HeaderMap(io.undertow.util.HeaderMap) ImmediatePooledByteBuffer(io.undertow.util.ImmediatePooledByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) HeaderValues(io.undertow.util.HeaderValues) ByteBuffer(java.nio.ByteBuffer) ImmediatePooledByteBuffer(io.undertow.util.ImmediatePooledByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ImmediatePooledByteBuffer(io.undertow.util.ImmediatePooledByteBuffer)

Example 53 with PooledByteBuffer

use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.

the class AjpServerResponseConduit method processAJPHeader.

/**
 * Handles generating the header if required, and adding it to the frame queue.
 *
 * No attempt is made to actually flush this, so a gathering write can be used to actually flush the data
 */
private void processAJPHeader() {
    int oldState = this.state;
    if (anyAreSet(oldState, FLAG_START)) {
        PooledByteBuffer[] byteBuffers = null;
        // merge the cookies into the header map
        Connectors.flattenCookies(exchange);
        PooledByteBuffer pooled = pool.allocate();
        ByteBuffer buffer = pooled.getBuffer();
        buffer.put((byte) 'A');
        buffer.put((byte) 'B');
        // we fill the size in later
        buffer.put((byte) 0);
        buffer.put((byte) 0);
        buffer.put((byte) 4);
        putInt(buffer, exchange.getStatusCode());
        String reason = exchange.getReasonPhrase();
        if (reason == null) {
            reason = StatusCodes.getReason(exchange.getStatusCode());
        }
        if (reason.length() + 4 > buffer.remaining()) {
            pooled.close();
            throw UndertowMessages.MESSAGES.reasonPhraseToLargeForBuffer(reason);
        }
        putString(buffer, reason);
        int headers = 0;
        // we need to count the headers
        final HeaderMap responseHeaders = exchange.getResponseHeaders();
        for (HttpString name : responseHeaders.getHeaderNames()) {
            headers += responseHeaders.get(name).size();
        }
        putInt(buffer, headers);
        for (final HttpString header : responseHeaders.getHeaderNames()) {
            for (String headerValue : responseHeaders.get(header)) {
                if (buffer.remaining() < header.length() + headerValue.length() + 6) {
                    // if there is not enough room in the buffer we need to allocate more
                    buffer.flip();
                    if (byteBuffers == null) {
                        byteBuffers = new PooledByteBuffer[2];
                        byteBuffers[0] = pooled;
                    } else {
                        PooledByteBuffer[] old = byteBuffers;
                        byteBuffers = new PooledByteBuffer[old.length + 1];
                        System.arraycopy(old, 0, byteBuffers, 0, old.length);
                    }
                    pooled = pool.allocate();
                    byteBuffers[byteBuffers.length - 1] = pooled;
                    buffer = pooled.getBuffer();
                }
                Integer headerCode = HEADER_MAP.get(header);
                if (headerCode != null) {
                    putInt(buffer, headerCode);
                } else {
                    putHttpString(buffer, header);
                }
                putString(buffer, headerValue);
            }
        }
        if (byteBuffers == null) {
            int dataLength = buffer.position() - 4;
            buffer.put(2, (byte) ((dataLength >> 8) & 0xFF));
            buffer.put(3, (byte) (dataLength & 0xFF));
            buffer.flip();
            queueFrame(new PooledBufferFrameCallback(pooled), buffer);
        } else {
            ByteBuffer[] bufs = new ByteBuffer[byteBuffers.length];
            for (int i = 0; i < bufs.length; ++i) {
                bufs[i] = byteBuffers[i].getBuffer();
            }
            int dataLength = (int) (Buffers.remaining(bufs) - 4);
            bufs[0].put(2, (byte) ((dataLength >> 8) & 0xFF));
            bufs[0].put(3, (byte) (dataLength & 0xFF));
            buffer.flip();
            queueFrame(new PooledBuffersFrameCallback(byteBuffers), bufs);
        }
        state &= ~FLAG_START;
    }
}
Also used : HeaderMap(io.undertow.util.HeaderMap) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) HttpString(io.undertow.util.HttpString) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) HttpString(io.undertow.util.HttpString)

Example 54 with PooledByteBuffer

use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.

the class AjpServerResponseConduit method write.

public int write(final ByteBuffer src) throws IOException {
    if (queuedDataLength() > 0) {
        // otherwise the queue can grow indefinitely
        if (!flushQueuedData()) {
            return 0;
        }
    }
    processAJPHeader();
    if (headRequest) {
        int remaining = src.remaining();
        src.position(src.position() + remaining);
        return remaining;
    }
    int limit = src.limit();
    try {
        int maxData = exchange.getConnection().getUndertowOptions().get(UndertowOptions.MAX_AJP_PACKET_SIZE, DEFAULT_MAX_DATA_SIZE) - 8;
        if (src.remaining() > maxData) {
            src.limit(src.position() + maxData);
        }
        final int writeSize = src.remaining();
        final ByteBuffer[] buffers = createHeader(src);
        int toWrite = 0;
        for (ByteBuffer buffer : buffers) {
            toWrite += buffer.remaining();
        }
        final int originalPayloadSize = writeSize;
        long r = 0;
        do {
            r = super.write(buffers, 0, buffers.length);
            toWrite -= r;
            if (r == -1) {
                throw new ClosedChannelException();
            } else if (r == 0) {
                // we need to copy all the remaining bytes
                // TODO: this assumes the buffer is big enough
                PooledByteBuffer newPooledBuffer = pool.allocate();
                while (src.hasRemaining()) {
                    newPooledBuffer.getBuffer().put(src);
                }
                newPooledBuffer.getBuffer().flip();
                ByteBuffer[] savedBuffers = new ByteBuffer[3];
                savedBuffers[0] = buffers[0];
                savedBuffers[1] = newPooledBuffer.getBuffer();
                savedBuffers[2] = buffers[2];
                queueFrame(new PooledBufferFrameCallback(newPooledBuffer), savedBuffers);
                return originalPayloadSize;
            }
        } while (toWrite > 0);
        return originalPayloadSize;
    } catch (IOException | RuntimeException e) {
        IoUtils.safeClose(exchange.getConnection());
        throw e;
    } finally {
        src.limit(limit);
    }
}
Also used : ClosedChannelException(java.nio.channels.ClosedChannelException) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer)

Example 55 with PooledByteBuffer

use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.

the class AjpReadListener method handleEvent.

public void handleEvent(final StreamSourceChannel channel) {
    if (connection.getOriginalSinkConduit().isWriteShutdown() || connection.getOriginalSourceConduit().isReadShutdown()) {
        safeClose(connection);
        channel.suspendReads();
        return;
    }
    PooledByteBuffer existing = connection.getExtraBytes();
    final PooledByteBuffer pooled = existing == null ? connection.getByteBufferPool().allocate() : existing;
    final ByteBuffer buffer = pooled.getBuffer();
    boolean free = true;
    boolean bytesRead = false;
    try {
        int res;
        do {
            if (existing == null) {
                buffer.clear();
                res = channel.read(buffer);
            } else {
                res = buffer.remaining();
            }
            if (res == 0) {
                if (bytesRead && parseTimeoutUpdater != null) {
                    parseTimeoutUpdater.failedParse();
                }
                if (!channel.isReadResumed()) {
                    channel.getReadSetter().set(this);
                    channel.resumeReads();
                }
                return;
            }
            if (res == -1) {
                channel.shutdownReads();
                final StreamSinkChannel responseChannel = connection.getChannel().getSinkChannel();
                responseChannel.shutdownWrites();
                safeClose(connection);
                return;
            }
            bytesRead = true;
            // TODO: we need to handle parse errors
            if (existing != null) {
                existing = null;
                connection.setExtraBytes(null);
            } else {
                buffer.flip();
            }
            int begin = buffer.remaining();
            if (httpServerExchange == null) {
                httpServerExchange = new HttpServerExchange(connection, maxEntitySize);
            }
            parser.parse(buffer, state, httpServerExchange);
            read += begin - buffer.remaining();
            if (buffer.hasRemaining()) {
                free = false;
                connection.setExtraBytes(pooled);
            }
            if (read > maxRequestSize) {
                UndertowLogger.REQUEST_LOGGER.requestHeaderWasTooLarge(connection.getPeerAddress(), maxRequestSize);
                safeClose(connection);
                return;
            }
        } while (!state.isComplete());
        if (parseTimeoutUpdater != null) {
            parseTimeoutUpdater.requestStarted();
        }
        if (state.prefix != AjpRequestParser.FORWARD_REQUEST) {
            if (state.prefix == AjpRequestParser.CPING) {
                UndertowLogger.REQUEST_LOGGER.debug("Received CPING, sending CPONG");
                handleCPing();
            } else if (state.prefix == AjpRequestParser.CPONG) {
                UndertowLogger.REQUEST_LOGGER.debug("Received CPONG, starting next request");
                state = new AjpRequestParseState();
                channel.getReadSetter().set(this);
                channel.resumeReads();
            } else {
                UndertowLogger.REQUEST_LOGGER.ignoringAjpRequestWithPrefixCode(state.prefix);
                safeClose(connection);
            }
            return;
        }
        // we remove ourselves as the read listener from the channel;
        // if the http handler doesn't set any then reads will suspend, which is the right thing to do
        channel.getReadSetter().set(null);
        channel.suspendReads();
        final HttpServerExchange httpServerExchange = this.httpServerExchange;
        final AjpServerResponseConduit responseConduit = new AjpServerResponseConduit(connection.getChannel().getSinkChannel().getConduit(), connection.getByteBufferPool(), httpServerExchange, new ConduitListener<AjpServerResponseConduit>() {

            @Override
            public void handleEvent(AjpServerResponseConduit channel) {
                Connectors.terminateResponse(httpServerExchange);
            }
        }, httpServerExchange.getRequestMethod().equals(Methods.HEAD));
        connection.getChannel().getSinkChannel().setConduit(responseConduit);
        connection.getChannel().getSourceChannel().setConduit(createSourceConduit(connection.getChannel().getSourceChannel().getConduit(), responseConduit, httpServerExchange));
        // we need to set the write ready handler. This allows the response conduit to wrap it
        responseConduit.setWriteReadyHandler(writeReadyHandler);
        connection.setSSLSessionInfo(state.createSslSessionInfo());
        httpServerExchange.setSourceAddress(state.createPeerAddress());
        httpServerExchange.setDestinationAddress(state.createDestinationAddress());
        if (scheme != null) {
            httpServerExchange.setRequestScheme(scheme);
        }
        if (state.attributes != null) {
            httpServerExchange.putAttachment(HttpServerExchange.REQUEST_ATTRIBUTES, state.attributes);
        }
        AjpRequestParseState oldState = state;
        state = null;
        this.httpServerExchange = null;
        httpServerExchange.setPersistent(true);
        if (recordRequestStartTime) {
            Connectors.setRequestStartTime(httpServerExchange);
        }
        connection.setCurrentExchange(httpServerExchange);
        if (connectorStatistics != null) {
            connectorStatistics.setup(httpServerExchange);
        }
        if (!Connectors.areRequestHeadersValid(httpServerExchange.getRequestHeaders())) {
            oldState.badRequest = true;
            UndertowLogger.REQUEST_IO_LOGGER.debugf("Invalid AJP request from %s, request contained invalid headers", connection.getPeerAddress());
        }
        if (oldState.badRequest) {
            httpServerExchange.setStatusCode(StatusCodes.BAD_REQUEST);
            httpServerExchange.endExchange();
            handleBadRequest();
            safeClose(connection);
        } else {
            Connectors.executeRootHandler(connection.getRootHandler(), httpServerExchange);
        }
    } catch (BadRequestException e) {
        UndertowLogger.REQUEST_IO_LOGGER.failedToParseRequest(e);
        handleBadRequest();
        safeClose(connection);
    } catch (IOException e) {
        UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
        handleInternalServerError();
        safeClose(connection);
    } catch (Throwable t) {
        UndertowLogger.REQUEST_LOGGER.exceptionProcessingRequest(t);
        handleInternalServerError();
        safeClose(connection);
    } finally {
        if (free)
            pooled.close();
    }
}
Also used : StreamSinkChannel(org.xnio.channels.StreamSinkChannel) ConduitStreamSinkChannel(org.xnio.conduits.ConduitStreamSinkChannel) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) HttpServerExchange(io.undertow.server.HttpServerExchange) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) BadRequestException(io.undertow.util.BadRequestException)

Aggregations

PooledByteBuffer (io.undertow.connector.PooledByteBuffer)58 ByteBuffer (java.nio.ByteBuffer)47 IOException (java.io.IOException)29 ImmediatePooledByteBuffer (io.undertow.util.ImmediatePooledByteBuffer)10 StreamSourceChannel (org.xnio.channels.StreamSourceChannel)8 HttpServerExchange (io.undertow.server.HttpServerExchange)7 ClosedChannelException (java.nio.channels.ClosedChannelException)7 ByteArrayOutputStream (java.io.ByteArrayOutputStream)5 ChannelListener (org.xnio.ChannelListener)5 HttpHandler (io.undertow.server.HttpHandler)4 HeaderMap (io.undertow.util.HeaderMap)4 StreamSinkChannel (org.xnio.channels.StreamSinkChannel)4 SendFrameHeader (io.undertow.server.protocol.framed.SendFrameHeader)3 HttpString (io.undertow.util.HttpString)3 ByteBufferPool (io.undertow.connector.ByteBufferPool)2 HeaderValues (io.undertow.util.HeaderValues)2 InterruptedIOException (java.io.InterruptedIOException)2 CharBuffer (java.nio.CharBuffer)2 CharsetDecoder (java.nio.charset.CharsetDecoder)2 IoCallback (io.undertow.io.IoCallback)1