diff --git a/src/main/asciidoc/enums.adoc b/src/main/asciidoc/enums.adoc index 15c120110..f201c5f35 100644 --- a/src/main/asciidoc/enums.adoc +++ b/src/main/asciidoc/enums.adoc @@ -87,30 +87,6 @@ ID 14, bad timestamp +++ |=== -[[HttpMethod]] -== HttpMethod - -++++ - Represents an HTTP method -++++ -''' - -[cols=">25%,75%"] -[frame="topbot"] -|=== -^|Name | Description -|[[OPTIONS]]`OPTIONS`|- -|[[GET]]`GET`|- -|[[HEAD]]`HEAD`|- -|[[POST]]`POST`|- -|[[PUT]]`PUT`|- -|[[DELETE]]`DELETE`|- -|[[TRACE]]`TRACE`|- -|[[CONNECT]]`CONNECT`|- -|[[PATCH]]`PATCH`|- -|[[OTHER]]`OTHER`|- -|=== - [[HttpVersion]] == HttpVersion diff --git a/src/main/asciidoc/http.adoc b/src/main/asciidoc/http.adoc index cfdc6d259..75cf9b1b6 100644 --- a/src/main/asciidoc/http.adoc +++ b/src/main/asciidoc/http.adoc @@ -382,11 +382,6 @@ this will get called every time a custom frame arrives. Here's an example: HTTP/2 frames are not subject to flow control - the frame handler will be called immediatly when a custom frame is received whether the request is paused or is not -==== Non standard HTTP methods - -The {@link io.vertx.core.http.HttpMethod#OTHER} HTTP method is used for non standard methods, in this case -{@link io.vertx.core.http.HttpServerRequest#rawMethod()} returns the HTTP method as sent by the client. - === Sending back responses The server response object is an instance of {@link io.vertx.core.http.HttpServerResponse} and is obtained from the @@ -887,12 +882,6 @@ You can also write headers using {@link io.vertx.core.http.HttpClientRequest#put If you wish to write headers to the request you must do so before any part of the request body is written. -==== Non standard HTTP methods - -The {@link io.vertx.core.http.HttpMethod#OTHER} HTTP method is used for non standard methods, when this method -is used, {@link io.vertx.core.http.HttpClientRequest#setRawMethod(java.lang.String)} must be used to -set the raw method to send to the server. - ==== Ending HTTP requests Once you have finished with the HTTP request you must end it with one of the {@link io.vertx.core.http.HttpClientRequest#end} diff --git a/src/main/java/io/vertx/core/http/HttpClientRequest.java b/src/main/java/io/vertx/core/http/HttpClientRequest.java index c040990df..5934c6a70 100644 --- a/src/main/java/io/vertx/core/http/HttpClientRequest.java +++ b/src/main/java/io/vertx/core/http/HttpClientRequest.java @@ -99,20 +99,6 @@ public interface HttpClientRequest extends WriteStream, FutureTim Fox */ @VertxGen -public enum HttpMethod { - OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, PATCH, OTHER +public interface HttpMethod { + + /** + * The {@code OPTIONS} method, this instance is interned and uniquely used. + */ + HttpMethod OPTIONS = new HttpMethodImpl(io.netty.handler.codec.http.HttpMethod.OPTIONS); + + /** + * The {@code GET} method, this instance is interned and uniquely used. + */ + HttpMethod GET = new HttpMethodImpl(io.netty.handler.codec.http.HttpMethod.GET); + + /** + * The {@code HEAD} method, this instance is interned and uniquely used. + */ + HttpMethod HEAD = new HttpMethodImpl(io.netty.handler.codec.http.HttpMethod.HEAD); + + /** + * The {@code POST} method, this instance is interned and uniquely used. + */ + HttpMethod POST = new HttpMethodImpl(io.netty.handler.codec.http.HttpMethod.POST); + + /** + * The {@code PUT} method, this instance is interned and uniquely used. + */ + HttpMethod PUT = new HttpMethodImpl(io.netty.handler.codec.http.HttpMethod.PUT); + + /** + * The {@code DELETE} method, this instance is interned and uniquely used. + */ + HttpMethod DELETE = new HttpMethodImpl(io.netty.handler.codec.http.HttpMethod.DELETE); + + /** + * The {@code TRACE} method, this instance is interned and uniquely used. + */ + HttpMethod TRACE = new HttpMethodImpl(io.netty.handler.codec.http.HttpMethod.TRACE); + + /** + * The {@code CONNECT} method, this instance is interned and uniquely used. + */ + HttpMethod CONNECT = new HttpMethodImpl(io.netty.handler.codec.http.HttpMethod.CONNECT); + + /** + * The {@code PATCH} method, this instance is interned and uniquely used. + */ + HttpMethod PATCH = new HttpMethodImpl(io.netty.handler.codec.http.HttpMethod.PATCH); + + /** + * @return the method name + */ + String name(); + + /** + * @return the same value than {@link #name()} + */ + String toString(); + + /** + * Lookup the {@code HttpMethod} value for the specified {@code value}. + *
+ * The predefined method constants {@link #GET}, {@link #POST}, {@link #PUT}, {@link #HEAD}, {@link #OPTIONS}, + * {@link #DELETE}, {@link #TRACE}, {@link #CONNECT} and {@link #PATCH} are interned and will be returned + * when case sensitively matching their string value (i.e {@code "GET"}, etc...) + *
+ * Otherwise a new instance is returned. + * + * @param value the value + * @return the {@code HttpMethod} instance for the specified string {@code value} + * @throws IllegalArgumentException when the value is incorrect, the value is empty or contains an invalid char + */ + static HttpMethod valueOf(String value) { + Objects.requireNonNull(value, "value"); + switch (value) { + case "OPTIONS": + return OPTIONS; + case "GET": + return GET; + case "HEAD": + return HEAD; + case "POST": + return POST; + case "PUT": + return PUT; + case "DELETE": + return DELETE; + case "TRACE": + return TRACE; + case "CONNECT": + return CONNECT; + case "PATCH": + return PATCH; + default: + return new HttpMethodImpl(io.netty.handler.codec.http.HttpMethod.valueOf(value)); + } + } } diff --git a/src/main/java/io/vertx/core/http/HttpServerRequest.java b/src/main/java/io/vertx/core/http/HttpServerRequest.java index 7f764704c..4cdf5c650 100644 --- a/src/main/java/io/vertx/core/http/HttpServerRequest.java +++ b/src/main/java/io/vertx/core/http/HttpServerRequest.java @@ -72,11 +72,6 @@ public interface HttpServerRequest extends ReadStream { */ HttpMethod method(); - /** - * @return the HTTP method as sent by the client - */ - String rawMethod(); - /** * @return true if this {@link io.vertx.core.net.NetSocket} is encrypted via SSL/TLS */ diff --git a/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java b/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java index 29051bf04..106f57877 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java @@ -117,12 +117,11 @@ class Http1xClientConnection extends Http1xConnectionBase impleme private HttpRequest createRequest( HttpMethod method, - String rawMethod, String uri, MultiMap headerMap, String hostHeader, boolean chunked) { - DefaultHttpRequest request = new DefaultHttpRequest(HttpUtils.toNettyHttpVersion(version), HttpUtils.toNettyHttpMethod(method, rawMethod), uri, false); + DefaultHttpRequest request = new DefaultHttpRequest(HttpUtils.toNettyHttpVersion(version), HttpMethodImpl.toNetty(method), uri, false); HttpHeaders headers = request.headers(); if (headerMap != null) { for (Map.Entry header : headerMap) { @@ -313,8 +312,8 @@ class Http1xClientConnection extends Http1xConnectionBase impleme } @Override - public void writeHead(HttpMethod method, String rawMethod, String uri, MultiMap headers, String hostHeader, boolean chunked, ByteBuf buf, boolean end, StreamPriority priority, Handler> handler) { - HttpRequest request = conn.createRequest(method, rawMethod, uri, headers, hostHeader, chunked); + public void writeHead(HttpMethod method, String uri, MultiMap headers, String hostHeader, boolean chunked, ByteBuf buf, boolean end, StreamPriority priority, Handler> handler) { + HttpRequest request = conn.createRequest(method, uri, headers, hostHeader, chunked); if (end) { if (buf != null) { request = new AssembledFullHttpRequest(request, buf); diff --git a/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java b/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java index 707f0f62e..c5259e215 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java @@ -65,7 +65,6 @@ public class Http1xServerRequest implements HttpServerRequest { private HttpRequest request; private io.vertx.core.http.HttpVersion version; private io.vertx.core.http.HttpMethod method; - private String rawMethod; private String uri; private String path; private String query; @@ -208,24 +207,11 @@ public class Http1xServerRequest implements HttpServerRequest { @Override public io.vertx.core.http.HttpMethod method() { if (method == null) { - String sMethod = request.method().toString(); - try { - method = io.vertx.core.http.HttpMethod.valueOf(sMethod); - } catch (IllegalArgumentException e) { - method = io.vertx.core.http.HttpMethod.OTHER; - } + method = io.vertx.core.http.impl.HttpMethodImpl.fromNetty(request.method()); } return method; } - @Override - public String rawMethod() { - if (rawMethod == null) { - rawMethod = request.method().toString(); - } - return rawMethod; - } - @Override public String uri() { if (uri == null) { diff --git a/src/main/java/io/vertx/core/http/impl/Http2ClientConnection.java b/src/main/java/io/vertx/core/http/impl/Http2ClientConnection.java index 514241961..8876c0147 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ClientConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ClientConnection.java @@ -17,7 +17,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http2.DefaultHttp2Headers; -import io.netty.handler.codec.http2.Http2Connection; import io.netty.handler.codec.http2.Http2Error; import io.netty.handler.codec.http2.Http2Exception; import io.netty.handler.codec.http2.Http2Headers; @@ -166,7 +165,7 @@ class Http2ClientConnection extends Http2ConnectionBase implements HttpClientCon Handler pushHandler = stream.pushHandler(); if (pushHandler != null) { String rawMethod = headers.method().toString(); - HttpMethod method = HttpUtils.toVertxMethod(rawMethod); + HttpMethod method = HttpMethod.valueOf(rawMethod); String uri = headers.path().toString(); String authority = headers.authority() != null ? headers.authority().toString() : null; MultiMap headersMap = new Http2HeadersAdaptor(headers); @@ -181,7 +180,7 @@ class Http2ClientConnection extends Http2ConnectionBase implements HttpClientCon host = authority.substring(0, pos); port = Integer.parseInt(authority.substring(pos + 1)); } - HttpClientRequestPushPromise pushReq = new HttpClientRequestPushPromise(this, client, isSsl(), method, rawMethod, uri, host, port, headersMap); + HttpClientRequestPushPromise pushReq = new HttpClientRequestPushPromise(this, client, isSsl(), method, uri, host, port, headersMap); pushReq.getStream().init(promisedStream); if (metrics != null) { ((Stream)pushReq.getStream()).metric = metrics.responsePushed(queueMetric, metric(), localAddress(), remoteAddress(), pushReq); @@ -455,9 +454,9 @@ class Http2ClientConnection extends Http2ConnectionBase implements HttpClientCon } @Override - public void writeHead(HttpMethod method, String rawMethod, String uri, MultiMap headers, String hostHeader, boolean chunked, ByteBuf content, boolean end, StreamPriority priority, Handler> handler) { + public void writeHead(HttpMethod method, String uri, MultiMap headers, String hostHeader, boolean chunked, ByteBuf content, boolean end, StreamPriority priority, Handler> handler) { Http2Headers h = new DefaultHttp2Headers(); - h.method(method != HttpMethod.OTHER ? method.name() : rawMethod); + h.method(method.name()); boolean e; if (method == HttpMethod.CONNECT) { if (hostHeader == null) { diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java b/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java index 84a8cce0b..59ee34731 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java @@ -132,11 +132,7 @@ public class Http2ServerConnection extends Http2ConnectionBase implements HttpSe private synchronized void doSendPush(int streamId, String host, HttpMethod method, MultiMap headers, String path, StreamPriority streamPriority, Promise promise) { Http2Headers headers_ = new DefaultHttp2Headers(); - if (method == HttpMethod.OTHER) { - throw new IllegalArgumentException("Cannot push HttpMethod.OTHER"); - } else { - headers_.method(method.name()); - } + headers_.method(method.name()); headers_.path(path); headers_.scheme(isSsl() ? "https" : "http"); if (host != null) { diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerRequestImpl.java b/src/main/java/io/vertx/core/http/impl/Http2ServerRequestImpl.java index 82e2d42b0..ff3a59f53 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerRequestImpl.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerRequestImpl.java @@ -419,7 +419,7 @@ public class Http2ServerRequestImpl extends Http2ServerStream implements HttpSer if (postRequestDecoder == null) { String contentType = headersMap.get(HttpHeaderNames.CONTENT_TYPE); if (contentType != null) { - io.netty.handler.codec.http.HttpMethod method = io.netty.handler.codec.http.HttpMethod.valueOf(rawMethod); + io.netty.handler.codec.http.HttpMethod method = HttpMethodImpl.toNetty(this.method); String lowerCaseContentType = contentType.toString().toLowerCase(); boolean isURLEncoded = lowerCaseContentType.startsWith(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.toString()); if ((lowerCaseContentType.startsWith(HttpHeaderValues.MULTIPART_FORM_DATA.toString()) || isURLEncoded) && diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java b/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java index 14fdb8550..e64e7f005 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java @@ -27,7 +27,6 @@ import static io.vertx.core.spi.metrics.Metrics.METRICS_ENABLED; abstract class Http2ServerStream extends VertxHttp2Stream { protected final Http2Headers headers; - protected final String rawMethod; protected final HttpMethod method; protected final String uri; protected final String host; @@ -43,7 +42,6 @@ abstract class Http2ServerStream extends VertxHttp2Stream this.headers = null; this.method = method; - this.rawMethod = method.name(); this.uri = uri; this.host = null; this.response = new Http2ServerResponseImpl(conn, this, true, contentEncoding, null); @@ -61,8 +59,7 @@ abstract class Http2ServerStream extends VertxHttp2Stream this.headers = headers; this.host = host; this.uri = headers.get(":path") != null ? headers.get(":path").toString() : null; - this.rawMethod = headers.get(":method") != null ? headers.get(":method").toString() : null; - this.method = HttpUtils.toVertxMethod(rawMethod); + this.method = headers.get(":method") != null ? HttpMethod.valueOf(headers.get(":method").toString()) : null; this.response = new Http2ServerResponseImpl(conn, this, false, contentEncoding, host); } @@ -115,10 +112,6 @@ abstract class Http2ServerStream extends VertxHttp2Stream return method; } - public String rawMethod() { - return rawMethod; - } - @Override void handleClose() { super.handleClose(); diff --git a/src/main/java/io/vertx/core/http/impl/Http2UpgradedClientConnection.java b/src/main/java/io/vertx/core/http/impl/Http2UpgradedClientConnection.java index d770a5fd4..c3ea39d65 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2UpgradedClientConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http2UpgradedClientConnection.java @@ -103,7 +103,6 @@ public class Http2UpgradedClientConnection implements HttpClientConnection { */ @Override public void writeHead(HttpMethod method, - String rawMethod, String uri, MultiMap headers, String hostHeader, @@ -171,7 +170,7 @@ public class Http2UpgradedClientConnection implements HttpClientConnection { HttpClientUpgradeHandler upgradeHandler = new HttpClientUpgradeHandler(httpCodec, upgradeCodec, 65536); pipeline.addAfter("codec", null, new UpgradeRequestHandler()); pipeline.addAfter("codec", null, upgradeHandler); - stream.writeHead(method, rawMethod, uri, headers, hostHeader, chunked, buf, end, priority, listener); + stream.writeHead(method, uri, headers, hostHeader, chunked, buf, end, priority, listener); } @Override diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java b/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java index 84a60b751..7a148278d 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java @@ -14,7 +14,6 @@ package io.vertx.core.http.impl; import io.netty.buffer.ByteBuf; import io.netty.buffer.CompositeByteBuf; import io.netty.buffer.Unpooled; -import io.vertx.codegen.annotations.Nullable; import io.vertx.core.*; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpClientRequest; @@ -57,7 +56,6 @@ public class HttpClientRequestImpl extends HttpClientRequestBase implements Http private final Future endFuture; private boolean chunked; private String hostHeader; - private String rawMethod; private Handler continueHandler; private Handler drainHandler; private Handler pushHandler; @@ -151,17 +149,6 @@ public class HttpClientRequestImpl extends HttpClientRequestBase implements Http return chunked; } - @Override - public synchronized String getRawMethod() { - return rawMethod; - } - - @Override - public synchronized HttpClientRequest setRawMethod(String method) { - this.rawMethod = method; - return this; - } - @Override public synchronized HttpClientRequest setHost(String host) { this.hostHeader = host; @@ -403,11 +390,6 @@ public class HttpClientRequestImpl extends HttpClientRequestBase implements Http private synchronized void connect(Handler> headersHandler) { if (!connecting) { - - if (method == HttpMethod.OTHER && rawMethod == null) { - throw new IllegalStateException("You must provide a rawMethod when using an HttpMethod.OTHER method"); - } - SocketAddress peerAddress; if (hostHeader != null) { int idx = hostHeader.lastIndexOf(':'); @@ -478,7 +460,7 @@ public class HttpClientRequestImpl extends HttpClientRequestBase implements Http } }; } - stream.writeHead(method, rawMethod, uri, headers, hostHeader(), chunked, pending, ended, priority, handler); + stream.writeHead(method, uri, headers, hostHeader(), chunked, pending, ended, priority, handler); if (ended) { tryComplete(); } diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientRequestPushPromise.java b/src/main/java/io/vertx/core/http/impl/HttpClientRequestPushPromise.java index 5275d3c7b..afdf490c1 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientRequestPushPromise.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientRequestPushPromise.java @@ -27,7 +27,6 @@ class HttpClientRequestPushPromise extends HttpClientRequestBase { private final Http2ClientConnection conn; private final Http2ClientConnection.StreamImpl stream; - private final String rawMethod; private final MultiMap headers; public HttpClientRequestPushPromise( @@ -35,7 +34,6 @@ class HttpClientRequestPushPromise extends HttpClientRequestBase { HttpClientImpl client, boolean ssl, HttpMethod method, - String rawMethod, String uri, String host, int port, @@ -43,7 +41,6 @@ class HttpClientRequestPushPromise extends HttpClientRequestBase { super(client, conn.getContext(), ssl, method, SocketAddress.inetSocketAddress(port, host), host, port, uri); this.conn = conn; this.stream = new Http2ClientConnection.StreamImpl(conn, conn.getContext(), this, null); - this.rawMethod = rawMethod; this.headers = headers; } @@ -82,16 +79,6 @@ class HttpClientRequestPushPromise extends HttpClientRequestBase { return method; } - @Override - public String getRawMethod() { - return rawMethod; - } - - @Override - public HttpClientRequest setRawMethod(String method) { - throw new IllegalStateException(); - } - @Override public String uri() { return uri; diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientStream.java b/src/main/java/io/vertx/core/http/impl/HttpClientStream.java index 482cbf341..0b6107af4 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientStream.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientStream.java @@ -12,17 +12,14 @@ package io.vertx.core.http.impl; import io.netty.buffer.ByteBuf; -import io.netty.util.concurrent.FutureListener; import io.vertx.core.AsyncResult; import io.vertx.core.Handler; import io.vertx.core.MultiMap; -import io.vertx.core.Promise; import io.vertx.core.http.HttpConnection; import io.vertx.core.http.HttpMethod; import io.vertx.core.http.HttpVersion; import io.vertx.core.http.StreamPriority; import io.vertx.core.impl.ContextInternal; -import io.vertx.core.net.NetSocket; /** * @author Julien Viet @@ -45,7 +42,7 @@ public interface HttpClientStream { HttpConnection connection(); ContextInternal getContext(); - void writeHead(HttpMethod method, String rawMethod, String uri, MultiMap headers, String hostHeader, boolean chunked, ByteBuf buf, boolean end, StreamPriority priority, Handler> listener); + void writeHead(HttpMethod method, String uri, MultiMap headers, String hostHeader, boolean chunked, ByteBuf buf, boolean end, StreamPriority priority, Handler> listener); void writeBuffer(ByteBuf buf, boolean end, Handler> listener); void writeFrame(int type, int flags, ByteBuf payload); diff --git a/src/main/java/io/vertx/core/http/impl/HttpMethodImpl.java b/src/main/java/io/vertx/core/http/impl/HttpMethodImpl.java new file mode 100644 index 000000000..bcdd9df9e --- /dev/null +++ b/src/main/java/io/vertx/core/http/impl/HttpMethodImpl.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011-2019 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://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 io.vertx.core.http.impl; + +import io.vertx.core.http.HttpMethod; + +import java.util.Objects; + +public class HttpMethodImpl implements HttpMethod { + + public static io.netty.handler.codec.http.HttpMethod toNetty(HttpMethod method) { + if (method instanceof HttpMethodImpl) { + return ((HttpMethodImpl) method).nettyMethod; + } else { + return io.netty.handler.codec.http.HttpMethod.valueOf(method.name()); + } + } + + /** + * Lookup the {@code HttpMethod} value for the specified {@code nettyMethod}. + *
+ * The predefined method constants {@link #GET}, {@link #POST}, {@link #PUT}, {@link #HEAD}, {@link #OPTIONS}, + * {@link #DELETE}, {@link #TRACE}, {@link #CONNECT} and {@link #PATCH} are interned and will be returned + * when case sensitively matching their string value (i.e {@code "GET"}, etc...) + *
+ * Otherwise a new instance is returned. + * + * @param method the netty method + * @return the {@code HttpMethod} instance for the specified netty {@code method} + */ + public static HttpMethod fromNetty(io.netty.handler.codec.http.HttpMethod method) { + // Fast path + if (method == io.netty.handler.codec.http.HttpMethod.GET) { + return GET; + } else if (method == io.netty.handler.codec.http.HttpMethod.POST) { + return POST; + } else { + // Keep method small + return _fromNetty(method); + } + } + + private static HttpMethod _fromNetty(io.netty.handler.codec.http.HttpMethod sMethod) { + switch (sMethod.name()) { + case "OPTIONS": + return OPTIONS; + case "HEAD": + return HEAD; + case "PUT": + return PUT; + case "DELETE": + return DELETE; + case "TRACE": + return TRACE; + case "CONNECT": + return CONNECT; + case "PATCH": + return PATCH; + default: + return new HttpMethodImpl(sMethod); + } + } + + private final io.netty.handler.codec.http.HttpMethod nettyMethod; + + public HttpMethodImpl(io.netty.handler.codec.http.HttpMethod nettyMethod) { + this.nettyMethod = nettyMethod; + } + + @Override + public String name() { + return nettyMethod.name(); + } + + @Override + public int hashCode() { + return nettyMethod.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof HttpMethod) { + HttpMethod that = (HttpMethod) obj; + return Objects.equals(name(), that.name()); + } + return false; + } + + @Override + public String toString() { + return name(); + } +} diff --git a/src/main/java/io/vertx/core/http/impl/HttpUtils.java b/src/main/java/io/vertx/core/http/impl/HttpUtils.java index 8e118a611..f67918444 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpUtils.java +++ b/src/main/java/io/vertx/core/http/impl/HttpUtils.java @@ -667,41 +667,6 @@ public final class HttpUtils { return null; } - static HttpMethod toNettyHttpMethod(io.vertx.core.http.HttpMethod method, String rawMethod) { - switch (method) { - case CONNECT: { - return HttpMethod.CONNECT; - } - case GET: { - return HttpMethod.GET; - } - case PUT: { - return HttpMethod.PUT; - } - case POST: { - return HttpMethod.POST; - } - case DELETE: { - return HttpMethod.DELETE; - } - case HEAD: { - return HttpMethod.HEAD; - } - case OPTIONS: { - return HttpMethod.OPTIONS; - } - case TRACE: { - return HttpMethod.TRACE; - } - case PATCH: { - return HttpMethod.PATCH; - } - default: { - return HttpMethod.valueOf(rawMethod); - } - } - } - static HttpVersion toNettyHttpVersion(io.vertx.core.http.HttpVersion version) { switch (version) { case HTTP_1_0: { @@ -716,11 +681,7 @@ public final class HttpUtils { } static io.vertx.core.http.HttpMethod toVertxMethod(String method) { - try { - return io.vertx.core.http.HttpMethod.valueOf(method); - } catch (IllegalArgumentException e) { - return io.vertx.core.http.HttpMethod.OTHER; - } + return io.vertx.core.http.HttpMethod.valueOf(method); } private static final AsciiString TIMEOUT_EQ = AsciiString.of("timeout="); diff --git a/src/test/java/io/vertx/core/http/Http1xTest.java b/src/test/java/io/vertx/core/http/Http1xTest.java index d67e836b6..d7350d83f 100644 --- a/src/test/java/io/vertx/core/http/Http1xTest.java +++ b/src/test/java/io/vertx/core/http/Http1xTest.java @@ -3826,7 +3826,7 @@ public class Http1xTest extends HttpTest { @Test public void testPartialH2CAmbiguousRequest() throws Exception { server.requestHandler(req -> { - assertEquals("POST", req.rawMethod()); + assertEquals(HttpMethod.POST, req.method()); testComplete(); }); Buffer fullRequest = Buffer.buffer("POST /whatever HTTP/1.1\r\n\r\n"); diff --git a/src/test/java/io/vertx/core/http/HttpMethodTest.java b/src/test/java/io/vertx/core/http/HttpMethodTest.java new file mode 100644 index 000000000..54449ab72 --- /dev/null +++ b/src/test/java/io/vertx/core/http/HttpMethodTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011-2019 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://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 io.vertx.core.http; + +import io.vertx.core.http.impl.HttpMethodImpl; +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; + +public class HttpMethodTest { + + @Test + public void testConstantNames() { + assertEquals("GET", HttpMethod.GET.name()); + assertEquals("POST", HttpMethod.POST.name()); + assertEquals("PUT", HttpMethod.PUT.name()); + assertEquals("HEAD", HttpMethod.HEAD.name()); + assertEquals("CONNECT", HttpMethod.CONNECT.name()); + assertEquals("DELETE", HttpMethod.DELETE.name()); + assertEquals("OPTIONS", HttpMethod.OPTIONS.name()); + assertEquals("PATCH", HttpMethod.PATCH.name()); + assertEquals("TRACE", HttpMethod.TRACE.name()); + } + + @Test + public void testConstants() { + for (HttpMethod method : Arrays.asList( + HttpMethod.GET, + HttpMethod.POST, + HttpMethod.HEAD, + HttpMethod.PUT, + HttpMethod.CONNECT, + HttpMethod.DELETE, + HttpMethod.OPTIONS, + HttpMethod.PATCH, + HttpMethod.TRACE + )) { + assertSame(HttpMethod.valueOf(method.name()), method); + assertSame(method.name(), method.toString()); + } + } + + @Test + public void testInvalidValueOf() { + for (String method : Arrays.asList("", " ")) { + try { + HttpMethod.valueOf(method); + fail(); + } catch (IllegalArgumentException ignore) { + } + } + try { + HttpMethod.valueOf(null); + fail(); + } catch (NullPointerException ignore) { + } + } + + @Test + public void testValueOf() { + HttpMethod m1 = HttpMethod.valueOf("foo"); + HttpMethod m2 = HttpMethod.valueOf("foo"); + assertEquals("foo", m1.name()); + assertEquals("foo", m1.toString()); + assertNotSame(m1, m2); + assertEquals(m1.hashCode(), m2.hashCode()); + assertEquals(m1, m2); + } + + @Test + public void testCaseSensitive() { + HttpMethod m1 = HttpMethod.valueOf("Foo"); + HttpMethod m2 = HttpMethod.valueOf("foo"); + assertEquals("Foo", m1.name()); + assertEquals("Foo", m1.toString()); + assertNotSame(m1, m2); + assertNotEquals(m1.hashCode(), m2.hashCode()); + assertNotEquals(m1, m2); + } + + @Test + public void testNettyInterop() { + assertSame(HttpMethodImpl.toNetty(HttpMethod.GET), io.netty.handler.codec.http.HttpMethod.GET); + assertSame(HttpMethodImpl.toNetty(HttpMethod.POST), io.netty.handler.codec.http.HttpMethod.POST); + assertSame(HttpMethodImpl.toNetty(HttpMethod.PUT), io.netty.handler.codec.http.HttpMethod.PUT); + assertSame(HttpMethodImpl.toNetty(HttpMethod.HEAD), io.netty.handler.codec.http.HttpMethod.HEAD); + assertSame(HttpMethodImpl.toNetty(HttpMethod.CONNECT), io.netty.handler.codec.http.HttpMethod.CONNECT); + assertSame(HttpMethodImpl.toNetty(HttpMethod.DELETE), io.netty.handler.codec.http.HttpMethod.DELETE); + assertSame(HttpMethodImpl.toNetty(HttpMethod.OPTIONS), io.netty.handler.codec.http.HttpMethod.OPTIONS); + assertSame(HttpMethodImpl.toNetty(HttpMethod.PATCH), io.netty.handler.codec.http.HttpMethod.PATCH); + assertSame(HttpMethodImpl.toNetty(HttpMethod.TRACE), io.netty.handler.codec.http.HttpMethod.TRACE); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.GET), HttpMethod.GET); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.valueOf("GET")), HttpMethod.GET); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.POST), HttpMethod.POST); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.valueOf("POST")), HttpMethod.POST); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.PUT), HttpMethod.PUT); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.valueOf("PUT")), HttpMethod.PUT); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.HEAD), HttpMethod.HEAD); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.CONNECT), HttpMethod.CONNECT); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.DELETE), HttpMethod.DELETE); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.OPTIONS), HttpMethod.OPTIONS); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.PATCH), HttpMethod.PATCH); + assertSame(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.TRACE), HttpMethod.TRACE); + assertEquals(HttpMethodImpl.toNetty(HttpMethod.valueOf("foo")).name(), "foo"); + assertEquals(HttpMethodImpl.fromNetty(io.netty.handler.codec.http.HttpMethod.valueOf("foo")).name(), "foo"); + } +} diff --git a/src/test/java/io/vertx/core/http/HttpTest.java b/src/test/java/io/vertx/core/http/HttpTest.java index 9b94717a7..7e67b326d 100644 --- a/src/test/java/io/vertx/core/http/HttpTest.java +++ b/src/test/java/io/vertx/core/http/HttpTest.java @@ -3494,26 +3494,15 @@ public abstract class HttpTest extends HttpTestBase { await(); } - @Test - public void testOtherMethodWithRawMethod() { - try { - client.request(HttpMethod.OTHER, testAddress, DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/somepath", resp -> { - }).end(); - fail(); - } catch (IllegalStateException expected) { - } - } - @Test public void testOtherMethodRequest() { server.requestHandler(r -> { - assertEquals(HttpMethod.OTHER, r.method()); - assertEquals("COPY", r.rawMethod()); + assertEquals("COPY", r.method().name()); r.response().end(); }).listen(testAddress, onSuccess(s -> { - client.request(HttpMethod.OTHER, testAddress, DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/somepath", onSuccess(resp -> { + client.request(HttpMethod.valueOf("COPY"), testAddress, DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/somepath", onSuccess(resp -> { testComplete(); - })).setRawMethod("COPY").end(); + })).end(); })); await(); } diff --git a/src/test/java/io/vertx/core/json/JsonCodecTest.java b/src/test/java/io/vertx/core/json/JsonCodecTest.java index ac2418969..5a6850c18 100644 --- a/src/test/java/io/vertx/core/json/JsonCodecTest.java +++ b/src/test/java/io/vertx/core/json/JsonCodecTest.java @@ -12,7 +12,7 @@ package io.vertx.core.json; import com.fasterxml.jackson.core.type.TypeReference; import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.WebsocketVersion; import io.vertx.core.impl.Utils; import io.vertx.core.json.jackson.DatabindCodec; import io.vertx.core.json.jackson.JacksonCodec; @@ -401,9 +401,9 @@ public class JsonCodecTest { @Test public void testEnumValue() { // just a random enum - Buffer json = mapper.toBuffer(HttpMethod.CONNECT); + Buffer json = mapper.toBuffer(WebsocketVersion.V13); assertNotNull(json); - assertEquals("\"CONNECT\"", json.toString()); + assertEquals("\"V13\"", json.toString()); } @Test