Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support absolute-form URI in HTTP requests (#7201)
* Support absolute-form URI in HTTP requests This changeset drops the scheme and authority parts from the URI in two places where we interact with the netty uri. There is also a workaround for netty/netty#12301 . Fixes #7193 * work around infinite loop in BufferLeakDetection * add a url without authority to the test
- Loading branch information
Showing
4 changed files
with
142 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
http-server-netty/src/test/groovy/io/micronaut/http/server/netty/RequestLineSpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package io.micronaut.http.server.netty | ||
|
||
import io.micronaut.context.ApplicationContext | ||
import io.micronaut.context.annotation.Requires | ||
import io.micronaut.http.annotation.Controller | ||
import io.micronaut.http.annotation.Get | ||
import io.micronaut.runtime.server.EmbeddedServer | ||
import io.netty.channel.ChannelHandlerContext | ||
import io.netty.channel.ChannelOutboundHandlerAdapter | ||
import io.netty.channel.ChannelPromise | ||
import io.netty.channel.embedded.EmbeddedChannel | ||
import io.netty.handler.codec.http.DefaultHttpRequest | ||
import io.netty.handler.codec.http.FullHttpResponse | ||
import io.netty.handler.codec.http.HttpClientCodec | ||
import io.netty.handler.codec.http.HttpHeaderNames | ||
import io.netty.handler.codec.http.HttpHeaderValues | ||
import io.netty.handler.codec.http.HttpMethod | ||
import io.netty.handler.codec.http.HttpObjectAggregator | ||
import io.netty.handler.codec.http.HttpResponseStatus | ||
import io.netty.handler.codec.http.HttpVersion | ||
import jakarta.inject.Singleton | ||
import spock.lang.Issue | ||
import spock.lang.Specification | ||
|
||
import java.nio.charset.StandardCharsets | ||
|
||
class RequestLineSpec extends Specification { | ||
@Issue('https://github.com/micronaut-projects/micronaut-core/issues/7193') | ||
def 'test different request lines http 1'() { | ||
given: | ||
ApplicationContext ctx = ApplicationContext.run([ | ||
'spec.name': 'RequestLineSpec', | ||
]) | ||
def embeddedServer = (NettyHttpServer) ctx.getBean(EmbeddedServer) | ||
|
||
def serverEmbeddedChannel = embeddedServer.buildEmbeddedChannel(false) | ||
|
||
def clientEmbeddedChannel = new EmbeddedChannel() | ||
|
||
serverEmbeddedChannel.pipeline() | ||
.addFirst(new ChannelOutboundHandlerAdapter() { | ||
@Override | ||
void write(ChannelHandlerContext ctx_, Object msg, ChannelPromise promise) throws Exception { | ||
// forward to client | ||
clientEmbeddedChannel.writeOneInbound(msg) | ||
} | ||
|
||
@Override | ||
void flush(ChannelHandlerContext ctx_) throws Exception { | ||
clientEmbeddedChannel.flushInbound() | ||
} | ||
}) | ||
clientEmbeddedChannel.pipeline() | ||
.addLast(new ChannelOutboundHandlerAdapter() { | ||
@Override | ||
void write(ChannelHandlerContext ctx_, Object msg, ChannelPromise promise) throws Exception { | ||
// forward to server | ||
serverEmbeddedChannel.writeOneInbound(msg) | ||
} | ||
|
||
@Override | ||
void flush(ChannelHandlerContext ctx_) throws Exception { | ||
serverEmbeddedChannel.flushInbound() | ||
} | ||
}) | ||
.addLast(new HttpClientCodec()) | ||
.addLast(new HttpObjectAggregator(1024)) | ||
|
||
def request1 = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri) | ||
request1.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE) | ||
|
||
when: | ||
clientEmbeddedChannel.writeOneOutbound(request1) | ||
clientEmbeddedChannel.flushOutbound() | ||
serverEmbeddedChannel.runPendingTasks() | ||
|
||
then: | ||
FullHttpResponse response = clientEmbeddedChannel.readInbound() | ||
response.status() == HttpResponseStatus.OK | ||
response.content().toString(StandardCharsets.UTF_8) == 'bar' | ||
|
||
cleanup: | ||
response.release() | ||
clientEmbeddedChannel.close() | ||
serverEmbeddedChannel.close() | ||
ctx.close() | ||
|
||
where: | ||
uri << [ | ||
'/foo', // origin-form | ||
'http://example.com/foo', // absolute-form | ||
'http:///foo', // weird form | ||
] | ||
} | ||
|
||
@Singleton | ||
@Controller | ||
@Requires(property = 'spec.name', value = 'RequestLineSpec') | ||
public static class SimpleController { | ||
@Get('/foo') | ||
public String foo() { | ||
return "bar" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters