Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
topframe committed Apr 19, 2024
1 parent 9219337 commit 88a81d3
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 259 deletions.
37 changes: 4 additions & 33 deletions web/src/main/java/com/aspectran/web/activity/WebActivity.java
Expand Up @@ -30,12 +30,11 @@
import com.aspectran.utils.Assert;
import com.aspectran.utils.StringUtils;
import com.aspectran.utils.annotation.jsr305.NonNull;
import com.aspectran.web.activity.request.MultipartFormDataParser;
import com.aspectran.web.activity.request.MultipartRequestParseException;
import com.aspectran.web.activity.request.WebRequestBodyParser;
import com.aspectran.web.adapter.HttpServletRequestAdapter;
import com.aspectran.web.adapter.HttpServletResponseAdapter;
import com.aspectran.web.adapter.HttpSessionAdapter;
import com.aspectran.web.adapter.WebRequestAdapter;
import com.aspectran.web.service.WebService;
import com.aspectran.web.support.http.HttpHeaders;
import com.aspectran.web.support.http.MediaType;
Expand All @@ -45,6 +44,7 @@
import java.io.UnsupportedEncodingException;

import static com.aspectran.core.context.rule.RequestRule.LOCALE_CHANGE_INTERCEPTOR_SETTING_NAME;
import static com.aspectran.web.activity.request.WebRequestBodyParser.MAX_REQUEST_SIZE_SETTING_NAME;

/**
* An activity that processes a web request.
Expand All @@ -53,10 +53,6 @@
*/
public class WebActivity extends CoreActivity {

private static final String MULTIPART_FORM_DATA_PARSER_SETTING_NAME = "multipartFormDataParser";

private static final String MAX_REQUEST_SIZE_SETTING_NAME = "maxRequestSize";

private final String reverseContextPath;

private final HttpServletRequest request;
Expand Down Expand Up @@ -223,40 +219,15 @@ protected void parseRequest() throws RequestParseException, ActivityTerminatedEx
MediaType mediaType = ((HttpServletRequestAdapter)getRequestAdapter()).getMediaType();
if (mediaType != null) {
if (WebRequestBodyParser.isMultipartForm(getRequestAdapter().getRequestMethod(), mediaType)) {
parseMultipartFormData();
WebRequestBodyParser.parseMultipartFormData(this);
} else if (WebRequestBodyParser.isURLEncodedForm(mediaType)) {
parseURLEncodedFormData();
WebRequestBodyParser.parseURLEncodedFormData((WebRequestAdapter)getRequestAdapter());
}
}

super.parseRequest();
}

/**
* Parse the multipart form data.
*/
private void parseMultipartFormData() throws MultipartRequestParseException {
String multipartFormDataParser = getSetting(MULTIPART_FORM_DATA_PARSER_SETTING_NAME);
if (multipartFormDataParser == null) {
throw new MultipartRequestParseException("The setting name 'multipartFormDataParser' for multipart " +
"form data parsing is not specified. Please specify 'multipartFormDataParser' via Aspect so " +
"that Translet can parse multipart form data.");
}

MultipartFormDataParser parser = getBean(multipartFormDataParser);
if (parser == null) {
throw new MultipartRequestParseException("No bean named '" + multipartFormDataParser + "' is defined");
}
parser.parse(getRequestAdapter());
}

/**
* Parse the URL-encoded Form Data to get the request parameters.
*/
private void parseURLEncodedFormData() throws RequestParseException {
WebRequestBodyParser.parseURLEncodedFormData(getRequestAdapter());
}

@Override
protected LocaleResolver resolveLocale() {
LocaleResolver localeResolver = super.resolveLocale();
Expand Down
Expand Up @@ -15,10 +15,10 @@
*/
package com.aspectran.web.activity.request;

import com.aspectran.core.activity.Activity;
import com.aspectran.core.activity.request.RequestBodyParser;
import com.aspectran.core.activity.request.RequestParseException;
import com.aspectran.core.activity.request.SizeLimitExceededException;
import com.aspectran.core.adapter.RequestAdapter;
import com.aspectran.core.context.rule.type.MethodType;
import com.aspectran.utils.ClassUtils;
import com.aspectran.utils.LinkedMultiValueMap;
Expand All @@ -29,13 +29,15 @@
import com.aspectran.utils.apon.JsonToApon;
import com.aspectran.utils.apon.Parameters;
import com.aspectran.utils.apon.XmlToApon;
import com.aspectran.web.adapter.WebRequestAdapter;
import com.aspectran.web.support.http.MediaType;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

Expand All @@ -44,28 +46,40 @@
*
* @since 6.2.0
*/
public class WebRequestBodyParser {
public abstract class WebRequestBodyParser {

private static final String DEFAULT_ENCODING = "ISO-8859-1";
public static final String MULTIPART_FORM_DATA_PARSER_SETTING_NAME = "multipartFormDataParser";

public static final String MAX_REQUEST_SIZE_SETTING_NAME = "maxRequestSize";

private static final Charset DEFAULT_ENCODING = StandardCharsets.ISO_8859_1;

private static final int BUFFER_SIZE = 1024;

private WebRequestBodyParser() {
}
/**
* Parse the multipart form data.
*/
public static void parseMultipartFormData(@NonNull Activity activity) throws MultipartRequestParseException {
String multipartFormDataParser = activity.getSetting(MULTIPART_FORM_DATA_PARSER_SETTING_NAME);
if (multipartFormDataParser == null) {
throw new MultipartRequestParseException("The setting name 'multipartFormDataParser' for multipart " +
"form data parsing is not specified. Please specify 'multipartFormDataParser' via Aspect so " +
"that Translet can parse multipart form data.");
}

@NonNull
public static String parseBody(InputStream inputStream, String encoding)
throws IOException, SizeLimitExceededException {
return parseBody(inputStream, encoding, 0L);
MultipartFormDataParser parser = activity.getBean(multipartFormDataParser);
if (parser == null) {
throw new MultipartRequestParseException("No bean named '" + multipartFormDataParser + "' is defined");
}
parser.parse(activity.getRequestAdapter());
}

@NonNull
public static String parseBody(InputStream inputStream, String encoding, long maxSize)
throws IOException, SizeLimitExceededException {
public static String parseBody(WebRequestAdapter requestAdapter) throws IOException, SizeLimitExceededException {
Charset encoding = determineEncoding(requestAdapter);
InputStream inputStream = requestAdapter.getInputStream();
long maxSize = requestAdapter.getMaxRequestSize();
StringBuilder sb = new StringBuilder();
if (encoding == null) {
encoding = DEFAULT_ENCODING;
}
InputStreamReader reader = new InputStreamReader(inputStream, encoding);
char[] buffer = new char[BUFFER_SIZE];
int bytesRead;
Expand All @@ -85,32 +99,46 @@ public static String parseBody(InputStream inputStream, String encoding, long ma
}

@Nullable
public static MultiValueMap<String, String> parseURLEncoded(String body, String encoding)
throws UnsupportedEncodingException {
if (StringUtils.isEmpty(body)) {
public static <T extends Parameters> T parseBodyAsParameters(
@NonNull WebRequestAdapter requestAdapter, Class<T> requiredType) throws RequestParseException {
MediaType mediaType = requestAdapter.getMediaType();
if (mediaType == null) {
return null;
}
MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
String[] pairs = StringUtils.tokenize(body, "&");
for (String pair : pairs) {
int idx = pair.indexOf('=');
if (idx == -1) {
String name = URLDecoder.decode(pair, encoding);
multiValueMap.add(name, null);
} else {
String name = URLDecoder.decode(pair.substring(0, idx), encoding);
String value = URLDecoder.decode(pair.substring(idx + 1), encoding);
multiValueMap.add(name, value);
if (isURLEncodedForm(mediaType)) {
return parseURLEncodedBodyAsParameters(requestAdapter, requiredType);
} else if (MediaType.APPLICATION_JSON.equalsTypeAndSubtype(mediaType)) {
try {
return JsonToApon.from(requestAdapter.getBody(), requiredType);
} catch (IOException e) {
throw new RequestParseException("Failed to parse request body of JSON format to required type [" +
requiredType.getName() + "]", e);
}
} else if (MediaType.APPLICATION_APON.equalsTypeAndSubtype(mediaType)) {
return RequestBodyParser.parseBodyAsParameters(requestAdapter.getBody(), requiredType);
} else if (MediaType.APPLICATION_XML.equalsTypeAndSubtype(mediaType)) {
try {
return XmlToApon.from(requestAdapter.getBody(), requiredType);
} catch (IOException e) {
throw new RequestParseException("Failed to parse request body of XML format to required type [" +
requiredType.getName() + "]", e);
}
} else {
return null;
}
return multiValueMap;
}

public static void parseURLEncodedFormData(RequestAdapter requestAdapter) throws RequestParseException {
/**
* Parse the URL-encoded Form Data to get the request parameters.
*/
public static void parseURLEncodedFormData(WebRequestAdapter requestAdapter) throws RequestParseException {
try {
String body = requestAdapter.getBody();
String encoding = requestAdapter.getEncoding();
MultiValueMap<String, String> multiValueMap = parseURLEncoded(body, encoding);
if (StringUtils.isEmpty(body)) {
return;
}
Charset encoding = determineEncoding(requestAdapter);
MultiValueMap<String, String> multiValueMap = parseURLEncodedBody(body, encoding);
if (multiValueMap != null) {
requestAdapter.putAllParameters(multiValueMap);
requestAdapter.setBody(null);
Expand All @@ -121,15 +149,21 @@ public static void parseURLEncodedFormData(RequestAdapter requestAdapter) throws
}
}

public static boolean isMultipartForm(MethodType requestMethod, MediaType mediaType) {
return MethodType.POST.equals(requestMethod) &&
MediaType.MULTIPART_FORM_DATA.equalsTypeAndSubtype(mediaType);
}

public static boolean isURLEncodedForm(MediaType mediaType) {
return MediaType.APPLICATION_FORM_URLENCODED.equalsTypeAndSubtype(mediaType);
}

@Nullable
public static <T extends Parameters> T parseURLEncodedAsParameters(
RequestAdapter requestAdapter, Class<T> requiredType) throws RequestParseException {
private static <T extends Parameters> T parseURLEncodedBodyAsParameters(
WebRequestAdapter requestAdapter, Class<T> requiredType) throws RequestParseException {
try {
String encoding = requestAdapter.getEncoding();
if (encoding == null) {
encoding = DEFAULT_ENCODING;
}
MultiValueMap<String, String> multiValueMap = parseURLEncoded(requestAdapter.getBody(), encoding);
Charset encoding = determineEncoding(requestAdapter);
MultiValueMap<String, String> multiValueMap = parseURLEncodedBody(requestAdapter.getBody(), encoding);
if (multiValueMap != null && !multiValueMap.isEmpty()) {
T parameters = ClassUtils.createInstance(requiredType);
for (Map.Entry<String, List<String>> entry : multiValueMap.entrySet()) {
Expand All @@ -147,42 +181,40 @@ public static <T extends Parameters> T parseURLEncodedAsParameters(
return null;
}

public static <T extends Parameters> T parseBodyAsParameters(
RequestAdapter requestAdapter, @Nullable MediaType mediaType, Class<T> requiredType)
throws RequestParseException {
if (mediaType == null) {
@Nullable
private static MultiValueMap<String, String> parseURLEncodedBody(String body, Charset encoding) {
if (StringUtils.isEmpty(body)) {
return null;
}
if (isURLEncodedForm(mediaType)) {
return parseURLEncodedAsParameters(requestAdapter, requiredType);
} else if (MediaType.APPLICATION_JSON.equalsTypeAndSubtype(mediaType)) {
try {
return JsonToApon.from(requestAdapter.getBody(), requiredType);
} catch (IOException e) {
throw new RequestParseException("Failed to parse request body of JSON format to required type [" +
requiredType.getName() + "]", e);
}
} else if (MediaType.APPLICATION_APON.equalsTypeAndSubtype(mediaType)) {
return RequestBodyParser.parseBodyAsParameters(requestAdapter.getBody(), requiredType);
} else if (MediaType.APPLICATION_XML.equalsTypeAndSubtype(mediaType)) {
try {
return XmlToApon.from(requestAdapter.getBody(), requiredType);
} catch (IOException e) {
throw new RequestParseException("Failed to parse request body of XML format to required type [" +
requiredType.getName() + "]", e);
MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
String[] pairs = StringUtils.tokenize(body, "&");
for (String pair : pairs) {
int idx = pair.indexOf('=');
if (idx == -1) {
String name = URLDecoder.decode(pair, encoding);
multiValueMap.add(name, null);
} else {
String name = URLDecoder.decode(pair.substring(0, idx), encoding);
String value = URLDecoder.decode(pair.substring(idx + 1), encoding);
multiValueMap.add(name, value);
}
} else {
return null;
}
return multiValueMap;
}

public static boolean isMultipartForm(MethodType requestMethod, MediaType mediaType) {
return MethodType.POST.equals(requestMethod) &&
MediaType.MULTIPART_FORM_DATA.equalsTypeAndSubtype(mediaType);
}

public static boolean isURLEncodedForm(MediaType mediaType) {
return MediaType.APPLICATION_FORM_URLENCODED.equalsTypeAndSubtype(mediaType);
@NonNull
private static Charset determineEncoding(@NonNull WebRequestAdapter requestAdapter) {
Charset encoding = null;
if (requestAdapter.getMediaType() != null) {
encoding = requestAdapter.getMediaType().getCharset();
}
if (encoding == null && requestAdapter.getEncoding() != null) {
encoding = Charset.forName(requestAdapter.getEncoding());
}
if (encoding == null) {
encoding = DEFAULT_ENCODING;
}
return encoding;
}

}

0 comments on commit 88a81d3

Please sign in to comment.