Search in sources :

Example 26 with HttpString

use of io.undertow.util.HttpString in project undertow by undertow-io.

the class HttpRequestParser method handleHeaderValueCacheMiss.

private void handleHeaderValueCacheMiss(ByteBuffer buffer, ParseState state, HttpServerExchange builder, HttpString headerName, HashMap<HttpString, String> headerValuesCache, StringBuilder stringBuilder) throws BadRequestException {
    int parseState = state.parseState;
    while (buffer.hasRemaining() && parseState == NORMAL) {
        final byte next = buffer.get();
        if (next == '\r') {
            parseState = BEGIN_LINE_END;
        } else if (next == '\n') {
            parseState = LINE_END;
        } else if (next == ' ' || next == '\t') {
            parseState = WHITESPACE;
        } else {
            stringBuilder.append((char) (next & 0xFF));
        }
    }
    while (buffer.hasRemaining()) {
        final byte next = buffer.get();
        switch(parseState) {
            case NORMAL:
                {
                    if (next == '\r') {
                        parseState = BEGIN_LINE_END;
                    } else if (next == '\n') {
                        parseState = LINE_END;
                    } else if (next == ' ' || next == '\t') {
                        parseState = WHITESPACE;
                    } else {
                        stringBuilder.append((char) (next & 0xFF));
                    }
                    break;
                }
            case WHITESPACE:
                {
                    if (next == '\r') {
                        parseState = BEGIN_LINE_END;
                    } else if (next == '\n') {
                        parseState = LINE_END;
                    } else if (next == ' ' || next == '\t') {
                    } else {
                        if (stringBuilder.length() > 0) {
                            stringBuilder.append(' ');
                        }
                        stringBuilder.append((char) (next & 0xFF));
                        parseState = NORMAL;
                    }
                    break;
                }
            case LINE_END:
            case BEGIN_LINE_END:
                {
                    if (next == '\n' && parseState == BEGIN_LINE_END) {
                        parseState = LINE_END;
                    } else if (next == '\t' || next == ' ') {
                        //this is a continuation
                        parseState = WHITESPACE;
                    } else {
                        //we have a header
                        String headerValue = stringBuilder.toString();
                        if (++state.mapCount > maxHeaders) {
                            throw new BadRequestException(UndertowMessages.MESSAGES.tooManyHeaders(maxHeaders));
                        }
                        //TODO: we need to decode this according to RFC-2047 if we have seen a =? symbol
                        builder.getRequestHeaders().add(headerName, headerValue);
                        if (headerValuesCache.size() < maxHeaders) {
                            //we have a limit on how many we can cache
                            //to prevent memory filling and hash collision attacks
                            headerValuesCache.put(headerName, headerValue);
                        }
                        state.nextHeader = null;
                        state.leftOver = next;
                        state.stringBuilder.setLength(0);
                        if (next == '\r') {
                            parseState = AWAIT_DATA_END;
                        } else if (next == '\n') {
                            state.state = ParseState.PARSE_COMPLETE;
                            return;
                        } else {
                            state.state = ParseState.HEADER;
                            state.parseState = 0;
                            return;
                        }
                    }
                    break;
                }
            case AWAIT_DATA_END:
                {
                    state.state = ParseState.PARSE_COMPLETE;
                    return;
                }
        }
    }
    //we only write to the state if we did not finish parsing
    state.parseState = parseState;
}
Also used : HttpString(io.undertow.util.HttpString)

Example 27 with HttpString

use of io.undertow.util.HttpString in project undertow by undertow-io.

the class HttpResponseConduit method processWrite.

/**
     * Handles writing out the header data. It can also take a byte buffer of user
     * data, to enable both user data and headers to be written out in a single operation,
     * which has a noticeable performance impact.
     * <p/>
     * It is up to the caller to note the current position of this buffer before and after they
     * call this method, and use this to figure out how many bytes (if any) have been written.
     *
     * @param state
     * @param userData
     * @return
     * @throws IOException
     */
private int processWrite(int state, final Object userData, int pos, int length) throws IOException {
    if (done || exchange == null) {
        throw new ClosedChannelException();
    }
    try {
        assert state != STATE_BODY;
        if (state == STATE_BUF_FLUSH) {
            final ByteBuffer byteBuffer = pooledBuffer.getBuffer();
            do {
                long res = 0;
                ByteBuffer[] data;
                if (userData == null || length == 0) {
                    res = next.write(byteBuffer);
                } else if (userData instanceof ByteBuffer) {
                    data = writevBuffer;
                    if (data == null) {
                        data = writevBuffer = new ByteBuffer[2];
                    }
                    data[0] = byteBuffer;
                    data[1] = (ByteBuffer) userData;
                    res = next.write(data, 0, 2);
                } else {
                    data = writevBuffer;
                    if (data == null || data.length < length + 1) {
                        data = writevBuffer = new ByteBuffer[length + 1];
                    }
                    data[0] = byteBuffer;
                    System.arraycopy(userData, pos, data, 1, length);
                    res = next.write(data, 0, data.length);
                }
                if (res == 0) {
                    return STATE_BUF_FLUSH;
                }
            } while (byteBuffer.hasRemaining());
            bufferDone();
            return STATE_BODY;
        } else if (state != STATE_START) {
            return processStatefulWrite(state, userData, pos, length);
        }
        //merge the cookies into the header map
        Connectors.flattenCookies(exchange);
        if (pooledBuffer == null) {
            pooledBuffer = pool.allocate();
        }
        ByteBuffer buffer = pooledBuffer.getBuffer();
        assert buffer.remaining() >= 50;
        exchange.getProtocol().appendTo(buffer);
        buffer.put((byte) ' ');
        int code = exchange.getStatusCode();
        assert 999 >= code && code >= 100;
        buffer.put((byte) (code / 100 + '0'));
        buffer.put((byte) (code / 10 % 10 + '0'));
        buffer.put((byte) (code % 10 + '0'));
        buffer.put((byte) ' ');
        String string = exchange.getReasonPhrase();
        if (string == null) {
            string = StatusCodes.getReason(code);
        }
        if (string.length() > buffer.remaining()) {
            pooledBuffer.close();
            pooledBuffer = null;
            truncateWrites();
            throw UndertowMessages.MESSAGES.reasonPhraseToLargeForBuffer(string);
        }
        writeString(buffer, string);
        buffer.put((byte) '\r').put((byte) '\n');
        int remaining = buffer.remaining();
        HeaderMap headers = exchange.getResponseHeaders();
        long fiCookie = headers.fastIterateNonEmpty();
        while (fiCookie != -1) {
            HeaderValues headerValues = headers.fiCurrent(fiCookie);
            HttpString header = headerValues.getHeaderName();
            int headerSize = header.length();
            int valueIdx = 0;
            while (valueIdx < headerValues.size()) {
                remaining -= (headerSize + 2);
                if (remaining < 0) {
                    this.fiCookie = fiCookie;
                    this.string = string;
                    this.headerValues = headerValues;
                    this.valueIdx = valueIdx;
                    this.charIndex = 0;
                    this.state = STATE_HDR_NAME;
                    buffer.flip();
                    return processStatefulWrite(STATE_HDR_NAME, userData, pos, length);
                }
                header.appendTo(buffer);
                buffer.put((byte) ':').put((byte) ' ');
                string = headerValues.get(valueIdx++);
                remaining -= (string.length() + 2);
                if (remaining < 2) {
                    //we use 2 here, to make sure we always have room for the final \r\n
                    this.fiCookie = fiCookie;
                    this.string = string;
                    this.headerValues = headerValues;
                    this.valueIdx = valueIdx;
                    this.charIndex = 0;
                    this.state = STATE_HDR_VAL;
                    buffer.flip();
                    return processStatefulWrite(STATE_HDR_VAL, userData, pos, length);
                }
                writeString(buffer, string);
                buffer.put((byte) '\r').put((byte) '\n');
            }
            fiCookie = headers.fiNextNonEmpty(fiCookie);
        }
        buffer.put((byte) '\r').put((byte) '\n');
        buffer.flip();
        do {
            long res = 0;
            ByteBuffer[] data;
            if (userData == null) {
                res = next.write(buffer);
            } else if (userData instanceof ByteBuffer) {
                data = writevBuffer;
                if (data == null) {
                    data = writevBuffer = new ByteBuffer[2];
                }
                data[0] = buffer;
                data[1] = (ByteBuffer) userData;
                res = next.write(data, 0, 2);
            } else {
                data = writevBuffer;
                if (data == null || data.length < length + 1) {
                    data = writevBuffer = new ByteBuffer[length + 1];
                }
                data[0] = buffer;
                System.arraycopy(userData, pos, data, 1, length);
                res = next.write(data, 0, length + 1);
            }
            if (res == 0) {
                return STATE_BUF_FLUSH;
            }
        } while (buffer.hasRemaining());
        bufferDone();
        return STATE_BODY;
    } catch (IOException | RuntimeException e) {
        //WFLY-4696, just to be safe
        if (pooledBuffer != null) {
            pooledBuffer.close();
            pooledBuffer = null;
        }
        throw e;
    }
}
Also used : ClosedChannelException(java.nio.channels.ClosedChannelException) HeaderMap(io.undertow.util.HeaderMap) HeaderValues(io.undertow.util.HeaderValues) HttpString(io.undertow.util.HttpString) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) HttpString(io.undertow.util.HttpString)

Example 28 with HttpString

use of io.undertow.util.HttpString in project undertow by undertow-io.

the class HttpServerConnection method sendOutOfBandResponse.

@Override
public HttpServerExchange sendOutOfBandResponse(HttpServerExchange exchange) {
    if (exchange == null || !HttpContinue.requiresContinueResponse(exchange)) {
        throw UndertowMessages.MESSAGES.outOfBandResponseOnlyAllowedFor100Continue();
    }
    final ConduitState state = resetChannel();
    HttpServerExchange newExchange = new HttpServerExchange(this);
    for (HttpString header : exchange.getRequestHeaders().getHeaderNames()) {
        newExchange.getRequestHeaders().putAll(header, exchange.getRequestHeaders().get(header));
    }
    newExchange.setProtocol(exchange.getProtocol());
    newExchange.setRequestMethod(exchange.getRequestMethod());
    exchange.setRequestURI(exchange.getRequestURI(), exchange.isHostIncludedInRequestURI());
    exchange.setRequestPath(exchange.getRequestPath());
    exchange.setRelativePath(exchange.getRelativePath());
    newExchange.getRequestHeaders().put(Headers.CONNECTION, Headers.KEEP_ALIVE.toString());
    newExchange.getRequestHeaders().put(Headers.CONTENT_LENGTH, 0);
    newExchange.setPersistent(true);
    Connectors.terminateRequest(newExchange);
    newExchange.addResponseWrapper(new ConduitWrapper<StreamSinkConduit>() {

        @Override
        public StreamSinkConduit wrap(ConduitFactory<StreamSinkConduit> factory, HttpServerExchange exchange) {
            ServerFixedLengthStreamSinkConduit fixed = new ServerFixedLengthStreamSinkConduit(new HttpResponseConduit(getSinkChannel().getConduit(), getByteBufferPool(), HttpServerConnection.this, exchange), false, false);
            fixed.reset(0, exchange);
            return fixed;
        }
    });
    //we restore the read channel immediately, as this out of band response has no read side
    channel.getSourceChannel().setConduit(source(state));
    newExchange.addExchangeCompleteListener(new ExchangeCompletionListener() {

        @Override
        public void exchangeEvent(HttpServerExchange exchange, NextListener nextListener) {
            restoreChannel(state);
        }
    });
    return newExchange;
}
Also used : HttpServerExchange(io.undertow.server.HttpServerExchange) StreamSinkConduit(org.xnio.conduits.StreamSinkConduit) ExchangeCompletionListener(io.undertow.server.ExchangeCompletionListener) HttpString(io.undertow.util.HttpString)

Example 29 with HttpString

use of io.undertow.util.HttpString in project undertow by undertow-io.

the class HttpTransferEncoding method handleRequestEncoding.

private static boolean handleRequestEncoding(final HttpServerExchange exchange, String transferEncodingHeader, String contentLengthHeader, HttpServerConnection connection, PipeliningBufferingStreamSinkConduit pipeliningBuffer, boolean persistentConnection) {
    HttpString transferEncoding = Headers.IDENTITY;
    if (transferEncodingHeader != null) {
        transferEncoding = new HttpString(transferEncodingHeader);
    }
    if (transferEncodingHeader != null && !transferEncoding.equals(Headers.IDENTITY)) {
        ConduitStreamSourceChannel sourceChannel = ((HttpServerConnection) exchange.getConnection()).getChannel().getSourceChannel();
        sourceChannel.setConduit(new ChunkedStreamSourceConduit(sourceChannel.getConduit(), exchange, chunkedDrainListener(exchange)));
    } else if (contentLengthHeader != null) {
        final long contentLength;
        contentLength = parsePositiveLong(contentLengthHeader);
        if (contentLength == 0L) {
            log.trace("No content, starting next request");
            // no content - immediately start the next request, returning an empty stream for this one
            Connectors.terminateRequest(exchange);
        } else {
            // fixed-length content - add a wrapper for a fixed-length stream
            ConduitStreamSourceChannel sourceChannel = ((HttpServerConnection) exchange.getConnection()).getChannel().getSourceChannel();
            sourceChannel.setConduit(fixedLengthStreamSourceConduitWrapper(contentLength, sourceChannel.getConduit(), exchange));
        }
    } else if (transferEncodingHeader != null) {
        //identity transfer encoding
        log.trace("Connection not persistent (no content length and identity transfer encoding)");
        // make it not persistent
        persistentConnection = false;
    } else if (persistentConnection) {
        //performance
        if (connection.getExtraBytes() != null && pipeliningBuffer == null && connection.getUndertowOptions().get(UndertowOptions.BUFFER_PIPELINED_DATA, false)) {
            pipeliningBuffer = new PipeliningBufferingStreamSinkConduit(connection.getOriginalSinkConduit(), connection.getByteBufferPool());
            connection.setPipelineBuffer(pipeliningBuffer);
            pipeliningBuffer.setupPipelineBuffer(exchange);
        }
        // no content - immediately start the next request, returning an empty stream for this one
        Connectors.terminateRequest(exchange);
    } else {
        //assume there is no content
        //we still know there is no content
        Connectors.terminateRequest(exchange);
    }
    return persistentConnection;
}
Also used : ConduitStreamSourceChannel(org.xnio.conduits.ConduitStreamSourceChannel) ChunkedStreamSourceConduit(io.undertow.conduits.ChunkedStreamSourceConduit) HttpString(io.undertow.util.HttpString)

Example 30 with HttpString

use of io.undertow.util.HttpString in project undertow by undertow-io.

the class HttpTransferEncoding method handleExplicitTransferEncoding.

private static StreamSinkConduit handleExplicitTransferEncoding(HttpServerExchange exchange, StreamSinkConduit channel, ConduitListener<StreamSinkConduit> finishListener, HeaderMap responseHeaders, String transferEncodingHeader, boolean headRequest) {
    HttpString transferEncoding = new HttpString(transferEncodingHeader);
    if (transferEncoding.equals(Headers.CHUNKED)) {
        if (headRequest) {
            return channel;
        }
        Boolean preChunked = exchange.getAttachment(HttpAttachments.PRE_CHUNKED_RESPONSE);
        if (preChunked != null && preChunked) {
            return new PreChunkedStreamSinkConduit(channel, finishListener, exchange);
        } else {
            return new ChunkedStreamSinkConduit(channel, exchange.getConnection().getByteBufferPool(), true, !exchange.isPersistent(), responseHeaders, finishListener, exchange);
        }
    } else {
        if (headRequest) {
            return channel;
        }
        log.trace("Cancelling persistence because response is identity with no content length");
        // make it not persistent - very unfortunate for the next request handler really...
        exchange.setPersistent(false);
        responseHeaders.put(Headers.CONNECTION, Headers.CLOSE.toString());
        return new FinishableStreamSinkConduit(channel, terminateResponseListener(exchange));
    }
}
Also used : PreChunkedStreamSinkConduit(io.undertow.conduits.PreChunkedStreamSinkConduit) ChunkedStreamSinkConduit(io.undertow.conduits.ChunkedStreamSinkConduit) PreChunkedStreamSinkConduit(io.undertow.conduits.PreChunkedStreamSinkConduit) FinishableStreamSinkConduit(io.undertow.conduits.FinishableStreamSinkConduit) HttpString(io.undertow.util.HttpString)

Aggregations

HttpString (io.undertow.util.HttpString)59 IOException (java.io.IOException)18 HttpServerExchange (io.undertow.server.HttpServerExchange)16 HeaderMap (io.undertow.util.HeaderMap)15 HttpHandler (io.undertow.server.HttpHandler)9 ByteBuffer (java.nio.ByteBuffer)9 Map (java.util.Map)8 HashMap (java.util.HashMap)7 PooledByteBuffer (io.undertow.connector.PooledByteBuffer)6 HeaderValues (io.undertow.util.HeaderValues)6 ClientRequest (io.undertow.client.ClientRequest)5 Session (io.undertow.server.session.Session)5 URISyntaxException (java.net.URISyntaxException)5 ArrayList (java.util.ArrayList)5 Test (org.junit.Test)5 InMemorySessionManager (io.undertow.server.session.InMemorySessionManager)4 SessionAttachmentHandler (io.undertow.server.session.SessionAttachmentHandler)4 SessionManager (io.undertow.server.session.SessionManager)4 List (java.util.List)4 TypeConverter (org.apache.camel.TypeConverter)4