Skip to content

Commit

Permalink
Improve multipart handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
noboomu committed Sep 18, 2020
1 parent 2ebba11 commit 66acf75
Show file tree
Hide file tree
Showing 11 changed files with 479 additions and 93 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Proteus Changelog.
## Unreleased
### No issue

**Added support for multiple file uploads.**


[2ebba11320f386e](https://github.com/noboomu/proteus/commit/2ebba11320f386e) Joshua Bauer *2020-09-16 23:33:26*

**Replace whenComplete in async.**


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
Expand Down Expand Up @@ -204,7 +205,7 @@ public void failure(Service service)

printStatus();

running.set(true);
running.set(false);
}

}, MoreExecutors.directExecutor());
Expand All @@ -229,6 +230,7 @@ public void failure(Service service)
}
}));


buildServer();

undertow.start();
Expand Down Expand Up @@ -265,97 +267,94 @@ public void buildServer()
{


for (Class<?> controllerClass : registeredControllers) {
HandlerGenerator generator = new HandlerGenerator("io.sinistral.proteus.controllers.handlers", controllerClass);

for (Class<?> controllerClass : registeredControllers) {
HandlerGenerator generator = new HandlerGenerator("io.sinistral.proteus.controllers.handlers", controllerClass);
injector.injectMembers(generator);

injector.injectMembers(generator);
try {
Supplier<RoutingHandler> generatedRouteSupplier = injector.getInstance(generator.compileClass());

try {
Supplier<RoutingHandler> generatedRouteSupplier = injector.getInstance(generator.compileClass());
router.addAll(generatedRouteSupplier.get());

router.addAll(generatedRouteSupplier.get());
} catch (Exception e) {
log.error("Exception creating handlers for " + controllerClass.getName() + "!!!\n" + e.getMessage(), e);
}

} catch (Exception e) {
log.error("Exception creating handlers for " + controllerClass.getName() + "!!!\n" + e.getMessage(), e);
}

}

this.addDefaultRoutes(router);
this.addDefaultRoutes(router);

HttpHandler handler;
HttpHandler handler;

if (rootHandlerClass != null) {
handler = injector.getInstance(rootHandlerClass);
} else {
handler = rootHandler;
}

SessionAttachmentHandler sessionAttachmentHandler = null;

try {
sessionAttachmentHandler = injector.getInstance(SessionAttachmentHandler.class);
} catch (Exception e) {
log.info("No session attachment handler found.");
}
if (rootHandlerClass != null) {
handler = injector.getInstance(rootHandlerClass);
} else {
handler = rootHandler;
}

if (sessionAttachmentHandler != null) {
log.info("Using session attachment handler.");
SessionAttachmentHandler sessionAttachmentHandler = null;

sessionAttachmentHandler.setNext(handler);
handler = sessionAttachmentHandler;
}
try {
sessionAttachmentHandler = injector.getInstance(SessionAttachmentHandler.class);
} catch (Exception e) {
log.info("No session attachment handler found.");
}

int httpPort = config.getInt("application.ports.http");
if (sessionAttachmentHandler != null) {
log.info("Using session attachment handler.");

if (System.getProperty("http.port") != null) {
httpPort = Integer.parseInt(System.getProperty("http.port"));
}
sessionAttachmentHandler.setNext(handler);
handler = sessionAttachmentHandler;
}

Undertow.Builder undertowBuilder = Undertow.builder().addHttpListener(httpPort, config.getString("application.host"))
int httpPort = config.getInt("application.ports.http");

if (System.getProperty("http.port") != null) {
httpPort = Integer.parseInt(System.getProperty("http.port"));
}

.setBufferSize(Long.valueOf(config.getMemorySize("undertow.bufferSize").toBytes()).intValue())
.setIoThreads(Runtime.getRuntime().availableProcessors() * config.getInt("undertow.ioThreadsMultiplier"))
.setWorkerThreads(Runtime.getRuntime().availableProcessors() * config.getInt("undertow.workerThreadMultiplier"))
.setDirectBuffers(config.getBoolean("undertow.directBuffers"))
.setSocketOption(org.xnio.Options.BACKLOG, config.getInt("undertow.socket.backlog"))
.setSocketOption(org.xnio.Options.REUSE_ADDRESSES, config.getBoolean("undertow.socket.reuseAddresses"))
.setSocketOption(org.xnio.Options.READ_TIMEOUT, config.getInt("undertow.socket.readTimeout"))
.setSocketOption(org.xnio.Options.WRITE_TIMEOUT, config.getInt("undertow.socket.writeTimeout"))
.setServerOption(UndertowOptions.ENABLE_HTTP2, config.getBoolean("undertow.server.enableHttp2"))
.setServerOption(UndertowOptions.ALWAYS_SET_DATE, config.getBoolean("undertow.server.alwaysSetDate"))
.setServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE, config.getBoolean("undertow.server.alwaysSetKeepAlive"))
.setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, config.getBoolean("undertow.server.recordRequestStartTime"))
.setServerOption(UndertowOptions.MAX_ENTITY_SIZE, config.getBytes("undertow.server.maxEntitySize"))
.setHandler(handler);
Undertow.Builder undertowBuilder = Undertow.builder().addHttpListener(httpPort, config.getString("application.host"))

.setBufferSize(Long.valueOf(config.getMemorySize("undertow.bufferSize").toBytes()).intValue())
.setIoThreads(Runtime.getRuntime().availableProcessors() * config.getInt("undertow.ioThreadsMultiplier"))
.setWorkerThreads(Runtime.getRuntime().availableProcessors() * config.getInt("undertow.workerThreadMultiplier"))
.setDirectBuffers(config.getBoolean("undertow.directBuffers"))
.setSocketOption(org.xnio.Options.BACKLOG, config.getInt("undertow.socket.backlog"))
.setSocketOption(org.xnio.Options.REUSE_ADDRESSES, config.getBoolean("undertow.socket.reuseAddresses"))
.setSocketOption(org.xnio.Options.READ_TIMEOUT, config.getInt("undertow.socket.readTimeout"))
.setSocketOption(org.xnio.Options.WRITE_TIMEOUT, config.getInt("undertow.socket.writeTimeout"))
.setServerOption(UndertowOptions.ENABLE_HTTP2, config.getBoolean("undertow.server.enableHttp2"))
.setServerOption(UndertowOptions.ALWAYS_SET_DATE, config.getBoolean("undertow.server.alwaysSetDate"))
.setServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE, config.getBoolean("undertow.server.alwaysSetKeepAlive"))
.setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, config.getBoolean("undertow.server.recordRequestStartTime"))
.setServerOption(UndertowOptions.MAX_ENTITY_SIZE, config.getBytes("undertow.server.maxEntitySize"))
.setHandler(handler);

if (config.getBoolean("undertow.ssl.enabled")) {
try {
int httpsPort = config.getInt("application.ports.https");

if (System.getProperty("https.port") != null) {
httpsPort = Integer.parseInt(System.getProperty("https.port"));
}

KeyStore keyStore = SecurityOps.loadKeyStore(config.getString("undertow.ssl.keystorePath"), config.getString("undertow.ssl.keystorePassword"));
KeyStore trustStore = SecurityOps.loadKeyStore(config.getString("undertow.ssl.truststorePath"), config.getString("undertow.ssl.truststorePassword"));

if (config.getBoolean("undertow.ssl.enabled")) {
try {
int httpsPort = config.getInt("application.ports.https");
undertowBuilder.addHttpsListener(httpsPort, config.getString("application.host"), SecurityOps.createSSLContext(keyStore, trustStore, config.getString("undertow.ssl.keystorePassword")));

if (System.getProperty("https.port") != null) {
httpsPort = Integer.parseInt(System.getProperty("https.port"));
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}

KeyStore keyStore = SecurityOps.loadKeyStore(config.getString("undertow.ssl.keystorePath"), config.getString("undertow.ssl.keystorePassword"));
KeyStore trustStore = SecurityOps.loadKeyStore(config.getString("undertow.ssl.truststorePath"), config.getString("undertow.ssl.truststorePassword"));

undertowBuilder.addHttpsListener(httpsPort, config.getString("application.host"), SecurityOps.createSSLContext(keyStore, trustStore, config.getString("undertow.ssl.keystorePassword")));


} catch (Exception e) {
log.error(e.getMessage(), e);
if (serverConfigurationFunction != null) {
undertowBuilder = serverConfigurationFunction.apply(undertowBuilder);
}
}

if (serverConfigurationFunction != null) {
undertowBuilder = serverConfigurationFunction.apply(undertowBuilder);
}
this.undertow = undertowBuilder.build();

this.undertow = undertowBuilder.build();

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.google.inject.Inject;
import io.sinistral.proteus.server.predicates.ServerPredicates;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.form.FormData;
import io.undertow.server.handlers.form.FormDataParser;
import io.undertow.util.HttpString;
import io.undertow.util.Methods;
Expand All @@ -31,6 +32,7 @@
import java.util.Date;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -368,6 +370,28 @@ public static List<File> fileList(final HttpServerExchange exchange, final Strin
}
}

public static Map<String,Path> pathMap(final HttpServerExchange exchange, final String name) throws IllegalArgumentException
{
try
{
return exchange.getAttachment(FormDataParser.FORM_DATA).get(name).stream().collect(Collectors.toMap(FormData.FormValue::getFileName, i -> i.getFileItem().getFile()));
} catch( Exception e )
{
throw new IllegalArgumentException("Missing parameter " + name, e);
}
}

public static Map<String,File> fileMap(final HttpServerExchange exchange, final String name) throws IllegalArgumentException
{
try
{
return exchange.getAttachment(FormDataParser.FORM_DATA).get(name).stream().collect(Collectors.toMap(FormData.FormValue::getFileName, i -> i.getFileItem().getFile().toFile()));
} catch( Exception e )
{
throw new IllegalArgumentException("Missing parameter " + name, e);
}
}

public static File file(final HttpServerExchange exchange, final String name) throws IllegalArgumentException
{
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,11 @@ public enum TypeHandler {
BeanListFromStringType("$T $L = io.sinistral.proteus.server.Extractors.model(exchange,$L)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.LITERAL),

FileListType("$T $L = io.sinistral.proteus.server.Extractors.fileList(exchange,$S)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.STRING),

PathListType("$T $L = io.sinistral.proteus.server.Extractors.pathList(exchange,$S)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.STRING),

FileMapType("$T $L = io.sinistral.proteus.server.Extractors.fileMap(exchange,$S)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.STRING),
PathMapType("$T $L = io.sinistral.proteus.server.Extractors.pathMap(exchange,$S)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.STRING),

HeaderValueOfType("$T $L = $T.valueOf($T.string(exchange,$S))", false, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.TYPE, io.sinistral.proteus.server.Extractors.Header.class, StatementParameterType.STRING),
HeaderFromStringType("$T $L = $T.fromString($T.string(exchange,$S))", false, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.TYPE, io.sinistral.proteus.server.Extractors.Header.class, StatementParameterType.STRING),
HeaderStringType("$T $L = $T.string(exchange,$S)", false, String.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Header.class, StatementParameterType.STRING),
Expand Down Expand Up @@ -314,6 +316,8 @@ public static TypeHandler forType(Type type, Boolean isBeanParam)

if (isArray && !isOptional) {
try {


Class<?> erasedType = (Class<?>) HandlerGenerator.extractErasedType(type);

if (HandlerGenerator.hasValueOfMethod(erasedType)) {
Expand Down Expand Up @@ -348,7 +352,19 @@ public static TypeHandler forType(Type type, Boolean isBeanParam)
if (isMap && !isOptional) {
try {

return ModelType;

ParameterizedType erasedType = (ParameterizedType) HandlerGenerator.extractErasedType(type);

Type[] types = erasedType.getActualTypeArguments();

if (types[1].getTypeName().contains("java.nio.file.Path")) {
return PathMapType;
} else if (types[1].getTypeName().contains("java.io.File")) {
return FileMapType;
}
else {
return ModelType;
}

} catch (Exception e) {
HandlerGenerator.log.error(e.getMessage(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ public ServerResponse<ByteBuffer> responseUploadFile(ServerRequest request, @For
@Produces(MediaType.APPLICATION_JSON)
@Consumes("*/*")
@Blocking
public ServerResponse<Map<String,String>> uploadMultipleFiles(ServerRequest request, @FormParam("files") List<File> files, @FormParam("names") List<String> names ) throws Exception
public ServerResponse<Map<String,String>> uploadMultipleFileList(ServerRequest request, @FormParam("files") List<File> files, @FormParam("names") List<String> names ) throws Exception
{

Map<String,String> map = new HashMap<>();
Expand All @@ -405,7 +405,7 @@ public ServerResponse<Map<String,String>> uploadMultipleFiles(ServerRequest requ
@Produces(MediaType.APPLICATION_JSON)
@Consumes("*/*")
@Blocking
public ServerResponse<Map<String,String>> uploadMultiplePaths(ServerRequest request, @FormParam("files") List<java.nio.file.Path> files, @FormParam("names") List<String> names ) throws Exception
public ServerResponse<Map<String,String>> uploadMultiplePathList(ServerRequest request, @FormParam("files") List<java.nio.file.Path> files, @FormParam("names") List<String> names ) throws Exception
{

Map<String,String> map = new HashMap<>();
Expand All @@ -421,6 +421,47 @@ public ServerResponse<Map<String,String>> uploadMultiplePaths(ServerRequest requ

}

@POST
@Path("map/file")
@Produces(MediaType.APPLICATION_JSON)
@Consumes("*/*")
@Blocking
public ServerResponse<Map<String,String>> uploadMultipleFileMap(ServerRequest request, @FormParam("files") Map<String,File> files ) throws Exception
{

Map<String,String> map = new HashMap<>();

for(String k : files.keySet())
{
map.put(k,files.get(k).getTotalSpace()+"");
}


return response(map).applicationJson();


}

@POST
@Path("map/path")
@Produces(MediaType.APPLICATION_JSON)
@Consumes("*/*")
@Blocking
public ServerResponse<Map<String,String>> uploadMultiplePathMap(ServerRequest request, @FormParam("files") Map<String,java.nio.file.Path> files ) throws Exception
{

Map<String,String> map = new HashMap<>();

for(String k : files.keySet())
{
map.put(k,files.get(k).toFile().getTotalSpace()+"");
}

return response(map).applicationJson();


}



@GET
Expand Down
Loading

0 comments on commit 66acf75

Please sign in to comment.