Skip to content

Commit

Permalink
Added support for the missing HTTP verbs (issue #30).
Browse files Browse the repository at this point in the history
  • Loading branch information
nmihajlovski committed Nov 25, 2015
1 parent f00b25a commit e8816e7
Show file tree
Hide file tree
Showing 6 changed files with 373 additions and 75 deletions.
Expand Up @@ -78,27 +78,26 @@ public class FastHttp implements Protocol, HttpMetadata {


private static final HttpParser HTTP_PARSER = Wire.singleton(HttpParser.class); private static final HttpParser HTTP_PARSER = Wire.singleton(HttpParser.class);


private static final byte[] POST = "POST".getBytes(); private static final byte[] _POST = "POST".getBytes();

private static final byte[] _PUT = "PUT".getBytes();
private static final byte[] PUT = "PUT".getBytes(); private static final byte[] _DELETE = "DELETE".getBytes();

private static final byte[] _PATCH = "PATCH".getBytes();
private static final byte[] DELETE = "DELETE".getBytes(); private static final byte[] _OPTIONS = "OPTIONS".getBytes();

private static final byte[] _HEAD = "HEAD".getBytes();
private static final byte[] OPTIONS = "OPTIONS".getBytes(); private static final byte[] _TRACE = "TRACE".getBytes();


private static final byte[][] CONTENT_LENGTHS = new byte[CONTENT_LENGTHS_SIZE][]; private static final byte[][] CONTENT_LENGTHS = new byte[CONTENT_LENGTHS_SIZE][];


private final HttpResponseCodes responseCodes = new HttpResponseCodes(); private final HttpResponseCodes responseCodes = new HttpResponseCodes();


private final BufMap<FastHttpHandler> getHandlers = new BufMapImpl<FastHttpHandler>(); private final BufMap<FastHttpHandler> getHandlers = new BufMapImpl<FastHttpHandler>();

private final BufMap<FastHttpHandler> postHandlers = new BufMapImpl<FastHttpHandler>(); private final BufMap<FastHttpHandler> postHandlers = new BufMapImpl<FastHttpHandler>();

private final BufMap<FastHttpHandler> putHandlers = new BufMapImpl<FastHttpHandler>(); private final BufMap<FastHttpHandler> putHandlers = new BufMapImpl<FastHttpHandler>();

private final BufMap<FastHttpHandler> deleteHandlers = new BufMapImpl<FastHttpHandler>(); private final BufMap<FastHttpHandler> deleteHandlers = new BufMapImpl<FastHttpHandler>();

private final BufMap<FastHttpHandler> patchHandlers = new BufMapImpl<FastHttpHandler>();
private final BufMap<FastHttpHandler> optionsHandlers = new BufMapImpl<FastHttpHandler>(); private final BufMap<FastHttpHandler> optionsHandlers = new BufMapImpl<FastHttpHandler>();
private final BufMap<FastHttpHandler> headHandlers = new BufMapImpl<FastHttpHandler>();
private final BufMap<FastHttpHandler> traceHandlers = new BufMapImpl<FastHttpHandler>();


private volatile byte[] path1, path2, path3; private volatile byte[] path1, path2, path3;


Expand Down Expand Up @@ -147,9 +146,18 @@ public synchronized void on(String verb, String path, FastHttpHandler handler) {
} else if (verb.equals("DELETE")) { } else if (verb.equals("DELETE")) {
deleteHandlers.put(path, handler); deleteHandlers.put(path, handler);


} else if (verb.equals("PATCH")) {
patchHandlers.put(path, handler);

} else if (verb.equals("OPTIONS")) { } else if (verb.equals("OPTIONS")) {
optionsHandlers.put(path, handler); optionsHandlers.put(path, handler);


} else if (verb.equals("HEAD")) {
headHandlers.put(path, handler);

} else if (verb.equals("TRACE")) {
traceHandlers.put(path, handler);

} else { } else {
throw U.rte("Unsupported HTTP verb: %s", verb); throw U.rte("Unsupported HTTP verb: %s", verb);
} }
Expand Down Expand Up @@ -297,14 +305,26 @@ private FastHttpHandler findFandler(Channel ctx, Buf buf, BoolWrap isGet, Range
return getHandler; return getHandler;
} }


} else if (BytesUtil.matches(bytes, verb, POST, true)) { } else if (BytesUtil.matches(bytes, verb, _POST, true)) {
return postHandlers.get(buf, path); return postHandlers.get(buf, path);
} else if (BytesUtil.matches(bytes, verb, PUT, true)) {
} else if (BytesUtil.matches(bytes, verb, _PUT, true)) {
return putHandlers.get(buf, path); return putHandlers.get(buf, path);
} else if (BytesUtil.matches(bytes, verb, DELETE, true)) {
} else if (BytesUtil.matches(bytes, verb, _DELETE, true)) {
return deleteHandlers.get(buf, path); return deleteHandlers.get(buf, path);
} else if (BytesUtil.matches(bytes, verb, OPTIONS, true)) {
} else if (BytesUtil.matches(bytes, verb, _PATCH, true)) {
return patchHandlers.get(buf, path);

} else if (BytesUtil.matches(bytes, verb, _OPTIONS, true)) {
return optionsHandlers.get(buf, path); return optionsHandlers.get(buf, path);

} else if (BytesUtil.matches(bytes, verb, _HEAD, true)) {
return headHandlers.get(buf, path);

} else if (BytesUtil.matches(bytes, verb, _TRACE, true)) {
return traceHandlers.get(buf, path);
} }


return null; // no handler return null; // no handler
Expand Down
12 changes: 12 additions & 0 deletions rapidoid-http-fast/src/main/java/org/rapidoid/http/fast/On.java
Expand Up @@ -70,10 +70,22 @@ public static synchronized OnAction delete(String path) {
return setup().delete(path); return setup().delete(path);
} }


public static synchronized OnAction patch(String path) {
return setup().patch(path);
}

public static synchronized OnAction options(String path) { public static synchronized OnAction options(String path) {
return setup().options(path); return setup().options(path);
} }


public static synchronized OnAction head(String path) {
return setup().head(path);
}

public static synchronized OnAction trace(String path) {
return setup().trace(path);
}

public static synchronized OnPage page(String path) { public static synchronized OnPage page(String path) {
return setup().page(path); return setup().page(path);
} }
Expand Down
Expand Up @@ -83,10 +83,22 @@ public OnAction delete(String path) {
return new OnAction(this, httpImpls(), "DELETE", path).wrap(wrappers); return new OnAction(this, httpImpls(), "DELETE", path).wrap(wrappers);
} }


public OnAction patch(String path) {
return new OnAction(this, httpImpls(), "PATCH", path).wrap(wrappers);
}

public OnAction options(String path) { public OnAction options(String path) {
return new OnAction(this, httpImpls(), "OPTIONS", path).wrap(wrappers); return new OnAction(this, httpImpls(), "OPTIONS", path).wrap(wrappers);
} }


public OnAction head(String path) {
return new OnAction(this, httpImpls(), "HEAD", path).wrap(wrappers);
}

public OnAction trace(String path) {
return new OnAction(this, httpImpls(), "TRACE", path).wrap(wrappers);
}

public OnPage page(String path) { public OnPage page(String path) {
return new OnPage(this, httpImpls(), path).wrap(wrappers); return new OnPage(this, httpImpls(), path).wrap(wrappers);
} }
Expand Down Expand Up @@ -124,6 +136,24 @@ public ServerSetup listener(FastHttpListener listener) {
return this; return this;
} }


public ServerSetup shutdown() {
reset();
this.server.shutdown();
return this;
}

public ServerSetup halt() {
reset();
this.server.halt();
return this;
}

private void reset() {
listening = false;
fastHttp = null;
wrappers = null;
}

public TCPServer server() { public TCPServer server() {
return server; return server;
} }
Expand Down
@@ -0,0 +1,56 @@
package org.rapidoid.test;

/*
* #%L
* rapidoid-integration-tests
* %%
* Copyright (C) 2014 - 2015 Nikolche Mihajlovski and contributors
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/

import org.junit.Test;
import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.http.HTTP;
import org.rapidoid.http.fast.On;

@Authors("Nikolche Mihajlovski")
@Since("5.0.5")
public class HttpVerbsTest extends TestCommons {

@Test
public void testHttpVerbs() {
On.get("/testGet").plain("get:success");
On.post("/testPost").plain("post:success");
On.put("/testPut").plain("put:success");
On.delete("/testDelete").plain("delete:success");
On.patch("/testPatch").plain("patch:success");
On.options("/testOptions").plain("options:success");
On.head("/testHead").plain(""); // no body for the HEAD verb
On.trace("/testTrace").plain("trace:success");

eq(new String(HTTP.get("http://localhost:8888/testGet")), "get:success");
eq(new String(HTTP.post("http://localhost:8888/testPost")), "post:success");
eq(new String(HTTP.put("http://localhost:8888/testPut")), "put:success");
eq(new String(HTTP.delete("http://localhost:8888/testDelete")), "delete:success");
eq(new String(HTTP.patch("http://localhost:8888/testPatch")), "patch:success");
eq(new String(HTTP.options("http://localhost:8888/testOptions")), "options:success");
eq(new String(HTTP.head("http://localhost:8888/testHead")), ""); // no body for the HEAD verb
eq(new String(HTTP.trace("http://localhost:8888/testTrace")), "trace:success");

On.getDefaultSetup().shutdown();
}

}
102 changes: 98 additions & 4 deletions rapidoid-rest/src/main/java/org/rapidoid/http/HTTP.java
Expand Up @@ -49,6 +49,46 @@ public static byte[] get(String uri) {
return get(uri, null).get(); return get(uri, null).get();
} }


/********************************** DELETE **********************************/

public static Future<byte[]> delete(String uri, Callback<byte[]> callback) {
return DEFAULT_CLIENT.delete(uri, callback);
}

public static byte[] delete(String uri) {
return delete(uri, null).get();
}

/********************************** OPTIONS **********************************/

public static Future<byte[]> options(String uri, Callback<byte[]> callback) {
return DEFAULT_CLIENT.options(uri, callback);
}

public static byte[] options(String uri) {
return options(uri, null).get();
}

/********************************** HEAD **********************************/

public static Future<byte[]> head(String uri, Callback<byte[]> callback) {
return DEFAULT_CLIENT.head(uri, callback);
}

public static byte[] head(String uri) {
return head(uri, null).get();
}

/********************************** TRACE **********************************/

public static Future<byte[]> trace(String uri, Callback<byte[]> callback) {
return DEFAULT_CLIENT.trace(uri, callback);
}

public static byte[] trace(String uri) {
return trace(uri, null).get();
}

/********************************** POST **********************************/ /********************************** POST **********************************/


public static Future<byte[]> post(String uri, Map<String, String> headers, Map<String, String> data, public static Future<byte[]> post(String uri, Map<String, String> headers, Map<String, String> data,
Expand All @@ -61,13 +101,67 @@ public static byte[] post(String uri, Map<String, String> headers, Map<String, S
return post(uri, headers, data, files, null).get(); return post(uri, headers, data, files, null).get();
} }


public static Future<byte[]> post(String uri, Map<String, String> headers, byte[] postData, String contentType, public static Future<byte[]> post(String uri, Map<String, String> headers, byte[] body, String contentType,
Callback<byte[]> callback) {
return DEFAULT_CLIENT.post(uri, headers, body, contentType, callback);
}

public static byte[] post(String uri, Map<String, String> headers, byte[] body, String contentType) {
return post(uri, headers, body, contentType, null).get();
}

public static byte[] post(String uri) {
return post(uri, null, (byte[]) null, null, null).get();
}

/********************************** PUT **********************************/

public static Future<byte[]> put(String uri, Map<String, String> headers, Map<String, String> data,
Map<String, String> files, Callback<byte[]> callback) {
return DEFAULT_CLIENT.put(uri, headers, data, files, callback);
}

public static byte[] put(String uri, Map<String, String> headers, Map<String, String> data,
Map<String, String> files) {
return put(uri, headers, data, files, null).get();
}

public static Future<byte[]> put(String uri, Map<String, String> headers, byte[] body, String contentType,
Callback<byte[]> callback) { Callback<byte[]> callback) {
return DEFAULT_CLIENT.post(uri, headers, postData, contentType, callback); return DEFAULT_CLIENT.put(uri, headers, body, contentType, callback);
}

public static byte[] put(String uri, Map<String, String> headers, byte[] body, String contentType) {
return put(uri, headers, body, contentType, null).get();
}

public static byte[] put(String uri) {
return put(uri, null, (byte[]) null, null, null).get();
}

/********************************** PATCH **********************************/

public static Future<byte[]> patch(String uri, Map<String, String> headers, Map<String, String> data,
Map<String, String> files, Callback<byte[]> callback) {
return DEFAULT_CLIENT.patch(uri, headers, data, files, callback);
}

public static byte[] patch(String uri, Map<String, String> headers, Map<String, String> data,
Map<String, String> files) {
return patch(uri, headers, data, files, null).get();
}

public static Future<byte[]> patch(String uri, Map<String, String> headers, byte[] body, String contentType,
Callback<byte[]> callback) {
return DEFAULT_CLIENT.patch(uri, headers, body, contentType, callback);
}

public static byte[] patch(String uri, Map<String, String> headers, byte[] body, String contentType) {
return patch(uri, headers, body, contentType, null).get();
} }


public static byte[] post(String uri, Map<String, String> headers, byte[] postData, String contentType) { public static byte[] patch(String uri) {
return post(uri, headers, postData, contentType, null).get(); return patch(uri, null, (byte[]) null, null, null).get();
} }


} }

0 comments on commit e8816e7

Please sign in to comment.