-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Fixes #11926 - Authority Customizer. Introduced AuthorityCustomizer to synthesize the authority from the Host header (or serverName:serverPort), and related documentation. Removed additional check on authority's host in `HttpCompliance`, as it was too strict and in the wrong place (authority checks should be factored out elsewhere for all HTTP protocol versions). Signed-off-by: Simone Bordet <[email protected]>
- Loading branch information
Showing
5 changed files
with
176 additions
and
5 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
63 changes: 63 additions & 0 deletions
63
.../jetty-http2-server/src/main/java/org/eclipse/jetty/http2/server/AuthorityCustomizer.java
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,63 @@ | ||
// | ||
// ======================================================================== | ||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. | ||
// | ||
// This program and the accompanying materials are made available under the | ||
// terms of the Eclipse Public License v. 2.0 which is available at | ||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
// which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
// | ||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
// ======================================================================== | ||
// | ||
|
||
package org.eclipse.jetty.http2.server; | ||
|
||
import org.eclipse.jetty.http.HttpFields; | ||
import org.eclipse.jetty.http.HttpHeader; | ||
import org.eclipse.jetty.http.HttpURI; | ||
import org.eclipse.jetty.server.HttpConfiguration; | ||
import org.eclipse.jetty.server.Request; | ||
import org.eclipse.jetty.util.HostPort; | ||
import org.eclipse.jetty.util.URIUtil; | ||
|
||
/** | ||
* <p>A {@link HttpConfiguration.Customizer} that synthesizes the authority when the | ||
* {@link HttpHeader#C_AUTHORITY} header is missing.</p> | ||
* <p>After customization, the synthesized authority is accessible via | ||
* {@link HttpURI#getAuthority()} from the {@link Request} object.</p> | ||
* <p>The authority is synthesized from the {@code Host} header. | ||
* If the {@code Host} header is also missing, it is synthesized using | ||
* {@link Request#getServerName(Request)} and {@link Request#getServerPort(Request)}.</p> | ||
*/ | ||
public class AuthorityCustomizer implements HttpConfiguration.Customizer | ||
{ | ||
@Override | ||
public Request customize(Request request, HttpFields.Mutable responseHeaders) | ||
{ | ||
if (request.getConnectionMetaData().getHttpVersion().getVersion() < 20) | ||
return request; | ||
|
||
HttpURI httpURI = request.getHttpURI(); | ||
if (httpURI.hasAuthority() && !httpURI.getAuthority().isEmpty()) | ||
return request; | ||
|
||
String hostPort = request.getHeaders().get(HttpHeader.HOST); | ||
if (hostPort == null) | ||
{ | ||
String host = Request.getServerName(request); | ||
int port = URIUtil.normalizePortForScheme(httpURI.getScheme(), Request.getServerPort(request)); | ||
hostPort = new HostPort(host, port).toString(); | ||
} | ||
|
||
HttpURI newHttpURI = HttpURI.build(httpURI).authority(hostPort).asImmutable(); | ||
return new Request.Wrapper(request) | ||
{ | ||
@Override | ||
public HttpURI getHttpURI() | ||
{ | ||
return newHttpURI; | ||
} | ||
}; | ||
} | ||
} |
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
98 changes: 98 additions & 0 deletions
98
...etty-http2-tests/src/test/java/org/eclipse/jetty/http2/tests/AuthorityCustomizerTest.java
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,98 @@ | ||
// | ||
// ======================================================================== | ||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. | ||
// | ||
// This program and the accompanying materials are made available under the | ||
// terms of the Eclipse Public License v. 2.0 which is available at | ||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
// which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
// | ||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
// ======================================================================== | ||
// | ||
|
||
package org.eclipse.jetty.http2.tests; | ||
|
||
import java.io.OutputStream; | ||
import java.net.Socket; | ||
import java.nio.ByteBuffer; | ||
import java.util.HashMap; | ||
import java.util.concurrent.CountDownLatch; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.atomic.AtomicReference; | ||
|
||
import org.eclipse.jetty.http.HttpFields; | ||
import org.eclipse.jetty.http.HttpScheme; | ||
import org.eclipse.jetty.http.HttpStatus; | ||
import org.eclipse.jetty.http.HttpVersion; | ||
import org.eclipse.jetty.http.MetaData; | ||
import org.eclipse.jetty.http2.frames.HeadersFrame; | ||
import org.eclipse.jetty.http2.frames.PrefaceFrame; | ||
import org.eclipse.jetty.http2.frames.SettingsFrame; | ||
import org.eclipse.jetty.http2.parser.Parser; | ||
import org.eclipse.jetty.http2.server.AuthorityCustomizer; | ||
import org.eclipse.jetty.io.ByteBufferPool; | ||
import org.eclipse.jetty.server.Handler; | ||
import org.eclipse.jetty.server.Request; | ||
import org.eclipse.jetty.server.Response; | ||
import org.eclipse.jetty.util.BufferUtil; | ||
import org.eclipse.jetty.util.Callback; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
public class AuthorityCustomizerTest extends AbstractServerTest | ||
{ | ||
@Test | ||
public void testSynthesizeAuthorityFromHost() throws Exception | ||
{ | ||
startServer(new Handler.Abstract() | ||
{ | ||
@Override | ||
public boolean handle(Request request, Response response, Callback callback) | ||
{ | ||
int status = request.getHttpURI().hasAuthority() ? HttpStatus.OK_200 : HttpStatus.BAD_REQUEST_400; | ||
response.setStatus(status); | ||
callback.succeeded(); | ||
return true; | ||
} | ||
}); | ||
httpConfig.addCustomizer(new AuthorityCustomizer()); | ||
|
||
ByteBufferPool.Accumulator accumulator = new ByteBufferPool.Accumulator(); | ||
generator.control(accumulator, new PrefaceFrame()); | ||
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false)); | ||
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), null, path, HttpVersion.HTTP_2, HttpFields.EMPTY, -1); | ||
generator.control(accumulator, new HeadersFrame(1, metaData, null, true)); | ||
|
||
try (Socket client = new Socket("localhost", connector.getLocalPort())) | ||
{ | ||
OutputStream output = client.getOutputStream(); | ||
for (ByteBuffer buffer : accumulator.getByteBuffers()) | ||
{ | ||
output.write(BufferUtil.toArray(buffer)); | ||
} | ||
|
||
CountDownLatch latch = new CountDownLatch(1); | ||
AtomicReference<HeadersFrame> frameRef = new AtomicReference<>(); | ||
Parser parser = new Parser(bufferPool, 8192); | ||
parser.init(new Parser.Listener() | ||
{ | ||
@Override | ||
public void onHeaders(HeadersFrame frame) | ||
{ | ||
frameRef.set(frame); | ||
latch.countDown(); | ||
} | ||
}); | ||
parseResponse(client, parser); | ||
|
||
assertTrue(latch.await(5, TimeUnit.SECONDS)); | ||
|
||
HeadersFrame frame = frameRef.get(); | ||
MetaData.Response response = (MetaData.Response)frame.getMetaData(); | ||
assertEquals(HttpStatus.OK_200, response.getStatus()); | ||
} | ||
} | ||
} |