For my current solution, I'm using apache commons FileUpload library to process incoming multi-part requests. I'm able to send the files appropriately then read the stream on the server end using the streaming api code here.
If you look at the format of multipart requests listed here, there is a Content-Disposition listed for each file added. I need to add a startByte tag (similar to how you add a "filename" tag in content-disposition). I'm not too sure how to do that properly and then retrieve it in the request? This is of course not a global header, because multiple files are in this stream.
Anyone have any ideas?
This is for anyone who might be interested, and turns out was easy: To do this, on the client, you append the header like below:
outputStream.writeBytes("Content-Disposition: form-data; name=\"" + filename + "\"; filename=\"" + filename + "\";\r\n");
outputStream.writeBytes("My-Custom-Header: My-Data\r\n");
outputStream.writeBytes("\r\n");
Then, on the server, using commons FileUpload, you would just do:
FileItemHeaders headers = item.getHeaders();
headers.getHeader("My-Custom-Header");
Related
I have a Java client which calls one REST web service. The web service accepts data in JSON format and produces data in multipart format. The content-type I have set here for calling the web service is 'application/json'
Now, in the java client I have to get the response and separate multiple files that are there in the multipart response. I have used following code to get the response.
ByteArrayDataSource ds = new ByteArrayDataSource(conn.getInputStream(), "multipart/form-data;boundary=" + boundary);
MimeMultipart multipart = new MimeMultipart(ds);
System.out.println(multipart.getCount());
When final line is executed, I get following exception
javax.mail.MessagingException: Missing start boundary.
I understand that when it tries to count the files in the response, it does not understand where to start and stop. So, should the webservice set the boundary where files are separated? If yes, how it is done?
If no, what can be done?
I think your boundary is wrong
The right boundary starts with "--" and then followed by a hash. Try to change the boundary parameter to
"--" + boundary
to see if that helps.
I have also faced a similar problem and found a workaround here: https://stackoverflow.com/a/42548549/5236494
Basically I am using javax mail's MimeMultipart class to parse the Multipart response.
I create Java 7 REST service using Spring, Apache CXF.
public SuccessfulResponse uploadFile(#Multipart("report") Attachment attachment)
I use "Content-Disposition" parameter in order to retrieve file name. I've read some solutions which are usedfor downloading files (for example, url-encoding). But how to cope with non-ASCII filenames for upload? Is it a client-side or a server-side solution? The signature of the method above can be changed. The client side uses html5 file api + iframe.
My experience is that content-disposition doesn't handle UTF8 in general. You can simply add another multipart field for the filename - multipart fields support charset indication and handles UTF8 chars if done correctly.
You can use the UTF8 for a filename (according to https://www.rfc-editor.org/rfc/rfc6266 and https://www.rfc-editor.org/rfc/rfc5987). For the Spring the easiest way is to use org.springframework.http.ContentDisposition class. For example:
ContentDisposition disposition = ContentDisposition
.builder("attachment")
.filename("репорт.export", StandardCharsets.UTF_8)
.build();
return ResponseEntity
.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION, disposition.toString())
.body((out) -> messageService.exportMessages(out));
It is an example to send the file from the server (download). To upload the file you can follow the same RFC, even the Content-Disposition header must be prepared on the browser, by JavaScript for example, and looks like:
Content-Disposition: attachment;
filename="EURO rates";
filename*=utf-8''%e2%82%ac%20rates
Parameter filename is optional in this case and is a fallback for the systems that don't support the RFC 6266 (it contains the ASCII file name). Value for filename* must the URL Encoded (https://www.url-encode-decode.com).
i'm using the following tutorial to upload a file in Android:
http://reecon.wordpress.com/2010/04/25/uploading-files-to-http-server-using-post-android-sdk/
On the server side I use Java servlets with Apache IOUtils to handle it.
ServletFileUpload fileUpload = new ServletFileUpload();
FileItemIterator fileItemIterator = fileUpload.getItemIterator(request);
while (fileItemIterator.hasNext()) {
FileItemStream filestream = fileItemIterator.next();
doStuff(filestream);
}
In the browser everything works fine, but on Android my problem is that when I call getContentType on a filestream, it returns null.
Why are the differences here? I'm not handling the null value of getContentType because something tells me is not ok to be null.
I used Wireshark to view what was the browser actually sending.
It seams that (among other stuff), another Content-Type header is sent (in the "MIME Multipart Media Encapsulation" section), after Content-Disposition (for ex. "Content-Type: application/pdf\r\n\r\n".
So, in the file upload tutorial, after the following line:
dos.writeBytes("Content-Disposition: form-data;name=\"uploadedfile\";" + "filename=\"" + fileName + "\"" + lineEnd);
I just added:
String mimeType = URLConnection.guessContentTypeFromName(file.getName());
dos.writeBytes("Content-Type: " + mimeType + lineEnd);
Now it seams the uploading process is working fine.
Of course, for many extensions, mimeType will probably be null, so it should be checked, according to needs.
I am uploading file using httpclient. After uploading file size get changed. During file upload some extra things get added in to file.
Before uploading file it contains:
hi this is vipin check
After uploading the file contains:
--j9q7PmvnWSP9wKHHp2w_KCI4Q2jCniJvPbrE0
Content-Disposition: form-data; name="vipin.txt"; filename="vipin.txt"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
hi this is vipin check
--j9q7PmvnWSP9wKHHp2w_KCI4Q2jCniJvPbrE0--
Why file size is changing?
Why does this extra contents get added?
My httpclient code is:
HttpPut httppost = new HttpPut(URIUtil.encodeQuery(newUrl));
httppost.setHeader("X-Auth-Token", cred.getAuthToken());
httppost.addHeader("User-Agent", "NetMagic-file-upload");
System.out.println("Dest : " + dest.getAbsolutePath());
MultipartEntity mpEntity = new MultipartEntity();
ContentBody cbFile = (ContentBody) new FileBody(src);
mpEntity.addPart(dest.getName(), cbFile);
httppost.setEntity(mpEntity);
System.out.println("executing request " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
You're doing a PUT request, yet your client uses multipart encoding as commonly uses in HTML form posts.
What appears to be happening is that the client is sending the file to be uploaded as multipart entity, but the server is treating it as an plain file. It is not entirely clear where the fault lies.
It is possible that the server is ignoring the content type in the request header. That would most likely be a bug in the servlet (or whatever) that is responsible for handing the upload request.
It is possible that the client is not setting a content type in the request header. I'd have expected that the client library would take care of that for you. But it is possible that you need to do it explicitly.
I'd advise looking at the request headers as they are sent by the client or received by the server to see if there is a proper multi-part content-type. That will help you determine where the problem is.
But there is an obvious solution. If the server cannot cope with multiparts, change the client side to not send them.
I am looking to create a RESTful API for use with an Android and iOS app. So far I have been experimenting with using Jersey on the server and then the appropriate http libraries on the client side. At the moment I have been using multipart/related as the mimetype for the request with JSON forming the first part of the body then a jpeg image as the second.
So far I have had problems with making the request to the server, getting a 406 Not Acceptable from Jersey. I note that multipart/related is primarily used in sending emails. Is there actually a way that I can support mixed type content as an upload or have I entirely mis-understood the usage of multipart/related in this context?
You may want to look at this blog, for more information, but here is the important part to help you along:
http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition fileDetail) {
String uploadedFileLocation = "d://uploaded/" + fileDetail.getFileName();
// save it
writeToFile(uploadedInputStream, uploadedFileLocation);
String output = "File uploaded to : " + uploadedFileLocation;
return Response.status(200).entity(output).build();
}
I expect you want multipart/form-data instead, as this is part of the description of multipart/related:
The Multipart/Related media type is intended for compound objects
consisting of several inter-related body parts. For a
Multipart/Related object, proper display cannot be achieved by
individually displaying the constituent body parts. The content-type
of the Multipart/Related object is specified by the type parameter.
The "start" parameter, if given, points, via a content-ID, to the
body part that contains the object root. The default root is the
first body part within the Multipart/Related body.
For more on this mime type you can look at
https://www.rfc-editor.org/rfc/rfc2387
If you are wanting to submit image along with the json body, you can base64 encode the image and include the base64 string in the json. Then on the server side, you base64 decode the string and upload the image file to the blobstore. See the file upload example (at the bottom of the page) here https://developers.google.com/appengine/docs/java/blobstore/overview
Alternatively, you could do a separate upload to the blobstore and get the blobkey for the uploaded image. You can then include the blobkey in the json body that you post to the server.Using this approach you would need to get the uploadurl every time you need to do a new image upload.