Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
trustin committed Dec 3, 2015
1 parent af5c48a commit 296a14a
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 2 deletions.
69 changes: 69 additions & 0 deletions src/main/java/com/linecorp/armeria/server/http/HttpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,20 @@

import static java.util.Objects.requireNonNull;

import java.util.concurrent.Executor;

import com.linecorp.armeria.common.ServiceInvocationContext;
import com.linecorp.armeria.common.SessionProtocol;
import com.linecorp.armeria.server.ServerPort;
import com.linecorp.armeria.server.Service;
import com.linecorp.armeria.server.ServiceCodec;
import com.linecorp.armeria.server.ServiceInvocationHandler;

import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;

/**
* A {@link Service} that handles an HTTP request. This {@link Service} must run on a {@link ServerPort}
* whose {@link SessionProtocol} is {@linkplain SessionProtocol#ofHttp() HTTP}.
Expand Down Expand Up @@ -69,8 +77,69 @@ public ServiceInvocationHandler handler() {
return handler;
}

public HttpService orElse(HttpService nextService) {
return new HttpService(new OrElseHandler(handler(), nextService.handler()));
}

@Override
public String toString() {
return "HttpService(" + handler().getClass().getSimpleName() + ')';
}

private static final class OrElseHandler implements ServiceInvocationHandler {

private final ServiceInvocationHandler first;
private final ServiceInvocationHandler second;

OrElseHandler(ServiceInvocationHandler first, ServiceInvocationHandler second) {
this.first = first;
this.second = second;
}

@Override
public void invoke(ServiceInvocationContext ctx,
Executor blockingTaskExecutor, Promise<Object> promise) throws Exception {

invoke0(ctx, blockingTaskExecutor, promise, first, second);
}

private void invoke0(ServiceInvocationContext ctx, Executor blockingTaskExecutor, Promise<Object> promise,
ServiceInvocationHandler subHandler,
ServiceInvocationHandler nextSubHandler) throws Exception {

Promise<Object> subPromise = ctx.eventLoop().newPromise();
subHandler.invoke(ctx, blockingTaskExecutor, subPromise);
if (subPromise.isDone()) {
handleResponse(ctx, blockingTaskExecutor, promise, subPromise, nextSubHandler);
} else {
subPromise.addListener(
future -> handleResponse(ctx, blockingTaskExecutor, promise, future, nextSubHandler));
}
}

void handleResponse(ServiceInvocationContext ctx, Executor blockingTaskExecutor, Promise<Object> promise,
Future<Object> subFuture, ServiceInvocationHandler nextSubHandler) throws Exception {

if (!subFuture.isSuccess()) {
// sub-handler failed with an exception.
promise.tryFailure(subFuture.cause());
return;
}

final FullHttpResponse res = (FullHttpResponse) subFuture.getNow();
if (nextSubHandler != null && res.status().code() == HttpResponseStatus.NOT_FOUND.code()) {
// The current sub-handler returned 404. Try the next sub-handler.
res.release();
if (!promise.isDone()) {
invoke0(ctx, blockingTaskExecutor, promise, nextSubHandler, null);
}
return;
}

// The current sub-handler returned non-404 or it is the last resort.
if (!promise.trySuccess(res)) {
res.release();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,12 @@ public class HttpFileServiceTest {
"/fs/",
HttpFileService.forFileSystem(tmpDir.toPath()).decorate(LoggingService::new));

final String baseResourceDir = HttpFileServiceTest.class.getPackage().getName().replace('.', '/');
defaultVirtualHost.serviceUnder(
"/",
HttpFileService.forClassPath("/http_file_service").decorate(LoggingService::new));
HttpFileService.forClassPath(baseResourceDir + "/foo")
.orElse(HttpFileService.forClassPath(baseResourceDir + "/bar"))
.decorate(LoggingService::new));

sb.defaultVirtualHost(defaultVirtualHost.build());
} catch (Exception e) {
Expand Down Expand Up @@ -120,7 +123,7 @@ public void testClassPathGet() throws Exception {
try (CloseableHttpClient hc = HttpClients.createMinimal()) {
final String lastModified;
try (CloseableHttpResponse res = hc.execute(new HttpGet(newUri("/foo.txt")))) {
lastModified = assert200Ok(res, "text/plain", "bar");
lastModified = assert200Ok(res, "text/plain", "foo");
}

// Test if the 'If-Modified-Since' header works as expected.
Expand All @@ -134,6 +137,16 @@ public void testClassPathGet() throws Exception {
}
}

@Test
public void testClassPathOrElseGet() throws Exception {
try (CloseableHttpClient hc = HttpClients.createMinimal()) {
final String lastModified;
try (CloseableHttpResponse res = hc.execute(new HttpGet(newUri("/bar.txt")))) {
lastModified = assert200Ok(res, "text/plain", "bar");
}
}
}

@Test
public void testFileSystemGet() throws Exception {
final File barFile = new File(tmpDir, "bar.html");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo

0 comments on commit 296a14a

Please sign in to comment.