Skip to content

Commit

Permalink
Merge pull request #784 from micronaut-projects/andriy/poja-improve
Browse files Browse the repository at this point in the history
Minor improvements for POJA
  • Loading branch information
andriy-dmytruk authored Aug 23, 2024
2 parents fb02e95 + 9e9a23c commit ddb664d
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.micronaut.context.ApplicationContext;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.io.buffer.ByteBufferFactory;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.MediaType;
import io.micronaut.http.codec.MediaTypeCodecRegistry;
Expand All @@ -26,6 +27,7 @@
import io.micronaut.inject.qualifiers.Qualifiers;
import io.micronaut.runtime.ApplicationConfiguration;
import io.micronaut.scheduling.TaskExecutors;
import io.micronaut.servlet.http.ByteArrayBufferFactory;
import io.micronaut.servlet.http.ServletHttpHandler;
import jakarta.inject.Singleton;
import org.apache.hc.core5.http.ClassicHttpResponse;
Expand Down Expand Up @@ -53,6 +55,7 @@ public class ApacheServerlessApplication
private final ConversionService conversionService;
private final MediaTypeCodecRegistry codecRegistry;
private final ExecutorService ioExecutor;
private final ByteBufferFactory<?, ?> byteBufferFactory;
private final ApacheServletConfiguration configuration;

/**
Expand All @@ -68,6 +71,7 @@ public ApacheServerlessApplication(ApplicationContext applicationContext,
codecRegistry = applicationContext.getBean(MediaTypeCodecRegistry.class);
ioExecutor = applicationContext.getBean(ExecutorService.class, Qualifiers.byName(TaskExecutors.BLOCKING));
configuration = applicationContext.getBean(ApacheServletConfiguration.class);
byteBufferFactory = ByteArrayBufferFactory.INSTANCE;
}

@Override
Expand All @@ -79,7 +83,7 @@ protected void handleSingleRequest(
ApacheServletHttpResponse<?> response = new ApacheServletHttpResponse<>(conversionService);
try {
ApacheServletHttpRequest exchange = new ApacheServletHttpRequest<>(
in, conversionService, codecRegistry, ioExecutor, response, configuration
in, conversionService, codecRegistry, ioExecutor, byteBufferFactory, response, configuration
);
servletHttpHandler.service(exchange);
} catch (ApacheServletBadRequestException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,34 @@
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.io.buffer.ByteBufferFactory;
import io.micronaut.http.HttpHeaders;
import io.micronaut.http.HttpMethod;
import io.micronaut.http.MutableHttpHeaders;
import io.micronaut.http.MutableHttpParameters;
import io.micronaut.http.MutableHttpRequest;
import io.micronaut.http.body.ByteBody;
import io.micronaut.http.body.stream.InputStreamByteBody;
import io.micronaut.http.codec.MediaTypeCodecRegistry;
import io.micronaut.http.cookie.Cookie;
import io.micronaut.http.cookie.Cookies;
import io.micronaut.http.poja.PojaHttpRequest;
import io.micronaut.http.poja.llhttp.exception.ApacheServletBadRequestException;
import io.micronaut.http.poja.util.LimitingInputStream;
import io.micronaut.http.poja.util.MultiValueHeaders;
import io.micronaut.http.poja.util.MultiValuesQueryParameters;
import io.micronaut.http.simple.cookies.SimpleCookies;
import io.micronaut.servlet.http.body.InputStreamByteBody;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.impl.io.ChunkedInputStream;
import org.apache.hc.core5.http.impl.io.ContentLengthInputStream;
import org.apache.hc.core5.http.impl.io.DefaultHttpRequestParser;
import org.apache.hc.core5.http.impl.io.SessionInputBufferImpl;
import org.apache.hc.core5.http.io.entity.EmptyInputStream;
import org.apache.hc.core5.net.URIBuilder;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
Expand All @@ -67,6 +69,8 @@
@Internal
public final class ApacheServletHttpRequest<B> extends PojaHttpRequest<B, ClassicHttpRequest, ClassicHttpResponse> {

private static final String TRANSFER_ENCODING_CHUNKED = "chunked";

private final ClassicHttpRequest request;

private final HttpMethod method;
Expand All @@ -92,6 +96,7 @@ public ApacheServletHttpRequest(
ConversionService conversionService,
MediaTypeCodecRegistry codecRegistry,
ExecutorService ioExecutor,
ByteBufferFactory<?, ?> byteBufferFactory,
ApacheServletHttpResponse<?> response,
ApacheServletConfiguration configuration
) {
Expand Down Expand Up @@ -119,29 +124,33 @@ public ApacheServletHttpRequest(

long contentLength = getContentLength();
OptionalLong optionalContentLength = contentLength >= 0 ? OptionalLong.of(contentLength) : OptionalLong.empty();
try {
InputStream bodyStream = inputStream;
if (sessionInputBuffer.length() > 0) {
byte[] data = new byte[sessionInputBuffer.length()];
sessionInputBuffer.read(data, inputStream);

bodyStream = new CombinedInputStream(
new ByteArrayInputStream(data),
inputStream
);
}
if (contentLength > 0) {
bodyStream = new LimitingInputStream(bodyStream, contentLength);
} else {
// Empty
bodyStream = new ByteArrayInputStream(new byte[0]);
}
byteBody = InputStreamByteBody.create(
bodyStream, optionalContentLength, ioExecutor
);
} catch (IOException e) {
throw new ApacheServletBadRequestException("Could not parse request body", e);
InputStream bodyStream = createBodyStream(inputStream, contentLength, sessionInputBuffer);
byteBody = InputStreamByteBody.create(
bodyStream, optionalContentLength, ioExecutor, byteBufferFactory
);
}

/**
* Create body stream.
* Based on org.apache.hc.core5.http.impl.io.BHttpConnectionBase#createContentOutputStream.
*
* @param inputStream The input stream
* @param contentLength The content length
* @param sessionInputBuffer The input buffer
* @return The body stream
*/
private InputStream createBodyStream(InputStream inputStream, long contentLength, SessionInputBufferImpl sessionInputBuffer) {
InputStream bodyStream;
if (contentLength > 0) {
bodyStream = new ContentLengthInputStream(sessionInputBuffer, inputStream, contentLength);
} else if (contentLength == 0) {
bodyStream = EmptyInputStream.INSTANCE;
} else if (TRANSFER_ENCODING_CHUNKED.equalsIgnoreCase(headers.get(HttpHeaders.TRANSFER_ENCODING))) {
bodyStream = new ChunkedInputStream(sessionInputBuffer, inputStream);
} else {
bodyStream = EmptyInputStream.INSTANCE;
}
return bodyStream;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ protected Undertow undertowServer(Undertow.Builder builder) {
*
* @param servletConfiguration The servlet configuration.
* @return The deployment info
* @deprecated Use {@link ##deploymentInfo(MicronautServletConfiguration, Collection)}
* @deprecated Use {@link #deploymentInfo(MicronautServletConfiguration, Collection)}
*/
@Deprecated(forRemoval = true, since = "4.8.0")
protected DeploymentInfo deploymentInfo(MicronautServletConfiguration servletConfiguration) {
Expand Down
22 changes: 15 additions & 7 deletions test-sample-poja/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,38 @@
plugins {
id("io.micronaut.build.internal.servlet.base")
id("application")
id("groovy")
id 'org.graalvm.buildtools.native'
}

dependencies {
implementation(projects.micronautHttpPojaApache)
implementation(mnLogging.slf4j.simple)
implementation(mn.micronaut.jackson.databind)
implementation(mnSerde.micronaut.serde.jackson)
annotationProcessor(mn.micronaut.inject.java)

testImplementation(projects.micronautHttpPojaTest)
testImplementation(mn.micronaut.jackson.databind)
testImplementation(mnTest.micronaut.test.spock)
testImplementation(mnTest.micronaut.test.junit5)

testImplementation(mn.micronaut.inject.groovy.test)
testAnnotationProcessor(mn.micronaut.inject.java.test)
testImplementation(mn.micronaut.inject.java)
testImplementation(mn.micronaut.inject.groovy)
}

run {
application {
mainClass.set("io.micronaut.http.poja.sample.Application")
}

run {
standardInput = System.in
standardOutput = System.out
}

graalvmNative {
binaries.all {
buildArgs.add("--gc=serial")
buildArgs.add("--install-exit-handlers")
}
}

test {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
import io.micronaut.http.annotation.Delete;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.annotation.Produces;
import io.micronaut.http.annotation.Put;
import io.micronaut.http.annotation.Status;
import io.micronaut.http.poja.sample.model.Cactus;

/**
* A controller for testing.
Expand Down Expand Up @@ -56,5 +58,11 @@ public final String update(@NonNull String name) {
return "Hello, " + name + "!\n";
}

@Get("/cactus")
@Produces(MediaType.APPLICATION_JSON)
public final Cactus getCactus() {
return new Cactus("green", 1);
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.micronaut.http.poja.sample.model;

import io.micronaut.serde.annotation.Serdeable;

@Serdeable
public record Cactus(
String color,
int spikeSize
) {
}

This file was deleted.

Loading

0 comments on commit ddb664d

Please sign in to comment.