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

org.jboss.resteasy.reactive.server.handlers.InputHandler Maven / Gradle / Ivy

There is a newer version: 3.17.5
Show newest version
package org.jboss.resteasy.reactive.server.handlers;

import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Supplier;

import jakarta.ws.rs.HttpMethod;

import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext;
import org.jboss.resteasy.reactive.server.spi.ServerHttpRequest;
import org.jboss.resteasy.reactive.server.spi.ServerRestHandler;

/**
 * Handler that reads data and sets up the input stream
 * 

* By default this will attempt to buffer and use a fully in memory stream, * to allow the request to stay on the IO thread. If the request is too large * it will be delegated to an executor and a blocking stream used instead. *

* TODO: the stream implementation here could be a lot more efficient. */ public class InputHandler implements ServerRestHandler { final long maxBufferSize; private volatile Executor workerExecutor; private final Supplier workerExecutorSupplier; private final ClassLoader originalTCCL; public InputHandler(long maxBufferSize, Supplier workerExecutorSupplier) { this.maxBufferSize = maxBufferSize; this.workerExecutorSupplier = workerExecutorSupplier; // capture the proper TCCL in order to avoid losing it to Vert.x in dev-mode this.originalTCCL = Thread.currentThread().getContextClassLoader(); } @Override public void handle(ResteasyReactiveRequestContext context) throws Exception { // in some cases, with sub-resource locators or via request filters, // it's possible we've already read the entity if (context.hasInputStream()) { // let's not set it twice return; } if (context.serverRequest().getRequestMethod().equals(HttpMethod.GET) || context.serverRequest().getRequestMethod().equals(HttpMethod.HEAD)) { return; } InputListener h = new InputListener(context); context.suspend(); ServerHttpRequest req = context.serverRequest(); if (!req.isRequestEnded()) { req.setReadListener(h); req.resumeRequestInput(); } else { req.resumeRequestInput(); h.done(); } } class InputListener implements ServerHttpRequest.ReadCallback { final ResteasyReactiveRequestContext context; int dataCount; final List data = new ArrayList<>(); InputListener(ResteasyReactiveRequestContext context) { this.context = context; } @Override public void done() { //super inefficient //TODO: write a stream that just uses the existing vert.x buffers byte[] ar = new byte[dataCount]; int count = 0; for (ByteBuffer i : data) { int remaining = i.remaining(); i.get(ar, count, remaining); count += remaining; } context.setInputStream(new ByteArrayInputStream(ar)); Thread.currentThread().setContextClassLoader(originalTCCL); context.resume(); } @Override public void data(ByteBuffer event) { dataCount += event.remaining(); data.add(event); if (dataCount > maxBufferSize) { context.serverRequest().pauseRequestInput(); if (workerExecutor == null) { workerExecutor = workerExecutorSupplier.get(); } //super inefficient //TODO: write a stream that just uses the existing vert.x buffers int count = 0; byte[] ar = new byte[dataCount]; for (ByteBuffer i : data) { int remaining = i.remaining(); i.get(ar, count, remaining); count += remaining; } //todo timeout context.setInputStream(context.serverRequest().createInputStream(ByteBuffer.wrap(ar))); context.resume(workerExecutor); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy