Skip to content

Commit

Permalink
Added low-level fast HTTP interception/listening mechanism.
Browse files Browse the repository at this point in the history
  • Loading branch information
nmihajlovski committed Nov 14, 2015
1 parent 3102136 commit 2b86342
Show file tree
Hide file tree
Showing 11 changed files with 236 additions and 20 deletions.
Expand Up @@ -37,9 +37,9 @@
@Since("4.3.0")
public abstract class AbstractAsyncHttpHandler extends AbstractFastHttpHandler {

private final FastHttp http;
protected final FastHttp http;

private final byte[] contentType;
protected final byte[] contentType;

protected final HttpWrapper[] wrappers;

Expand Down Expand Up @@ -111,15 +111,28 @@ private Object wrap(final Channel ctx, final Map<String, Object> params, final i
public Object invoke(Mapper<Object, Object> transformation) throws Exception {
try {
int next = index + 1;
Object val = next < wrappers.length ? wrap(ctx, params, next) : handleReq(ctx, params);

Object val;
if (next < wrappers.length) {
val = wrap(ctx, params, next);
} else {
val = handleReq(ctx, params);
}

return transformation.map(val);
} catch (Exception e) {
return e;
}
}
};

return wrapper.wrap(params, process);
http.getListener().entering(wrapper, params);

Object result = wrapper.wrap(params, process);

http.getListener().leaving(wrapper, contentType, result);

return result;
}

protected abstract Object handleReq(Channel ctx, Map<String, Object> params) throws Exception;
Expand Down
Expand Up @@ -102,20 +102,25 @@ public class FastHttp implements Protocol, HttpMetadata {

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

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

private FastHttpHandler handler1, handler2, handler3;
private volatile FastHttpHandler handler1, handler2, handler3;

private final FastHttpHandler staticResourcesHandler = new FastStaticResourcesHandler(this);
private volatile FastHttpHandler staticResourcesHandler = new FastStaticResourcesHandler(this);

private final FastHttpListener listener;

static {
for (int len = 0; len < CONTENT_LENGTHS.length; len++) {
CONTENT_LENGTHS[len] = (new String(CONTENT_LENGTH_IS) + len + new String(CR_LF)).getBytes();
}
}

public synchronized void on(String verb, String path, FastHttpHandler handler) {
public FastHttp(FastHttpListener listener) {
this.listener = listener;
}

public synchronized void on(String verb, String path, FastHttpHandler handler) {
if (verb.equals("GET")) {
if (path1 == null) {
path1 = path.getBytes();
Expand Down Expand Up @@ -173,6 +178,11 @@ public void process(Channel ctx) {

HTTP_PARSER.parse(buf, isGet, isKeepAlive, body, verb, uri, path, query, protocol, hdrs, helper);

// the listener may override all the request dispatching and handler execution
if (!listener.request(this, ctx, isGet, isKeepAlive, body, verb, uri, path, query, protocol, hdrs)) {
return;
}

HttpStatus status = HttpStatus.NOT_FOUND;

FastHttpHandler handler = findFandler(ctx, buf, isGet, verb, path);
Expand Down Expand Up @@ -241,6 +251,7 @@ public void process(Channel ctx) {

if (status == HttpStatus.NOT_FOUND) {
ctx.write(HTTP_404_NOT_FOUND);
listener.notFound(this, ctx, isGet, isKeepAlive, body, verb, uri, path, query, protocol, hdrs);
}

if (status != HttpStatus.ASYNC) {
Expand Down Expand Up @@ -330,11 +341,13 @@ private void addCustomHeader(Channel ctx, byte[] name, byte[] value) {
public void write200(Channel ctx, boolean isKeepAlive, byte[] contentTypeHeader, byte[] content) {
start200(ctx, isKeepAlive, contentTypeHeader);
writeContent(ctx, content);
listener.onOkResponse(contentTypeHeader, content);
}

public void write500(Channel ctx, boolean isKeepAlive, byte[] contentTypeHeader, byte[] content) {
start500(ctx, isKeepAlive, contentTypeHeader);
writeContent(ctx, content);
listener.onErrorResponse(500, contentTypeHeader, content);
}

public HttpStatus error(Channel ctx, boolean isKeepAlive, Throwable error) {
Expand Down Expand Up @@ -394,4 +407,7 @@ public void done(Channel ctx, boolean isKeepAlive) {
ctx.closeIf(!isKeepAlive);
}

public FastHttpListener getListener() {
return listener;
}
}
@@ -0,0 +1,56 @@
package org.rapidoid.http.fast;

/*
* #%L
* rapidoid-http-fast
* %%
* 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 java.util.Map;

import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.data.Range;
import org.rapidoid.data.Ranges;
import org.rapidoid.net.abstracts.Channel;
import org.rapidoid.wrap.BoolWrap;

@Authors("Nikolche Mihajlovski")
@Since("5.0.2")
public interface FastHttpListener {

boolean request(FastHttp http, Channel channel, BoolWrap isGet, BoolWrap isKeepAlive, Range body, Range verb,
Range uri, Range path, Range query, Range protocol, Ranges hdrs);

void notFound(FastHttp fastHttp, Channel ctx, BoolWrap isGet, BoolWrap isKeepAlive, Range body, Range verb,
Range uri, Range path, Range query, Range protocol, Ranges hdrs);

void state(FastHttpHandler handler, Map<String, Object> state);

void result(FastHttpHandler handler, byte[] contentType, Object result);

void entering(HttpWrapper wrapper, Map<String, Object> state);

void leaving(HttpWrapper wrapper, byte[] contentType, Object result);

void resultNotFound(FastHttpHandler handler);

void onOkResponse(byte[] contentType, byte[] content);

void onErrorResponse(int code, byte[] contentType, byte[] content);

}
Expand Up @@ -39,7 +39,12 @@ public FastParamsAwareHttpHandler(FastHttp http, byte[] contentType, HttpWrapper

@Override
protected Object handleReq(Channel channel, Map<String, Object> params) throws Exception {
return handler.handle(params);
http.getListener().state(this, params);

Object result = handler.handle(params);

http.getListener().result(this, contentType, result);
return result;
}

@Override
Expand Down
Expand Up @@ -39,8 +39,13 @@ public FastParamsAwarePageHandler(FastHttp http, byte[] contentType, HttpWrapper

@Override
protected Object handleReq(Channel channel, Map<String, Object> params) throws Exception {
http.getListener().state(this, params);

// call the handler, get the result
return handler.handle(params);
Object result = handler.handle(params);

http.getListener().result(this, contentType, result);
return result;
}

@Override
Expand Down
Expand Up @@ -45,12 +45,16 @@ public FastResourceHttpHandler(FastHttp http, byte[] contentType, Res resource)

@Override
public HttpStatus handle(Channel ctx, boolean isKeepAlive, Map<String, Object> params) {
http.getListener().state(this, params);

byte[] bytes = resource.getBytesOrNull();

if (bytes != null) {
http.getListener().result(this, contentType, bytes);
http.write200(ctx, isKeepAlive, contentType, bytes);
return HttpStatus.DONE;
} else {
http.getListener().resultNotFound(this);
return HttpStatus.NOT_FOUND;
}
}
Expand Down
Expand Up @@ -44,7 +44,11 @@ public FastStaticHttpHandler(FastHttp http, byte[] contentType, byte[] response)

@Override
public HttpStatus handle(Channel ctx, boolean isKeepAlive, Map<String, Object> params) {
http.getListener().state(this, params);

http.getListener().result(this, contentType, response);
http.write200(ctx, isKeepAlive, contentType, response);

return HttpStatus.DONE;
}

Expand Down
Expand Up @@ -40,15 +40,19 @@ public FastStaticResourcesHandler(FastHttp http) {

@Override
public HttpStatus handle(Channel ctx, boolean isKeepAlive, Map<String, Object> params) {
http.getListener().state(this, params);

try {
Res res = HttpUtils.staticPage(params);
byte[] bytes = res.getBytesOrNull();

if (bytes != null) {
byte[] contentType = MediaType.getByFileName(res.getShortName()).asHttpHeader();
http.getListener().result(this, contentType, bytes);
http.write200(ctx, isKeepAlive, contentType, bytes);
return HttpStatus.DONE;
} else {
http.getListener().resultNotFound(this);
return HttpStatus.NOT_FOUND;
}
} catch (Exception e) {
Expand Down
@@ -0,0 +1,84 @@
package org.rapidoid.http.fast;

/*
* #%L
* rapidoid-http-fast
* %%
* 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 java.util.Map;

import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.data.Range;
import org.rapidoid.data.Ranges;
import org.rapidoid.net.abstracts.Channel;
import org.rapidoid.wrap.BoolWrap;

@Authors("Nikolche Mihajlovski")
@Since("5.0.2")
public class IgnorantHttpListener implements FastHttpListener {

@Override
public void onOkResponse(byte[] contentType, byte[] content) {
// do nothing
}

@Override
public void onErrorResponse(int code, byte[] contentType, byte[] content) {
// do nothing
}

@Override
public boolean request(FastHttp http, Channel channel, BoolWrap isGet, BoolWrap isKeepAlive, Range body,
Range verb, Range uri, Range path, Range query, Range protocol, Ranges hdrs) {
// do nothing
return true; // continue with normal request processing
}

@Override
public void state(FastHttpHandler handler, Map<String, Object> state) {
// do nothing
}

@Override
public void notFound(FastHttp fastHttp, Channel ctx, BoolWrap isGet, BoolWrap isKeepAlive, Range body, Range verb,
Range uri, Range path, Range query, Range protocol, Ranges hdrs) {
// do nothing
}

@Override
public void result(FastHttpHandler handler, byte[] contentType, Object result) {
// do nothing
}

@Override
public void resultNotFound(FastHttpHandler handler) {
// do nothing
}

@Override
public void entering(HttpWrapper wrapper, Map<String, Object> state) {
// do nothing
}

@Override
public void leaving(HttpWrapper wrapper, byte[] contentType, Object result) {
// do nothing
}

}
16 changes: 12 additions & 4 deletions rapidoid-http-fast/src/main/java/org/rapidoid/http/fast/On.java
Expand Up @@ -42,10 +42,6 @@ private static ServerSetup setup() {
return DEFAULT_SERVER_SETUP;
}

public static ServerSetup custom() {
return new ServerSetup();
}

private static void initialize() {
DEFAULT_SERVER_SETUP.listen();

Expand Down Expand Up @@ -93,4 +89,16 @@ public static synchronized ServerSetup defaultWrap(HttpWrapper... wrappers) {
return DEFAULT_SERVER_SETUP.defaultWrap(wrappers);
}

public static synchronized ServerSetup listener(FastHttpListener listener) {
return DEFAULT_SERVER_SETUP.listener(listener);
}

public static synchronized ServerSetup getDefaultSetup() {
return setup();
}

public static ServerSetup createCustomSetup() {
return new ServerSetup();
}

}

0 comments on commit 2b86342

Please sign in to comment.