Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WebServiceHandler interface. #416

Merged
merged 5 commits into from
Jun 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright (C) 2013-2019 Expedia Inc.

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.
*/
package com.hotels.styx.api;

/**
* A web service handler that handles a {@link HttpRequest}, returning an {@link Eventual} that is expected to publish
* a single {@link HttpResponse} value.
*/
@FunctionalInterface
public interface WebServiceHandler {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don´t know if this "Web service" describes the functionality correctly. The handler does not have to be used to implement web services, and a webservice might need to stream the body of the request. I guess we should describe that´s a handler that works in a non-streaming fashion.

However I am also wondering if this is the best way to fix the issue... couldn´t it appear in cases in which we cannot use a WebserviceHandler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @dvlato.

  • I'm not 100% happy with this name either. Seems contrived. However it hints at most likely usage: web service endpoints which usually deal with finite sized objects. Should we consider naming it to StaticHttpHandler or something similar? WDYT?

  • You are correct. There are cases where an HttpRequest can trigger a streaming LiveHttpRequest, and this interface won't help there. However being pragmatic, just look at our admin interface. This new interface caters for pretty every admin interface use case. Also going forward we need to improve the bridging between HttpHandler and WebServiceHandler. Please share any other ideas :-)

  • Also worth noticing I'm not attempting to solve every content body issue in this PR. Just trying getting the admin interface (low hanging fruit) sorted. I still need to do more follow on work to cover the rest.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StaticHttpHandler could be ok in this case.

/**
* Processes an incoming request.
*
* @param request the current incoming request
* @return an {@link Eventual} that is expected to publish a single response
*/
Eventual<HttpResponse> handle(HttpRequest request, HttpInterceptor.Context context);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (C) 2013-2018 Expedia Inc.
Copyright (C) 2013-2019 Expedia Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -18,18 +18,19 @@
import com.hotels.styx.api.Eventual;
import com.hotels.styx.api.HttpHandler;
import com.hotels.styx.api.HttpInterceptor;
import com.hotels.styx.api.LiveHttpRequest;
import com.hotels.styx.api.LiveHttpResponse;
import com.hotels.styx.api.HttpRequest;
import com.hotels.styx.api.HttpResponse;
import com.hotels.styx.api.WebServiceHandler;

/**
* This class provides a skeleton implementation of the {@link HttpHandler} interface, that can be used when no
* complex {@link Eventual} mechanism is required.
*/
public abstract class BaseHttpHandler implements HttpHandler {
public abstract class BaseHttpHandler implements WebServiceHandler {

@Override
public Eventual<LiveHttpResponse> handle(LiveHttpRequest request, HttpInterceptor.Context context) {
return Eventual.of(doHandle(request));
public Eventual<HttpResponse> handle(HttpRequest request, HttpInterceptor.Context context) {
return Eventual.of(doHandle(request, context));
}

/**
Expand All @@ -38,5 +39,5 @@ public Eventual<LiveHttpResponse> handle(LiveHttpRequest request, HttpIntercepto
* @param request request
* @return response
*/
protected abstract LiveHttpResponse doHandle(LiveHttpRequest request);
protected abstract HttpResponse doHandle(HttpRequest request, HttpInterceptor.Context context);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright (C) 2013-2019 Expedia Inc.

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.
*/
package com.hotels.styx.common.http.handler;

import com.hotels.styx.api.Eventual;
import com.hotels.styx.api.HttpHandler;
import com.hotels.styx.api.HttpInterceptor;
import com.hotels.styx.api.HttpResponse;
import com.hotels.styx.api.LiveHttpRequest;
import com.hotels.styx.api.LiveHttpResponse;
import com.hotels.styx.api.WebServiceHandler;

import static java.util.Objects.requireNonNull;

/**
* Adapts a static WebServiceHandler to streaming HttpHandler interface.
*/
public class HttpAggregator implements HttpHandler {

private static final int KILOBYTE = 1024;

private final WebServiceHandler delegate;
private final int bytes;

/**
* HttpAggregator Constructor.
*
* @param bytes max number of bytes to aggregate
* @param delegate adapted WebServiceHandler endpoint
*/
public HttpAggregator(int bytes, WebServiceHandler delegate) {
this.delegate = requireNonNull(delegate);
this.bytes = bytes;
}

/**
* HttpAggregator constructor.
*
* @param delegate adapted WebServiceHandler endpoint
*/
public HttpAggregator(WebServiceHandler delegate) {
this(120 * KILOBYTE, delegate);
}

@Override
public Eventual<LiveHttpResponse> handle(LiveHttpRequest request, HttpInterceptor.Context context) {
return request.aggregate(bytes)
.flatMap(aggregated -> this.delegate.handle(aggregated, context))
.map(HttpResponse::stream);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (C) 2013-2018 Expedia Inc.
Copyright (C) 2013-2019 Expedia Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -15,13 +15,12 @@
*/
package com.hotels.styx.common.http.handler;

import com.hotels.styx.api.HttpResponse;
import com.hotels.styx.api.HttpHandler;
import com.hotels.styx.api.HttpInterceptor;
import com.hotels.styx.api.LiveHttpRequest;
import com.hotels.styx.api.LiveHttpResponse;
import com.hotels.styx.api.Eventual;
import com.hotels.styx.api.HttpInterceptor;
import com.hotels.styx.api.HttpMethod;
import com.hotels.styx.api.HttpRequest;
import com.hotels.styx.api.HttpResponse;
import com.hotels.styx.api.WebServiceHandler;

import java.nio.charset.StandardCharsets;

Expand All @@ -33,25 +32,24 @@
* A handler that checks whether incoming messages have the expected HTTP method. If the method is correct, this handler
* delegates to its child handler. Otherwise, it responds with a 405 error.
*/
public class HttpMethodFilteringHandler implements HttpHandler {
public class HttpMethodFilteringHandler implements WebServiceHandler {
private final HttpMethod method;
private final HttpHandler httpHandler;
private final WebServiceHandler httpHandler;
private final String errorBody;

public HttpMethodFilteringHandler(HttpMethod method, HttpHandler httpHandler) {
public HttpMethodFilteringHandler(HttpMethod method, WebServiceHandler httpHandler) {
this.method = requireNonNull(method);
this.httpHandler = requireNonNull(httpHandler);
this.errorBody = format("%s. Only [%s] is allowed for this request.", METHOD_NOT_ALLOWED.description(), method);
}

@Override
public Eventual<LiveHttpResponse> handle(LiveHttpRequest request, HttpInterceptor.Context context) {
public Eventual<HttpResponse> handle(HttpRequest request, HttpInterceptor.Context context) {
if (!method.equals(request.method())) {
return Eventual.of(
HttpResponse.response(METHOD_NOT_ALLOWED)
.body(errorBody, StandardCharsets.UTF_8)
.build()
.stream()
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Copyright (C) 2013-2019 Expedia Inc.

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.
*/
package com.hotels.styx.common.http.handler;

import com.hotels.styx.api.Eventual;
import com.hotels.styx.api.HttpHandler;
import com.hotels.styx.api.HttpInterceptor;
import com.hotels.styx.api.HttpRequest;
import com.hotels.styx.api.HttpResponse;
import com.hotels.styx.api.WebServiceHandler;

import static java.util.Objects.requireNonNull;

/**
* Adapts Streaming HttpHandler API to STATIC WebServiceHandler interface.
*/
public class HttpStreamer implements WebServiceHandler {
private static final int KILOBYTE = 1024;

private int maxContentBytes;
private HttpHandler delegate;

/**
* HttpStreamer constructor.
*
* @param maxContentBytes max number of content maxContentBytes to aggregate
* @param delegate adapted HttpHandler instance
*/
public HttpStreamer(int maxContentBytes, HttpHandler delegate) {
this.maxContentBytes = maxContentBytes;
this.delegate = requireNonNull(delegate);
}

/**
* HttpStreamer constructor.
*
* @param delegate adapted HttpHandler instance
*/
public HttpStreamer(HttpHandler delegate) {
this(125 * KILOBYTE, delegate);
}

@Override
public Eventual<HttpResponse> handle(HttpRequest request, HttpInterceptor.Context context) {
return delegate.handle(request.stream(), context)
.flatMap(live -> live.aggregate(maxContentBytes));
}
}
Loading