
oracle.kv.util.http.ProxyRequestHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oracle-nosql-server Show documentation
Show all versions of oracle-nosql-server Show documentation
NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.
The newest version!
/*-
* Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle NoSQL
* Database made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle NoSQL Database for a copy of the license and
* additional information.
*/
package oracle.kv.util.http;
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import static oracle.kv.util.http.Constants.CONTENT_DISPOSITION;
import static oracle.kv.util.http.Constants.CONTENT_DISPOSITION_VALUE;
import static oracle.kv.util.http.Constants.CONTENT_LENGTH;
import static oracle.kv.util.http.Constants.X_CONTENT_TYPE_OPTIONS;
import static oracle.kv.util.http.Constants.X_CONTENT_TYPE_OPTIONS_VALUE;
import static oracle.kv.util.http.Constants.X_REAL_IP;
import static oracle.kv.util.http.Constants.X_FORWARDED_FOR;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import oracle.kv.impl.util.contextlogger.LogContext;
import oracle.kv.impl.util.sklogger.SkLogger;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
/**
* Generic request handler that attempts to map a url to a specific,
* registered Service instance before passing it along.
*/
public final class ProxyRequestHandler implements RequestHandler {
final SkLogger logger;
final Map services;
final LogControl logControl;
public ProxyRequestHandler(LogControl logControl, final SkLogger logger) {
this.logger = logger;
this.logControl = logControl;
services = new HashMap();
}
public void addService(String name, Service service) {
services.put(name, service);
}
Service getService(String name) {
return services.get(name);
}
@Override
public FullHttpResponse handleRequest(FullHttpRequest request,
ChannelHandlerContext ctx) {
FullHttpResponse response;
try {
final String path = new URI(request.uri()).getPath();
Service service = findService(path);
if (service == null) {
HttpHeaders headers = request.headers();
final CharSequence realIp = headers.get(X_REAL_IP);
final CharSequence forwardedFor =
headers.get(X_FORWARDED_FOR);
final String remoteAddr =
ctx.channel().remoteAddress().toString();
StringBuilder sb = new StringBuilder();
sb.append("Cannot find service for path ").append(path)
.append(", remote address=").append(remoteAddr);
if (realIp != null) {
sb.append(", ").append(X_REAL_IP).append("=")
.append(realIp);
}
if (forwardedFor != null) {
sb.append(", ").append(X_FORWARDED_FOR).append("=")
.append(forwardedFor);
}
/*
* TODO:
* o consider rate-limiting logger if there are lot of these
* o consider hard-close of connection if this looks like an
* attack.
*/
logger.info(sb.toString());
return badResponse();
}
LogContext lc =logControl.generateLogContext
(request.method().name() + " " + path);
response = service.handleRequest(request, ctx, lc);
} catch (Exception e) {
logger.info("Exception handling request: " + e.getMessage());
/*
* In general services must handle their own internal exceptions and
* map them to a reasonable FullHttpResponse.
*
* TODO: some exceptions may indicate that the channel needs to be
* closed. Look into this.
*/
// TODO: use exception message.
response = badResponse();
}
addRequiredHeaders(response);
return response;
}
private static FullHttpResponse badResponse() {
FullHttpResponse response =
new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST);
response.headers().set(CONTENT_LENGTH, 0);
return response;
}
/**
* These headers are required by Oracle's security policies
*/
private void addRequiredHeaders(FullHttpResponse response) {
response.headers().set(X_CONTENT_TYPE_OPTIONS,
X_CONTENT_TYPE_OPTIONS_VALUE);
response.headers().set(CONTENT_DISPOSITION,
CONTENT_DISPOSITION_VALUE);
}
/**
* Locate a registered Service instance based on the URI path.
* This is not as efficient as a hash, but given that there are relatively
* few services expected it is reasonable. Services should implement their
* lookupService methods in an efficient manner.
*/
private Service findService(String uri) {
/*
* Strip leading "/" if present
*/
String name = (uri.startsWith("/") ? uri.substring(1) : uri);
for (Service service : services.values()) {
if (service.lookupService(name)) {
return service;
}
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy