Multipart/form-data Mixed field and file

800 views
Skip to first unread message

justinl...@gmail.com

unread,
Aug 10, 2017, 1:58:34 PM8/10/17
to vert.x
Hello,

do you think it is possible to get form-field in order in server-side ?
The primary motivation for wanting to know this is so I can do server-side validation of form data w/o being required to cache the entire HTTP request in RAM | disk first.

it could be good to have an handler for each field in the same order than the html/form (http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4)

maybe there is also a solution with vertx but i don't find it :(

this is my code :

html

<form action="/" ENCTYPE="multipart/form-data" method="POST" name="wibble">
    foo:
<input type="text" name="foo"/><br>
    bar:
<input type="text" name="bar"/><br>
    choose a file to upload:
<input type="file" name="myfile"/><br>
   
<input type="submit"/>
</form>


verticle

     
vertx.createHttpServer()
     
.requestHandler(req -> {
         
final String contentType = req.getHeader(HttpHeaders.CONTENT_TYPE);
         
Boolean isMultipart = contentType != null && contentType.contains("multipart/form-data");

         
if (isMultipart) {    
              req
.setExpectMultipart(true);
             
String foo = req.getFormAttribute("foo");
             
System.out.println(foo); // NULL value                  
              req
.uploadHandler(upload -> {
                  upload
.handler(buff -> {
                     
System.out.println("data");
                 
});
                  upload
.endHandler(r -> {
                     
System.out.println("enddata");
                 
});
             
});

              req
.endHandler(fin -> {
               
String foo = req.getFormAttribute("foo");
               
System.out.println(foo); // good value
             
});
         
} else {
              req
.response().sendFile("index.html");
         
}
          req
.exceptionHandler(th -> {
             
System.out.println("fail to handle request");
         
});
     
})
     
.listen(8080);




Paulo Lopes

unread,
Aug 11, 2017, 5:18:25 AM8/11/17
to vert.x
Currently form attributes are populated at the end of the request, that is why your code prints null in the begin and prints the right value at the end. Since the filling of the attribute multimap is not a hander you can't quickly change the behavior since you don't know when the attribute has been parsed or not.

Can you describe a good use case for this feature? Why is it so important that the order is preserved?

justinl...@gmail.com

unread,
Aug 11, 2017, 9:34:18 AM8/11/17
to vert.x
For exemple imagine a upload file form with a token validation

<form action="/" ENCTYPE="multipart/form-data" method="POST" name="wibble">

    token:
<input type="text" name="token"/><br>

   
choose a file to upload:<input type="file" name="myfile"/><br>
   
<input type="submit"/>
</form>


if i can check the validity of the token before retrieve the whole request, i can abort the request if the token is invalid and save resource in server-side.

i have check the vertx code (HttpServerRequestImpl) and i see two solution :

1) Add handler into HttpServerRequest => attributehandler, but it needs to modify three class HttpServerRequest, HttpServerRequestImpl,  and NettyFileUploadDataFactory
and override createAttribute(...) like createFileUpload into NettyFileUploadDataFactory

2) A more simple solution is to check when we call formAttributes(), if there is also any attributes that have been parsed by the decoder.

The second solution don't change anything to the current behaviour.

i have implemented the second solution (i join the file), can you check rapidly ?
And can you tell me what unit test cover multipart  please ?

if is good, i can do a pullrequest
HttpServerRequestImpl.java

Paulo Lopes

unread,
Aug 11, 2017, 3:22:03 PM8/11/17
to vert.x
just some thoughts,

regarding API Tokens, you want to abort the request ASAP, in that case it would make more sense to use an HTTP header for it, either the `Authorization` or some custom `X-APITOKEN` for example so the processing can be stopped before handling the body, or if you need to use HTML forms, a path parameter/variable.

This way it could be even be stopped by a proxy to the application if needed...

Now regarding the proposed fixes, the 1st one would have some impact but would work as expected imho. While the second one would only be useful if you're handling the body yourself (like in your example), where you can check the value of the form attributes once a buffer is delivered to the handler. For other users, such as everyone using vert.x web this would not change at all the current behavior and it wouldn't be exposed either.

My concern with 2 is that knowing when a new param has been parsed is not deterministic since there is no handler for it, so depending on the handler where you're requesting the parsed attribute the value can be either null or not null...

I guess you could open a discussion on vertx-core github issues and link to this thread for discussion.

justinl...@gmail.com

unread,
Aug 11, 2017, 5:38:11 PM8/11/17
to vert.x


regarding API Tokens, you want to abort the request ASAP, in that case it would make more sense to use an HTTP header for it, either the `Authorization` or some custom `X-APITOKEN` for example so the processing can be stopped before handling the body, or if you need to use HTML forms, a path parameter/variable.


yes i agree with you but i need to consume request from client that use multipart/form-data method to deal with token ...
 
This way it could be even be stopped by a proxy to the application if needed...

Now regarding the proposed fixes, the 1st one would have some impact but would work as expected imho. While the second one would only be useful if you're handling the body yourself (like in your example), where you can check the value of the form attributes once a buffer is delivered to the handler. For other users, such as everyone using vert.x web this would not change at all the current behavior and it wouldn't be exposed either.

My concern with 2 is that knowing when a new param has been parsed is not deterministic since there is no handler for it, so depending on the handler where you're requesting the parsed attribute the value can be either null or not null...


effectively, but we could use the odrer of form attributes for that.

in fact there is two case :
1) no uploadfile attribure => we can retrieve param only when the whole body is retrieved
2) mixed => at each uploadHandler call, we can get previous attributes (in order of forms)

but effectively, it's not clear for end user, and that's why i think the first method that "emit" an handlerAttribute is better
 

Reply all
Reply to author
Forward
0 new messages