Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HTTP POJA implementation based on Apache to the 4.10.x branch #779

Merged
merged 41 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
cdd7af6
Update common files (#771)
micronaut-build Aug 16, 2024
78f4c64
GCN-4404: Initial commit of serverless micronaut web applications.
wwwsahoo May 20, 2024
55c1c99
GCN-4622 Create a simple test for the serverless application
andriy-dmytruk Jun 17, 2024
f74f814
added copyright and license.
wwwsahoo Jun 17, 2024
6cdb40e
GCN-4624 Add the Micronaut server TCK for POJA
andriy-dmytruk Jun 18, 2024
ccb2e5e
Add body support to the poja
andriy-dmytruk Jun 24, 2024
9ed8e98
Improve body support
andriy-dmytruk Jun 25, 2024
9ee9de1
Improvements with closing client and streams
andriy-dmytruk Jun 25, 2024
ac6db61
Store attributes in the POJA request
andriy-dmytruk Jun 26, 2024
ce19b04
Use the ServletResponseFactory for creating responses
andriy-dmytruk Jun 26, 2024
de3b54d
Change body input stream reading
andriy-dmytruk Jun 26, 2024
e329be4
More TCK test fixes
andriy-dmytruk Jun 26, 2024
d742893
Fixing and refactoring
andriy-dmytruk Jun 27, 2024
6a6e401
Move the sample
andriy-dmytruk Jun 27, 2024
c09604a
Copy QueryStringDecoderTest from netty
andriy-dmytruk Jun 27, 2024
bb495b0
Remove TODO
andriy-dmytruk Jun 27, 2024
c600aae
Spotless and binary compatability fixes
andriy-dmytruk Jun 28, 2024
e991d6d
Fix checkstyle
andriy-dmytruk Jun 28, 2024
c453168
Decouple POJA into a common and implementation module
andriy-dmytruk Aug 9, 2024
69c73aa
Begin adding Apache implementation for HTTP POJA
andriy-dmytruk Aug 9, 2024
77e1999
Fix header parsing and body reading for Apache POJA
andriy-dmytruk Aug 15, 2024
72f7915
Fix cookie parsing for Apache POJA
andriy-dmytruk Aug 15, 2024
35c38cc
More fixes for TCK tests
andriy-dmytruk Aug 16, 2024
5213a91
Fix the LimitingInputStream
andriy-dmytruk Aug 16, 2024
0e25da7
Fix header standardization
andriy-dmytruk Aug 16, 2024
ebdde39
Refactor, fix checkstyle and javadoc
andriy-dmytruk Aug 16, 2024
5c748e1
Minor fix for sample
andriy-dmytruk Aug 16, 2024
faadb0e
Fix TCK client configuration
andriy-dmytruk Aug 16, 2024
08d8006
Enable CORS test
andriy-dmytruk Aug 19, 2024
543f642
Add a test
andriy-dmytruk Aug 19, 2024
8cff255
Remove sample and tck from being modules
andriy-dmytruk Aug 19, 2024
3141c04
Create PojaHttpServerlessApplicationContextConfigurer
andriy-dmytruk Aug 19, 2024
242bcc7
Create more specific exceptions
andriy-dmytruk Aug 19, 2024
f298fa0
Add buffer size configuration options
andriy-dmytruk Aug 19, 2024
63abdc5
Fix sonar cloud warnings
andriy-dmytruk Aug 19, 2024
ed1fdb2
Minor style fix
andriy-dmytruk Aug 19, 2024
5c586f8
More sonar cloud fixes
andriy-dmytruk Aug 19, 2024
da74733
Fix TCK test with native-image
andriy-dmytruk Aug 19, 2024
330b5f6
Attempt to fix GraalVM 17 native image
andriy-dmytruk Aug 19, 2024
5b1a41c
Revert and fix GraalVM TCK by adding required configurations
andriy-dmytruk Aug 19, 2024
b6e7e33
Fixes after Micronaut update
andriy-dmytruk Aug 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,6 @@ jobs:
- name: Upload assets
# Upload the artifacts to the existing release. Note that the SLSA provenance will
# attest to each artifact file and not the aggregated ZIP file.
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8
with:
files: artifacts.zip
2 changes: 2 additions & 0 deletions config/checkstyle/suppressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
<!-- files="DefaultBeanContext.java|BeanDefinitionWriter.java|DefaultHttpClient.java"/> -->

<suppress checks="MissingJavadocType" files=".*doc-examples.*" />

<suppress checks=".*" files=".*/http-poja-common/src/main/java/io/micronaut/http/poja/util/QueryStringDecoder.java" />
</suppressions>
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ undertow = '2.3.15.Final'
tomcat = '10.1.26'
bcpkix = "1.70"

managed-apache-http-core5 = "5.2.5"
managed-jetty = '11.0.22'

micronaut-reactor = "3.5.0"
Expand Down Expand Up @@ -46,6 +47,7 @@ junit-platform-engine = { module = "org.junit.platform:junit-platform-suite-engi
kotlin-stdlib-jdk8 = { module = 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' }
kotlin-reflect = { module = 'org.jetbrains.kotlin:kotlin-reflect' }

apache-http-core5 = { module = 'org.apache.httpcomponents.core5:httpcore5', version.ref = 'managed-apache-http-core5' }
tomcat-embed-core = { module = 'org.apache.tomcat.embed:tomcat-embed-core', version.ref = 'tomcat' }
undertow-servlet = { module = 'io.undertow:undertow-servlet', version.ref = 'undertow' }
jetty-servlet = { module = 'org.eclipse.jetty:jetty-servlet', version.ref = 'managed-jetty' }
Expand Down
40 changes: 40 additions & 0 deletions http-poja-apache/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright © 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id("io.micronaut.build.internal.servlet.module")
id("idea")
}

dependencies {
api(projects.micronautHttpPojaCommon)
implementation(libs.apache.http.core5)

compileOnly(mn.reactor)
compileOnly(mn.micronaut.json.core)


testImplementation(mnSerde.micronaut.serde.jackson)
}

micronautBuild {
binaryCompatibility {
enabled.set(false)
}
}

javadoc {
failOnError(false)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright 2017-2024 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.http.poja.llhttp;

import io.micronaut.context.ApplicationContext;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.MediaType;
import io.micronaut.http.codec.MediaTypeCodecRegistry;
import io.micronaut.http.poja.PojaHttpServerlessApplication;
import io.micronaut.http.poja.llhttp.exception.ApacheServletBadRequestException;
import io.micronaut.http.server.exceptions.HttpServerException;
import io.micronaut.inject.qualifiers.Qualifiers;
import io.micronaut.runtime.ApplicationConfiguration;
import io.micronaut.scheduling.TaskExecutors;
import io.micronaut.servlet.http.ServletHttpHandler;
import jakarta.inject.Singleton;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.impl.io.DefaultHttpResponseWriter;
import org.apache.hc.core5.http.impl.io.SessionOutputBufferImpl;
import org.apache.hc.core5.http.io.SessionOutputBuffer;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ExecutorService;

/**
* Implementation of {@link PojaHttpServerlessApplication} for Apache.
*
* @author Andriy Dmytruk.
* @since 4.10.0
*/
@Singleton
public class ApacheServerlessApplication
extends PojaHttpServerlessApplication<ApacheServletHttpRequest<?>, ApacheServletHttpResponse<?>> {

private final ConversionService conversionService;
private final MediaTypeCodecRegistry codecRegistry;
private final ExecutorService ioExecutor;
private final ApacheServletConfiguration configuration;

/**
* Default constructor.
*
* @param applicationContext The application context
* @param applicationConfiguration The application configuration
*/
public ApacheServerlessApplication(ApplicationContext applicationContext,
ApplicationConfiguration applicationConfiguration) {
super(applicationContext, applicationConfiguration);
conversionService = applicationContext.getConversionService();
codecRegistry = applicationContext.getBean(MediaTypeCodecRegistry.class);
ioExecutor = applicationContext.getBean(ExecutorService.class, Qualifiers.byName(TaskExecutors.BLOCKING));
configuration = applicationContext.getBean(ApacheServletConfiguration.class);
}

@Override
protected void handleSingleRequest(
ServletHttpHandler<ApacheServletHttpRequest<?>, ApacheServletHttpResponse<?>> servletHttpHandler,
InputStream in,
OutputStream out
) throws IOException {
ApacheServletHttpResponse<?> response = new ApacheServletHttpResponse<>(conversionService);
try {
ApacheServletHttpRequest exchange = new ApacheServletHttpRequest<>(
in, conversionService, codecRegistry, ioExecutor, response, configuration
);
servletHttpHandler.service(exchange);
} catch (ApacheServletBadRequestException e) {
response.status(HttpStatus.BAD_REQUEST);
response.contentType(MediaType.TEXT_PLAIN_TYPE);
response.getOutputStream().write(e.getMessage().getBytes());
}
writeResponse(response.getNativeResponse(), out);
}

private void writeResponse(ClassicHttpResponse response, OutputStream out) throws IOException {
SessionOutputBuffer buffer = new SessionOutputBufferImpl(configuration.outputBufferSize());
DefaultHttpResponseWriter responseWriter = new DefaultHttpResponseWriter();
try {
responseWriter.write(response, buffer, out);
} catch (HttpException e) {
throw new HttpServerException("Could not write response body", e);
}
buffer.flush(out);

HttpEntity entity = response.getEntity();
if (entity != null) {
entity.writeTo(out);
}
out.flush();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2017-2024 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.http.poja.llhttp;

import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.core.bind.annotation.Bindable;

/**
* Configuration specific to the Apache POJA serverless application.
*
* @param inputBufferSize The size of the buffer that is used to read and parse the HTTP request
* (in bytes). Default value is 8192 (8Kb).
* @param outputBufferSize The size of the buffer that is used to write the HTTP response
* (in bytes). Default value is 8192 (8Kb).
* @author Andriy Dmytruk
* @since 4.10.0
*/
@ConfigurationProperties("poja.apache")
public record ApacheServletConfiguration(
@Bindable(defaultValue = "8192")
int inputBufferSize,
@Bindable(defaultValue = "8192")
int outputBufferSize
) {

}
Loading
Loading