Search in sources :

Example 1 with CONNECTION

use of io.netty.handler.codec.http.HttpHeaderNames.CONNECTION in project ignite-3 by apache.

the class RestApiHandler method channelRead0.

/**
 * {@inheritDoc}
 */
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) {
    CompletableFuture<DefaultFullHttpResponse> responseFuture = router.route(request).map(route -> {
        var response = new RestApiHttpResponse(new DefaultHttpResponse(HttpVersion.HTTP_1_1, OK));
        return route.handle(request, response).thenApply(resp -> {
            ByteBuf content = resp.content() != null ? Unpooled.wrappedBuffer(resp.content()) : new EmptyByteBuf(UnpooledByteBufAllocator.DEFAULT);
            return new DefaultFullHttpResponse(resp.protocolVersion(), resp.status(), content, resp.headers(), EmptyHttpHeaders.INSTANCE);
        });
    }).orElseGet(() -> CompletableFuture.completedFuture(new DefaultFullHttpResponse(request.protocolVersion(), HttpResponseStatus.NOT_FOUND)));
    responseFuture.whenCompleteAsync((response, e) -> {
        if (e != null) {
            exceptionCaught(ctx, e);
            return;
        }
        response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
        boolean keepAlive = HttpUtil.isKeepAlive(request);
        if (keepAlive) {
            if (!request.protocolVersion().isKeepAliveDefault()) {
                response.headers().set(CONNECTION, KEEP_ALIVE);
            }
        } else {
            response.headers().set(CONNECTION, CLOSE);
        }
        ChannelFuture f = ctx.writeAndFlush(response);
        if (!keepAlive) {
            f.addListener(ChannelFutureListener.CLOSE);
        }
    }, ctx.executor());
}
Also used : UnpooledByteBufAllocator(io.netty.buffer.UnpooledByteBufAllocator) CONNECTION(io.netty.handler.codec.http.HttpHeaderNames.CONNECTION) CONTENT_LENGTH(io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH) HttpVersion(io.netty.handler.codec.http.HttpVersion) KEEP_ALIVE(io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE) HttpResponseStatus(io.netty.handler.codec.http.HttpResponseStatus) CompletableFuture(java.util.concurrent.CompletableFuture) FullHttpRequest(io.netty.handler.codec.http.FullHttpRequest) IgniteLogger(org.apache.ignite.lang.IgniteLogger) Unpooled(io.netty.buffer.Unpooled) ChannelFuture(io.netty.channel.ChannelFuture) RestApiHttpResponse(org.apache.ignite.internal.rest.api.RestApiHttpResponse) EmptyHttpHeaders(io.netty.handler.codec.http.EmptyHttpHeaders) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ByteBuf(io.netty.buffer.ByteBuf) EmptyByteBuf(io.netty.buffer.EmptyByteBuf) SimpleChannelInboundHandler(io.netty.channel.SimpleChannelInboundHandler) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) ChannelFutureListener(io.netty.channel.ChannelFutureListener) CLOSE(io.netty.handler.codec.http.HttpHeaderValues.CLOSE) DefaultFullHttpResponse(io.netty.handler.codec.http.DefaultFullHttpResponse) Router(org.apache.ignite.internal.rest.routes.Router) OK(io.netty.handler.codec.http.HttpResponseStatus.OK) HttpUtil(io.netty.handler.codec.http.HttpUtil) ChannelFuture(io.netty.channel.ChannelFuture) DefaultFullHttpResponse(io.netty.handler.codec.http.DefaultFullHttpResponse) EmptyByteBuf(io.netty.buffer.EmptyByteBuf) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) RestApiHttpResponse(org.apache.ignite.internal.rest.api.RestApiHttpResponse) ByteBuf(io.netty.buffer.ByteBuf) EmptyByteBuf(io.netty.buffer.EmptyByteBuf)

Example 2 with CONNECTION

use of io.netty.handler.codec.http.HttpHeaderNames.CONNECTION in project GraphScope by alibaba.

the class MaxGraphHttpGremlinEndpointHandler method channelRead.

@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
    if (msg instanceof FullHttpRequest) {
        final FullHttpRequest req = (FullHttpRequest) msg;
        if ("/favicon.ico".equals(req.uri())) {
            sendError(ctx, NOT_FOUND, "Gremlin Server doesn't have a favicon.ico");
            ReferenceCountUtil.release(msg);
            return;
        }
        if (HttpUtil.is100ContinueExpected(req)) {
            ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
        }
        if (req.method() != GET && req.method() != POST && req.method() != HEAD) {
            sendError(ctx, METHOD_NOT_ALLOWED, METHOD_NOT_ALLOWED.toString());
            ReferenceCountUtil.release(msg);
            return;
        }
        final Quartet<String, Map<String, Object>, String, Map<String, String>> requestArguments;
        try {
            requestArguments = getRequestArguments(req);
        } catch (IllegalArgumentException iae) {
            sendError(ctx, BAD_REQUEST, iae.getMessage());
            ReferenceCountUtil.release(msg);
            return;
        }
        final String acceptString = Optional.ofNullable(req.headers().get("Accept")).orElse("application/json");
        final Pair<String, MessageTextSerializer> serializer = chooseSerializer(acceptString);
        if (null == serializer) {
            sendError(ctx, BAD_REQUEST, String.format("no serializer for requested Accept header: %s", acceptString));
            ReferenceCountUtil.release(msg);
            return;
        }
        final String origin = req.headers().get(ORIGIN);
        final boolean keepAlive = HttpUtil.isKeepAlive(req);
        // not using the req any where below here - assume it is safe to release at this point.
        ReferenceCountUtil.release(msg);
        try {
            logger.debug("Processing request containing script [{}] and bindings of [{}] on {}", requestArguments.getValue0(), requestArguments.getValue1(), Thread.currentThread().getName());
            if (settings.authentication.enableAuditLog) {
                String address = ctx.channel().remoteAddress().toString();
                if (address.startsWith("/") && address.length() > 1)
                    address = address.substring(1);
                auditLogger.info("User with address {} requested: {}", address, requestArguments.getValue0());
            }
            final ChannelPromise promise = ctx.channel().newPromise();
            final AtomicReference<Object> resultHolder = new AtomicReference<>();
            promise.addListener(future -> {
                // processing of the exception
                if (future.isSuccess()) {
                    logger.debug("Preparing HTTP response for request with script [{}] and" + " bindings of [{}] with result of [{}] on [{}]", requestArguments.getValue0(), requestArguments.getValue1(), resultHolder.get(), Thread.currentThread().getName());
                    ByteBuf content = (ByteBuf) resultHolder.get();
                    final FullHttpResponse response = req.method() == GET ? new DefaultFullHttpResponse(HTTP_1_1, OK, content) : new DefaultFullHttpResponse(HTTP_1_1, OK);
                    response.headers().set(CONTENT_TYPE, serializer.getValue0());
                    response.headers().set(CONTENT_LENGTH, content.readableBytes());
                    // handle cors business
                    if (origin != null)
                        response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
                    if (!keepAlive) {
                        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
                    } else {
                        response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
                        ctx.writeAndFlush(response);
                    }
                }
            });
            final Timer.Context timerContext = evalOpTimer.time();
            final Bindings bindings;
            try {
                bindings = createBindings(requestArguments.getValue1(), requestArguments.getValue3());
            } catch (IllegalStateException iae) {
                sendError(ctx, BAD_REQUEST, iae.getMessage());
                ReferenceCountUtil.release(msg);
                return;
            }
            // provide a transform function to serialize to message - this will force
            // serialization to occur
            // in the same thread as the eval. after the CompletableFuture is returned from the
            // eval the result
            // is ready to be written as a ByteBuf directly to the response.  nothing should be
            // blocking here.
            String script = requestArguments.getValue0();
            final CompletableFuture<Object> evalFuture = gremlinExecutor.eval(script, requestArguments.getValue2(), bindings, FunctionUtils.wrapFunction(o -> {
                // stopping the timer here is roughly equivalent to
                // where the timer would have been stopped for
                // this metric in other contexts.  we just want to
                // measure eval time not serialization time.
                timerContext.stop();
                logger.debug("Transforming result of request with script" + " [{}] and bindings of [{}] with result" + " of [{}] on [{}]", requestArguments.getValue0(), requestArguments.getValue1(), o, Thread.currentThread().getName());
                List<Object> resultList = opProcessor.processHttpGraphTraversal(script, o, settings.scriptEvaluationTimeout, req);
                final ResponseMessage responseMessage = ResponseMessage.build(UUID.randomUUID()).code(ResponseStatusCode.SUCCESS).result(resultList).create();
                // http server is sessionless and must handle commit on
                // transactions. the commit occurs
                // before serialization to be consistent with how things
                // work for websocket based
                // communication.  this means that failed serialization
                // does not mean that you won't get
                // a commit to the database
                attemptCommit(requestArguments.getValue3(), graphManager, settings.strictTransactionManagement);
                try {
                    return Unpooled.wrappedBuffer(serializer.getValue1().serializeResponseAsString(responseMessage).getBytes(UTF8));
                } catch (Exception ex) {
                    logger.warn(String.format("Error during serialization for %s", responseMessage), ex);
                    throw ex;
                }
            }));
            evalFuture.exceptionally(t -> {
                if (t.getMessage() != null)
                    sendError(ctx, INTERNAL_SERVER_ERROR, t.getMessage(), Optional.of(t));
                else
                    sendError(ctx, INTERNAL_SERVER_ERROR, String.format("Error encountered evaluating script: %s", requestArguments.getValue0()), Optional.of(t));
                promise.setFailure(t);
                return null;
            });
            evalFuture.thenAcceptAsync(r -> {
                // now that the eval/serialization is done in the same thread - complete
                // the promise so we can
                // write back the HTTP response on the same thread as the original
                // request
                resultHolder.set(r);
                promise.setSuccess();
            }, gremlinExecutor.getExecutorService());
        } catch (Exception ex) {
            // tossed to exceptionCaught which delegates to sendError method
            final Throwable t = ExceptionUtils.getRootCause(ex);
            throw new RuntimeException(null == t ? ex : t);
        }
    }
}
Also used : NOT_FOUND(io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND) Settings(org.apache.tinkerpop.gremlin.server.Settings) Graph(org.apache.tinkerpop.gremlin.structure.Graph) Tokens(org.apache.tinkerpop.gremlin.driver.Tokens) LoggerFactory(org.slf4j.LoggerFactory) Unpooled(io.netty.buffer.Unpooled) Matcher(java.util.regex.Matcher) ChannelPromise(io.netty.channel.ChannelPromise) Map(java.util.Map) METHOD_NOT_ALLOWED(io.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED) CharsetUtil(io.netty.util.CharsetUtil) HTTP_1_1(io.netty.handler.codec.http.HttpVersion.HTTP_1_1) HttpGremlinEndpointHandler(org.apache.tinkerpop.gremlin.server.handler.HttpGremlinEndpointHandler) POST(io.netty.handler.codec.http.HttpMethod.POST) ObjectNode(org.apache.tinkerpop.shaded.jackson.databind.node.ObjectNode) HttpResponseStatus(io.netty.handler.codec.http.HttpResponseStatus) ArrayNode(org.apache.tinkerpop.shaded.jackson.databind.node.ArrayNode) JsonNode(org.apache.tinkerpop.shaded.jackson.databind.JsonNode) UUID(java.util.UUID) FullHttpRequest(io.netty.handler.codec.http.FullHttpRequest) Collectors(java.util.stream.Collectors) Pair(org.javatuples.Pair) SimpleBindings(javax.script.SimpleBindings) List(java.util.List) Stream(java.util.stream.Stream) ReferenceCountUtil(io.netty.util.ReferenceCountUtil) DefaultFullHttpResponse(io.netty.handler.codec.http.DefaultFullHttpResponse) Timer(com.codahale.metrics.Timer) Optional(java.util.Optional) ResponseStatusCode(org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode) CONTENT_TYPE(io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE) Pattern(java.util.regex.Pattern) GremlinExecutor(org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor) ORIGIN(io.netty.handler.codec.http.HttpHeaderNames.ORIGIN) OK(io.netty.handler.codec.http.HttpResponseStatus.OK) ExceptionUtils(org.apache.commons.lang3.exception.ExceptionUtils) CONNECTION(io.netty.handler.codec.http.HttpHeaderNames.CONNECTION) ObjectMapper(org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper) CONTENT_LENGTH(io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH) Bindings(javax.script.Bindings) INTERNAL_SERVER_ERROR(io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) AtomicReference(java.util.concurrent.atomic.AtomicReference) BAD_REQUEST(io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST) HashSet(java.util.HashSet) Meter(com.codahale.metrics.Meter) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) MessageSerializer(org.apache.tinkerpop.gremlin.driver.MessageSerializer) ResponseMessage(org.apache.tinkerpop.gremlin.driver.message.ResponseMessage) ByteBuf(io.netty.buffer.ByteBuf) Charset(java.nio.charset.Charset) GraphManager(org.apache.tinkerpop.gremlin.server.GraphManager) GremlinServer(org.apache.tinkerpop.gremlin.server.GremlinServer) ChannelFutureListener(io.netty.channel.ChannelFutureListener) MessageTextSerializer(org.apache.tinkerpop.gremlin.driver.ser.MessageTextSerializer) CONTINUE(io.netty.handler.codec.http.HttpResponseStatus.CONTINUE) Logger(org.slf4j.Logger) HttpHeaderValues(io.netty.handler.codec.http.HttpHeaderValues) Iterator(java.util.Iterator) GET(io.netty.handler.codec.http.HttpMethod.GET) Preconditions.checkNotNull(com.google.common.base.Preconditions.checkNotNull) IOException(java.io.IOException) HEAD(io.netty.handler.codec.http.HttpMethod.HEAD) FunctionUtils(org.apache.tinkerpop.gremlin.util.function.FunctionUtils) Quartet(org.javatuples.Quartet) ACCESS_CONTROL_ALLOW_ORIGIN(io.netty.handler.codec.http.HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN) FullHttpResponse(io.netty.handler.codec.http.FullHttpResponse) QueryStringDecoder(io.netty.handler.codec.http.QueryStringDecoder) ChannelHandler(io.netty.channel.ChannelHandler) TraversalSource(org.apache.tinkerpop.gremlin.process.traversal.TraversalSource) MetricManager(org.apache.tinkerpop.gremlin.server.util.MetricManager) MetricRegistry.name(com.codahale.metrics.MetricRegistry.name) HttpUtil(io.netty.handler.codec.http.HttpUtil) FullHttpRequest(io.netty.handler.codec.http.FullHttpRequest) ChannelPromise(io.netty.channel.ChannelPromise) ByteBuf(io.netty.buffer.ByteBuf) SimpleBindings(javax.script.SimpleBindings) Bindings(javax.script.Bindings) DefaultFullHttpResponse(io.netty.handler.codec.http.DefaultFullHttpResponse) FullHttpResponse(io.netty.handler.codec.http.FullHttpResponse) List(java.util.List) DefaultFullHttpResponse(io.netty.handler.codec.http.DefaultFullHttpResponse) AtomicReference(java.util.concurrent.atomic.AtomicReference) ResponseMessage(org.apache.tinkerpop.gremlin.driver.message.ResponseMessage) IOException(java.io.IOException) MessageTextSerializer(org.apache.tinkerpop.gremlin.driver.ser.MessageTextSerializer) Timer(com.codahale.metrics.Timer) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

ByteBuf (io.netty.buffer.ByteBuf)2 Unpooled (io.netty.buffer.Unpooled)2 ChannelFutureListener (io.netty.channel.ChannelFutureListener)2 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)2 DefaultFullHttpResponse (io.netty.handler.codec.http.DefaultFullHttpResponse)2 FullHttpRequest (io.netty.handler.codec.http.FullHttpRequest)2 CONNECTION (io.netty.handler.codec.http.HttpHeaderNames.CONNECTION)2 CONTENT_LENGTH (io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH)2 HttpResponseStatus (io.netty.handler.codec.http.HttpResponseStatus)2 OK (io.netty.handler.codec.http.HttpResponseStatus.OK)2 HttpUtil (io.netty.handler.codec.http.HttpUtil)2 Meter (com.codahale.metrics.Meter)1 MetricRegistry.name (com.codahale.metrics.MetricRegistry.name)1 Timer (com.codahale.metrics.Timer)1 Preconditions.checkNotNull (com.google.common.base.Preconditions.checkNotNull)1 EmptyByteBuf (io.netty.buffer.EmptyByteBuf)1 UnpooledByteBufAllocator (io.netty.buffer.UnpooledByteBufAllocator)1 ChannelFuture (io.netty.channel.ChannelFuture)1 ChannelHandler (io.netty.channel.ChannelHandler)1 ChannelPromise (io.netty.channel.ChannelPromise)1