All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.kv.util.http.ProxyRequestHandler Maven / Gradle / Ivy

Go to download

NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.

There is a newer version: 18.3.10
Show 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 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;

/**
 * Request handler for proxy requests
 *
 * TODO:
 * o handle unknown requests
 * o handle no-payload requests
 * o handle ping/no-op/etc
 * o handle health/version
 * o handle data requests
 */
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) {
                logger.warning("Cannot find service for path " + path);
                /* TODO: what should this be? special code? */
                return badResponse();
            }

            LogContext lc =logControl.generateLogContext
                (request.method().name() + " " + path);

            response = service.handleRequest(request, ctx, lc);

        } catch (Exception e) {
            logger.warning("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