1

I run a simple backend app which allows to upload files. I use Jersey and run it in Jetty. The piece of my code looks like this:

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(@Context UriInfo uriInfo, FormDataMultiPart multipart, @Context  HttpServletRequest httpRequest) {
    FormDataBodyPart fileId = multipart.getField("fileId");
    FormDataBodyPart fileSize = multipart.getField("fileSize");
    FormDataBodyPart file = multipart.getField("file");

    ContentDisposition cd = file.getContentDisposition();
    String fileName = cd.getFileName();
    long size = Long.valueOf(fileSize.getValue());
    ...

Upload works just fine, but I found that the method is called just when the whole stream is uploaded to the backend. So, for instance, if I send huge file (3Gigs to be uploaded) my POST request immediately appears on the backend, but the method above is invoked only when the whole 3 Gigs are uploaded through the network.

I would like to make some checks in the method and don't upload the file for some cases, so it doesn't need to pass the whole content to the backend and then send the error message back.

How can I avoid uploading the whole file content to the backend but make the method is invoked before I start to read from the data stream?

barmatat
  • 291
  • 2
  • 10
  • What checks are you wanting to make? I don't think you'll be able to make checks on anything within the `MultiPart` entity - IE fileId, because this would require the whole entity to be transmitted first. – Will Jul 15 '14 at 07:53
  • @Will, I would like to make some throttling check, so don't accept file if the size exceeds some value or many uploads have been made for some period of time. Actually I did some research for last couple days and it looks like there is no way to send a response before the whole multipart entity is consumed :(. It doesn't relate to Jetty, but to HTTP... – barmatat Jul 15 '14 at 15:50

1 Answers1

1

Eventually I worked it around with 2 sequential POSTs the client should make to upload such big files:

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response newUpload(@Context UriInfo uriInfo, FormDataMultiPart multipart,
        @Context HttpServletRequest httpRequest) {
    FormDataBodyPart fileSize = multipart.getField("fileSize");
    long size = Long.valueOf(fileSize.getValue());
    if (!checkSizeLimits(size)) {
        return Response.status(Status.BAD_REQUEST).build();
    }
    // here comes some code which generates an unique id and its URI for the data
    ...
    return Response.status(Status.CREATED).entity(new FileUploadInfo(uri.toString())).build();
}

@POST
@Path("/{fileId}")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(@Context UriInfo uriInfo, FormDataMultiPart multipart,
        @Context HttpServletRequest httpRequest, @PathParam("fileId") String fileId) {
    FormDataBodyPart fileSize = multipart.getField("fileSize");
    FormDataBodyPart file = multipart.getField("file");
    //...
    return Response.status(Status.CREATED).entity(new FileUploadInfo(uri.toString())).build();
 }

It looks ugly, but better than to do the file size check after the data stream is completely loaded. So, client should make POST call to the newUpload() method first providing the file size. If the size is ok, the response contains URI for the second POST to stream the file data. The second method can do the file size check again (not provided), to be sure that the initial POST had the same file size field.

barmatat
  • 291
  • 2
  • 10