Skip to content

Commit 702b78a

Browse files
General source cleanup and docs in multipart request handling
1 parent 82c8916 commit 702b78a

File tree

1 file changed

+38
-48
lines changed

1 file changed

+38
-48
lines changed

ng-adaptor-jetty/src/main/java/ng/adaptor/jetty/NGAdaptorJetty.java

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.eclipse.jetty.http.MultiPartConfig;
2626
import org.eclipse.jetty.http.MultiPartFormData;
2727
import org.eclipse.jetty.http.MultiPartFormData.ContentSource;
28-
import org.eclipse.jetty.http.MultiPartFormData.Parts;
2928
import org.eclipse.jetty.io.Content;
3029
import org.eclipse.jetty.io.Content.Source;
3130
import org.eclipse.jetty.server.Handler;
@@ -104,15 +103,6 @@ public void start( NGApplication application ) {
104103

105104
public class NGHandler extends Handler.Abstract {
106105

107-
/**
108-
* The directory used by Jetty to store cached data during processing of multipart requests
109-
*
110-
* FIXME: This should probably be specified in a property // Hugi 2025-06-17
111-
*/
112-
private static final String multipartTemporaryDirectory() {
113-
return "/tmp/ngmultijet";
114-
}
115-
116106
@Override
117107
public boolean handle( Request request, Response response, Callback callback ) throws Exception {
118108
doRequest( request, response, callback );
@@ -228,53 +218,53 @@ private static HttpCookie ngCookieToJettyCookie( final NGCookie ngCookie ) {
228218
return jettyCookieBuilder.build();
229219
}
230220

221+
/**
222+
* @return Jetty's configuration for handling of multipart request parsing
223+
*
224+
* FIXME: MultiPart configuration needs to be configurable on ng's side. Or we need to expose the Jetty configuration (which I'd prefer not to, since that makes configuration implementation dependent) // Hugi 2025-06-17
225+
*/
226+
private static MultiPartConfig multiPartConfig() {
227+
return new MultiPartConfig.Builder()
228+
.location( Path.of( "/tmp/ngmultijet" ) ) // Path to a directory used by Jetty to store cached data during processing of multipart requests
229+
.build();
230+
}
231+
231232
/**
232233
* @return the given Request converted to an NGRequest
233234
*/
234235
private static NGRequest multipartRequestToNGRequest( final Request jettyRequest, final String contentType, final Callback callback ) {
235236

236-
final MultiPartConfig config = new MultiPartConfig.Builder()
237-
.location( Path.of( multipartTemporaryDirectory() ) )
238-
.build();
239-
240-
// The formValues that will get set on the request
237+
// Regular formValues to set on the request
241238
final Map<String, List<String>> formValues = new HashMap<>();
242239

243-
// The uploaded files, if any
240+
// Uploaded files to set on the request
244241
final Map<String, UploadedFile> uploadedFiles = new HashMap<>();
245242

246-
final Parts parts = MultiPartFormData.getParts( jettyRequest, jettyRequest, contentType, config );
247-
248-
parts.forEach( p -> {
249-
final String partContentType = p.getHeaders().get( HttpHeader.CONTENT_TYPE );
250-
251-
final String parameterName = p.getName();
252-
final String parameterValue;
253-
254-
// We're assuming that if this part does not have a content type, it's a regular ol' form value, to be added to the requests formValues map as usual.
255-
if( partContentType == null ) {
256-
parameterValue = p.getContentAsString( StandardCharsets.UTF_8 ); // FIXME: Hardcoding the character set is a little presumptuous // Hugi 2025-04-05
257-
}
258-
else {
259-
// We're generating a unique ID here to store the attachment under in the request. This value will be stored in the request's formValues, and can be used to fetch the uploaded data in the request's uploadedFiles map
260-
final String uniqueID = UUID.randomUUID().toString();
261-
262-
parameterValue = uniqueID;
263-
264-
// Now we add the uploaded file to the request
265-
final UploadedFile file = new UploadedFile( p.getFileName(), partContentType, Content.Source.asInputStream( p.getContentSource() ), p.getLength() );
266-
uploadedFiles.put( uniqueID, file );
267-
}
268-
269-
List<String> list = formValues.get( parameterName );
270-
271-
if( list == null ) {
272-
list = new ArrayList<>();
273-
formValues.put( p.getName(), list );
274-
}
275-
276-
list.add( parameterValue );
277-
} );
243+
MultiPartFormData
244+
.getParts( jettyRequest, jettyRequest, contentType, multiPartConfig() )
245+
.forEach( part -> {
246+
final String partContentType = part.getHeaders().get( HttpHeader.CONTENT_TYPE );
247+
248+
final String parameterValue;
249+
250+
if( partContentType == null ) {
251+
// If this part does not have a content type, we treat it like a regular ol' form value, added to the request's formValues map as usual
252+
parameterValue = part.getContentAsString( StandardCharsets.UTF_8 ); // FIXME: Hardcoding the character set is a little presumptuous // Hugi 2025-04-05
253+
}
254+
else {
255+
// We generate a unique ID to store the attachment under. The ID will be stored as a value under the part's name in the request's formValues, where it can be used to obtaing the uploaded file from the request's uploadedFiles map
256+
parameterValue = UUID.randomUUID().toString();
257+
258+
// Now we add the uploaded file to the request
259+
final UploadedFile file = new UploadedFile( part.getFileName(), partContentType, Content.Source.asInputStream( part.getContentSource() ), part.getLength() );
260+
uploadedFiles.put( parameterValue, file );
261+
}
262+
263+
// Finally, we add our "value" to the request's form values
264+
formValues
265+
.computeIfAbsent( part.getName(), _unused -> new ArrayList<>() )
266+
.add( parameterValue );
267+
} );
278268

279269
final String method = jettyRequest.getMethod();
280270
final String uri = jettyRequest.getHttpURI().getCanonicalPath();

0 commit comments

Comments
 (0)