Search in sources :

Example 16 with HttpString

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

the class HttpRequestConduit 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.
     *
     * 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 java.io.IOException
     */
private int processWrite(int state, final ByteBuffer userData) throws IOException {
    if (state == STATE_START) {
        pooledBuffer = pool.allocate();
    }
    ClientRequest request = this.request;
    ByteBuffer buffer = pooledBuffer.getBuffer();
    Iterator<HttpString> nameIterator = this.nameIterator;
    Iterator<String> valueIterator = this.valueIterator;
    int charIndex = this.charIndex;
    int length;
    String string = this.string;
    HttpString headerName = this.headerName;
    int res;
    // BUFFER IS FLIPPED COMING IN
    if (state != STATE_START && buffer.hasRemaining()) {
        log.trace("Flushing remaining buffer");
        do {
            res = next.write(buffer);
            if (res == 0) {
                return state;
            }
        } while (buffer.hasRemaining());
    }
    buffer.clear();
    // BUFFER IS NOW EMPTY FOR FILLING
    for (; ; ) {
        switch(state) {
            case STATE_BODY:
                {
                    // shouldn't be possible, but might as well do the right thing anyway
                    return state;
                }
            case STATE_START:
                {
                    log.trace("Starting request");
                    int len = request.getMethod().length() + request.getPath().length() + request.getProtocol().length() + 4;
                    // test that our buffer has enough space for the initial request line plus one more CR+LF
                    if (len <= buffer.remaining()) {
                        assert buffer.remaining() >= 50;
                        request.getMethod().appendTo(buffer);
                        buffer.put((byte) ' ');
                        string = request.getPath();
                        length = string.length();
                        for (charIndex = 0; charIndex < length; charIndex++) {
                            buffer.put((byte) string.charAt(charIndex));
                        }
                        buffer.put((byte) ' ');
                        request.getProtocol().appendTo(buffer);
                        buffer.put((byte) '\r').put((byte) '\n');
                    } else {
                        StringBuilder sb = new StringBuilder(len);
                        sb.append(request.getMethod().toString());
                        sb.append(" ");
                        sb.append(request.getPath());
                        sb.append(" ");
                        sb.append(request.getProtocol());
                        sb.append("\r\n");
                        string = sb.toString();
                        charIndex = 0;
                        state = STATE_URL;
                        break;
                    }
                    HeaderMap headers = request.getRequestHeaders();
                    nameIterator = headers.getHeaderNames().iterator();
                    if (!nameIterator.hasNext()) {
                        log.trace("No request headers");
                        buffer.put((byte) '\r').put((byte) '\n');
                        buffer.flip();
                        while (buffer.hasRemaining()) {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_BUF_FLUSH;
                            }
                        }
                        pooledBuffer.close();
                        pooledBuffer = null;
                        log.trace("Body");
                        return STATE_BODY;
                    }
                    headerName = nameIterator.next();
                    charIndex = 0;
                // fall thru
                }
            case STATE_HDR_NAME:
                {
                    log.tracef("Processing header '%s'", headerName);
                    length = headerName.length();
                    while (charIndex < length) {
                        if (buffer.hasRemaining()) {
                            buffer.put(headerName.byteAt(charIndex++));
                        } else {
                            log.trace("Buffer flush");
                            buffer.flip();
                            do {
                                res = next.write(buffer);
                                if (res == 0) {
                                    this.string = string;
                                    this.headerName = headerName;
                                    this.charIndex = charIndex;
                                    this.valueIterator = valueIterator;
                                    this.nameIterator = nameIterator;
                                    log.trace("Continuation");
                                    return STATE_HDR_NAME;
                                }
                            } while (buffer.hasRemaining());
                            buffer.clear();
                        }
                    }
                // fall thru
                }
            case STATE_HDR_D:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                this.string = string;
                                this.headerName = headerName;
                                this.charIndex = charIndex;
                                this.valueIterator = valueIterator;
                                this.nameIterator = nameIterator;
                                return STATE_HDR_D;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    buffer.put((byte) ':');
                // fall thru
                }
            case STATE_HDR_DS:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                this.string = string;
                                this.headerName = headerName;
                                this.charIndex = charIndex;
                                this.valueIterator = valueIterator;
                                this.nameIterator = nameIterator;
                                return STATE_HDR_DS;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    buffer.put((byte) ' ');
                    if (valueIterator == null) {
                        valueIterator = request.getRequestHeaders().get(headerName).iterator();
                    }
                    assert valueIterator.hasNext();
                    string = valueIterator.next();
                    charIndex = 0;
                // fall thru
                }
            case STATE_HDR_VAL:
                {
                    log.tracef("Processing header value '%s'", string);
                    length = string.length();
                    while (charIndex < length) {
                        if (buffer.hasRemaining()) {
                            buffer.put((byte) string.charAt(charIndex++));
                        } else {
                            buffer.flip();
                            do {
                                res = next.write(buffer);
                                if (res == 0) {
                                    this.string = string;
                                    this.headerName = headerName;
                                    this.charIndex = charIndex;
                                    this.valueIterator = valueIterator;
                                    this.nameIterator = nameIterator;
                                    log.trace("Continuation");
                                    return STATE_HDR_VAL;
                                }
                            } while (buffer.hasRemaining());
                            buffer.clear();
                        }
                    }
                    charIndex = 0;
                    if (!valueIterator.hasNext()) {
                        if (!buffer.hasRemaining()) {
                            buffer.flip();
                            do {
                                res = next.write(buffer);
                                if (res == 0) {
                                    log.trace("Continuation");
                                    return STATE_HDR_EOL_CR;
                                }
                            } while (buffer.hasRemaining());
                            buffer.clear();
                        }
                        // CR
                        buffer.put((byte) 13);
                        if (!buffer.hasRemaining()) {
                            buffer.flip();
                            do {
                                res = next.write(buffer);
                                if (res == 0) {
                                    log.trace("Continuation");
                                    return STATE_HDR_EOL_LF;
                                }
                            } while (buffer.hasRemaining());
                            buffer.clear();
                        }
                        // LF
                        buffer.put((byte) 10);
                        if (nameIterator.hasNext()) {
                            headerName = nameIterator.next();
                            valueIterator = null;
                            state = STATE_HDR_NAME;
                            break;
                        } else {
                            if (!buffer.hasRemaining()) {
                                buffer.flip();
                                do {
                                    res = next.write(buffer);
                                    if (res == 0) {
                                        log.trace("Continuation");
                                        return STATE_HDR_FINAL_CR;
                                    }
                                } while (buffer.hasRemaining());
                                buffer.clear();
                            }
                            // CR
                            buffer.put((byte) 13);
                            if (!buffer.hasRemaining()) {
                                buffer.flip();
                                do {
                                    res = next.write(buffer);
                                    if (res == 0) {
                                        log.trace("Continuation");
                                        return STATE_HDR_FINAL_LF;
                                    }
                                } while (buffer.hasRemaining());
                                buffer.clear();
                            }
                            // LF
                            buffer.put((byte) 10);
                            this.nameIterator = null;
                            this.valueIterator = null;
                            this.string = null;
                            buffer.flip();
                            //for performance reasons we use a gather write if there is user data
                            if (userData == null) {
                                do {
                                    res = next.write(buffer);
                                    if (res == 0) {
                                        log.trace("Continuation");
                                        return STATE_BUF_FLUSH;
                                    }
                                } while (buffer.hasRemaining());
                            } else {
                                ByteBuffer[] b = { buffer, userData };
                                do {
                                    long r = next.write(b, 0, b.length);
                                    if (r == 0 && buffer.hasRemaining()) {
                                        log.trace("Continuation");
                                        return STATE_BUF_FLUSH;
                                    }
                                } while (buffer.hasRemaining());
                            }
                            pooledBuffer.close();
                            pooledBuffer = null;
                            log.trace("Body");
                            return STATE_BODY;
                        }
                    // not reached
                    }
                // fall thru
                }
            // Clean-up states
            case STATE_HDR_EOL_CR:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_HDR_EOL_CR;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    // CR
                    buffer.put((byte) 13);
                }
            case STATE_HDR_EOL_LF:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_HDR_EOL_LF;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    // LF
                    buffer.put((byte) 10);
                    if (valueIterator.hasNext()) {
                        state = STATE_HDR_NAME;
                        break;
                    } else if (nameIterator.hasNext()) {
                        headerName = nameIterator.next();
                        valueIterator = null;
                        state = STATE_HDR_NAME;
                        break;
                    }
                // fall thru
                }
            case STATE_HDR_FINAL_CR:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_HDR_FINAL_CR;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    // CR
                    buffer.put((byte) 13);
                // fall thru
                }
            case STATE_HDR_FINAL_LF:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_HDR_FINAL_LF;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    // LF
                    buffer.put((byte) 10);
                    this.nameIterator = null;
                    this.valueIterator = null;
                    this.string = null;
                    buffer.flip();
                    //for performance reasons we use a gather write if there is user data
                    if (userData == null) {
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_BUF_FLUSH;
                            }
                        } while (buffer.hasRemaining());
                    } else {
                        ByteBuffer[] b = { buffer, userData };
                        do {
                            long r = next.write(b, 0, b.length);
                            if (r == 0 && buffer.hasRemaining()) {
                                log.trace("Continuation");
                                return STATE_BUF_FLUSH;
                            }
                        } while (buffer.hasRemaining());
                    }
                // fall thru
                }
            case STATE_BUF_FLUSH:
                {
                    // buffer was successfully flushed above
                    pooledBuffer.close();
                    pooledBuffer = null;
                    return STATE_BODY;
                }
            case STATE_URL:
                {
                    for (int i = charIndex; i < string.length(); ++i) {
                        if (!buffer.hasRemaining()) {
                            buffer.flip();
                            do {
                                res = next.write(buffer);
                                if (res == 0) {
                                    log.trace("Continuation");
                                    this.charIndex = i;
                                    this.string = string;
                                    this.state = STATE_URL;
                                    return STATE_URL;
                                }
                            } while (buffer.hasRemaining());
                            buffer.clear();
                        }
                        buffer.put((byte) string.charAt(i));
                    }
                    HeaderMap headers = request.getRequestHeaders();
                    nameIterator = headers.getHeaderNames().iterator();
                    state = STATE_HDR_NAME;
                    if (!nameIterator.hasNext()) {
                        log.trace("No request headers");
                        buffer.put((byte) '\r').put((byte) '\n');
                        buffer.flip();
                        while (buffer.hasRemaining()) {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_BUF_FLUSH;
                            }
                        }
                        pooledBuffer.close();
                        pooledBuffer = null;
                        log.trace("Body");
                        return STATE_BODY;
                    }
                    headerName = nameIterator.next();
                    charIndex = 0;
                    break;
                }
            default:
                {
                    throw new IllegalStateException();
                }
        }
    }
}
Also used : HeaderMap(io.undertow.util.HeaderMap) HttpString(io.undertow.util.HttpString) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ClientRequest(io.undertow.client.ClientRequest) HttpString(io.undertow.util.HttpString)

Example 17 with HttpString

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

the class HttpResponseParser method handleHeaderValue.

/**
     * Parses a header value. This is called from the generated  bytecode.
     *
     * @param buffer    The buffer
     * @param state     The current state
     * @param builder   The exchange builder
     * @return The number of bytes remaining
     */
@SuppressWarnings("unused")
final void handleHeaderValue(ByteBuffer buffer, ResponseParseState state, HttpResponseBuilder builder) {
    StringBuilder stringBuilder = state.stringBuilder;
    if (stringBuilder == null) {
        stringBuilder = new StringBuilder();
        state.parseState = 0;
    }
    int parseState = state.parseState;
    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);
                    }
                    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);
                        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
                        HttpString nextStandardHeader = state.nextHeader;
                        String headerValue = stringBuilder.toString();
                        //TODO: we need to decode this according to RFC-2047 if we have seen a =? symbol
                        builder.getResponseHeaders().add(nextStandardHeader, headerValue);
                        state.nextHeader = null;
                        state.leftOver = next;
                        state.stringBuilder.setLength(0);
                        if (next == '\r') {
                            parseState = AWAIT_DATA_END;
                        } else {
                            state.state = ResponseParseState.HEADER;
                            state.parseState = 0;
                            return;
                        }
                    }
                    break;
                }
            case AWAIT_DATA_END:
                {
                    state.state = ResponseParseState.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) HttpString(io.undertow.util.HttpString)

Example 18 with HttpString

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

the class HttpResponseParser method httpStrings.

/**
     * This is a bit of hack to enable the parser to get access to the HttpString's that are sorted
     * in the static fields of the relevant classes. This means that in most cases a HttpString comparison
     * will take the fast path == route, as they will be the same object
     *
     * @return
     */
protected static Map<String, HttpString> httpStrings() {
    final Map<String, HttpString> results = new HashMap<>();
    final Class[] classs = { Headers.class, Methods.class, Protocols.class };
    for (Class<?> c : classs) {
        for (Field field : c.getDeclaredFields()) {
            if (field.getType().equals(HttpString.class)) {
                field.setAccessible(true);
                HttpString result = null;
                try {
                    result = (HttpString) field.get(null);
                    results.put(result.toString(), result);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    return results;
}
Also used : Field(java.lang.reflect.Field) HashMap(java.util.HashMap) HttpString(io.undertow.util.HttpString) HttpString(io.undertow.util.HttpString)

Example 19 with HttpString

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

the class HpackDecoder method decode.

/**
     * Decodes the provided frame data. If this method leaves data in the buffer then
     * this buffer should be compacted so this data is preserved, unless there is no
     * more data in which case this should be considered a protocol error.
     *
     * @param buffer The buffer
     */
public void decode(ByteBuffer buffer, boolean moreData) throws HpackException {
    while (buffer.hasRemaining()) {
        int originalPos = buffer.position();
        byte b = buffer.get();
        if ((b & 0b10000000) != 0) {
            first = false;
            //if the first bit is set it is an indexed header field
            //unget the byte
            buffer.position(buffer.position() - 1);
            //prefix is 7
            int index = Hpack.decodeInteger(buffer, 7);
            if (index == -1) {
                if (!moreData) {
                    throw UndertowMessages.MESSAGES.hpackFailed();
                }
                buffer.position(originalPos);
                return;
            } else if (index == 0) {
                throw UndertowMessages.MESSAGES.zeroNotValidHeaderTableIndex();
            }
            handleIndex(index);
        } else if ((b & 0b01000000) != 0) {
            first = false;
            //Literal Header Field with Incremental Indexing
            HttpString headerName = readHeaderName(buffer, 6);
            if (headerName == null) {
                if (!moreData) {
                    throw UndertowMessages.MESSAGES.hpackFailed();
                }
                buffer.position(originalPos);
                return;
            }
            String headerValue = readHpackString(buffer);
            if (headerValue == null) {
                if (!moreData) {
                    throw UndertowMessages.MESSAGES.hpackFailed();
                }
                buffer.position(originalPos);
                return;
            }
            headerEmitter.emitHeader(headerName, headerValue, false);
            addEntryToHeaderTable(new HeaderField(headerName, headerValue));
        } else if ((b & 0b11110000) == 0) {
            first = false;
            //Literal Header Field without Indexing
            HttpString headerName = readHeaderName(buffer, 4);
            if (headerName == null) {
                if (!moreData) {
                    throw UndertowMessages.MESSAGES.hpackFailed();
                }
                buffer.position(originalPos);
                return;
            }
            String headerValue = readHpackString(buffer);
            if (headerValue == null) {
                if (!moreData) {
                    throw UndertowMessages.MESSAGES.hpackFailed();
                }
                buffer.position(originalPos);
                return;
            }
            headerEmitter.emitHeader(headerName, headerValue, false);
        } else if ((b & 0b11110000) == 0b00010000) {
            first = false;
            //Literal Header Field never indexed
            HttpString headerName = readHeaderName(buffer, 4);
            if (headerName == null) {
                buffer.position(originalPos);
                return;
            }
            String headerValue = readHpackString(buffer);
            if (headerValue == null) {
                if (!moreData) {
                    throw UndertowMessages.MESSAGES.hpackFailed();
                }
                buffer.position(originalPos);
                return;
            }
            headerEmitter.emitHeader(headerName, headerValue, true);
        } else if ((b & 0b11100000) == 0b00100000) {
            if (!first) {
                throw new HpackException();
            }
            //context update max table size change
            if (!handleMaxMemorySizeChange(buffer, originalPos)) {
                return;
            }
        } else {
            throw UndertowMessages.MESSAGES.invalidHpackEncoding(b);
        }
    }
    if (!moreData) {
        first = true;
    }
}
Also used : HeaderField(io.undertow.protocols.http2.Hpack.HeaderField) HttpString(io.undertow.util.HttpString) HttpString(io.undertow.util.HttpString)

Example 20 with HttpString

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

the class HttpClientConnection method sendRequest.

@Override
public void sendRequest(final ClientRequest request, final ClientCallback<ClientExchange> clientCallback) {
    if (http2Delegate != null) {
        http2Delegate.sendRequest(request, clientCallback);
        return;
    }
    count++;
    if (anyAreSet(state, UPGRADE_REQUESTED | UPGRADED | CLOSE_REQ | CLOSED)) {
        clientCallback.failed(UndertowClientMessages.MESSAGES.invalidConnectionState());
        return;
    }
    final HttpClientExchange httpClientExchange = new HttpClientExchange(clientCallback, request, this);
    boolean ssl = this.connection instanceof SslConnection;
    if (!ssl && !http2Tried && options.get(UndertowOptions.ENABLE_HTTP2, false) && !request.getRequestHeaders().contains(Headers.UPGRADE) && request.getMethod().equals(Methods.GET)) {
        //this is the first request, as we want to try a HTTP2 upgrade
        request.getRequestHeaders().put(new HttpString("HTTP2-Settings"), Http2ClearClientProvider.createSettingsFrame(options, bufferPool));
        request.getRequestHeaders().put(Headers.UPGRADE, Http2Channel.CLEARTEXT_UPGRADE_STRING);
        request.getRequestHeaders().put(Headers.CONNECTION, "Upgrade, HTTP2-Settings");
        http2Tried = true;
    }
    if (currentRequest == null) {
        initiateRequest(httpClientExchange);
    } else {
        pendingQueue.add(httpClientExchange);
    }
}
Also used : SslConnection(org.xnio.ssl.SslConnection) 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