vert-x3 / issues

Apache License 2.0
37 stars 7 forks source link

Found a bug : java.lang.StringIndexOutOfBoundsException: String index out of range: 0 in Http2ServerRequestImpl #329

Open michaelpog opened 6 years ago

michaelpog commented 6 years ago

I found a bug in the HTTP server when the client is sending an H2C HTTP/2 request, and the HTTP server is using vertx-web

The scenario is when a request is sent without any relative URI: for example http://localhost:6000 In that case the call to HTTP client is with:

      RequestOptions requestOptions = new RequestOptions();
       requestOptions.setHost(127.0.0.1);
        requestOptions.setPort(8080);
        requestOptions.setURI("");

In the HTTP Server I'm getting this exception:

java.lang.StringIndexOutOfBoundsException: String index out of range: 0
    at java.lang.String.charAt(String.java:658)
    at io.vertx.core.http.impl.HttpUtils.parsePath(HttpUtils.java:226)
    at io.vertx.core.http.impl.Http2ServerRequestImpl.path(Http2ServerRequestImpl.java:296)
    at io.vertx.ext.web.impl.HttpServerRequestWrapper.<init>(HttpServerRequestWrapper.java:27)
    at io.vertx.ext.web.impl.RoutingContextImplBase.<init>(RoutingContextImplBase.java:45)
    at io.vertx.ext.web.impl.RoutingContextImpl.<init>(RoutingContextImpl.java:63)
    at io.vertx.ext.web.impl.RouterImpl.accept(RouterImpl.java:79)
    at io.vertx.core.http.impl.Http2ServerConnection.lambda$onHeadersRead$0(Http2ServerConnection.java:130)
    at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:342)
    at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:200)
    at io.vertx.core.http.impl.Http2ServerConnection.onHeadersRead(Http2ServerConnection.java:127)
    at io.vertx.core.http.impl.Http2ConnectionBase.onHeadersRead(Http2ConnectionBase.java:191)
    at io.vertx.core.http.impl.Http2ServerConnection.onHeadersRead(Http2ServerConnection.java:48)
    at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder$FrameReadListener.onHeadersRead(DefaultHttp2ConnectionDecoder.java:321)
    at io.netty.handler.codec.http2.DefaultHttp2FrameReader$1.processFragment(DefaultHttp2FrameReader.java:457)
    at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readHeadersFrame(DefaultHttp2FrameReader.java:464)
    at io.netty.handler.codec.http2.DefaultHttp2FrameReader.processPayloadState(DefaultHttp2FrameReader.java:254)
    at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readFrame(DefaultHttp2FrameReader.java:160)
    at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder.decodeFrame(DefaultHttp2ConnectionDecoder.java:118)
    at io.netty.handler.codec.http2.Http2ConnectionHandler$FrameDecoder.decode(Http2ConnectionHandler.java:373)
    at io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:433)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1359)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:935)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
    at java.lang.Thread.run(Thread.java:745)

and the request is never served by the HTTP server.

If I change the HTTP client request to:

      RequestOptions requestOptions = new RequestOptions();
       requestOptions.setHost("127.0.0.1");
        requestOptions.setPort(8080);
        requestOptions.setURI("\");

Then the HTTP server receives the request and serves it just fine.

I also verified that the issue is only in the HTTP Server in vert.x-web. The HTTP server in vert.x core is not having this issue.

I believe the problem is in io.vertx.ext.web.impl.HttpServerRequestWrapper's constructor:

HttpServerRequestWrapper(HttpServerRequest request) {
    delegate = request;
    method = request.method();
    path = request.path();
    uri = request.uri();
    absoluteURI = null;
  }

This calls

public String path() {
...
CharSequence path = headers.path();
 if (path != null) {
          this.path = HttpUtils.parsePath(path.toString());
        }

The path is not null, but it's empty "" and then HttpUtils.parsePath(String uri) makes an assumptions that uri is not empty, and fails here:

static String parsePath(String uri) {
    int i;
    if (uri.charAt(0) == '/') {
      i = 0;
..
vietj commented 6 years ago

can you investigate @pmlopes ?

michaelpog commented 6 years ago

Any progress on this? @vietj @pmlopes ?