How to get InputStream from MultipartFormDataInput? - jax-rs

I'm trying to save pdf in wildfly, I'm using RestEasy MultipartFormDataInput provided with wildfly 20.0.1,
but it doesn't work.
This is what I have:
public static Response uploadPdfFile(MultipartFormDataInput multipartFormDataInput) {
// local variables
MultivaluedMap<String, String> multivaluedMap = null;
String fileName = null;
InputStream inputStream = null;
String uploadFilePath = null;
try {
Map<String, List<InputPart>> map = multipartFormDataInput.getFormDataMap();
List<InputPart> lstInputPart = map.get("poc");
for(InputPart inputPart : lstInputPart){
// get filename to be uploaded
multivaluedMap = inputPart.getHeaders();
fileName = getFileName(multivaluedMap);
if(null != fileName && !"".equalsIgnoreCase(fileName)){
try {
// write & upload file to UPLOAD_FILE_SERVER
//here I have the error: Unable to find a MessageBodyReader for media type:
//application/pdf
inputStream = inputPart.getBody(InputStream.class,InputStream.class);
uploadFilePath = writeToFileServer(inputStream, fileName);
}catch (Exception e) {
e.printStackTrace();
}
// close the stream
inputStream.close();
}
}
}
catch(IOException ioe){
ioe.printStackTrace();
}
finally{
// release resources, if any
}
return Response.ok("File uploaded successfully at " + uploadFilePath).build();
}
I'm using postman for test, http POST method, in the body I send: form-data - file and selected the file.pdf.
When I sent the request, I have the next RunTimeException when I try:
inputStream = inputPart.getBody(InputStream.class,null);
I get:
java.lang.RuntimeException: RESTEASY007545: Unable to find a MessageBodyReader for media type: application/pdf and class type org.jboss.resteasy.util.Base64$InputStream
At the moment I am saving the file receiving it in Base64, but I think that with MultipartFormDataInput it is the correct way.
This is what I have when debug:
Thanks for your support.

I solved this changing the InputStream from "org.jboss.resteasy.util.Base64.InputStream"
to "java.io.InputStream"

Related

How to encrypt payload file streamingly via WSO2 ESB

I have to implement a scenario by using WSO2 ESB, as encrypting the binary payload streamingly while response to the client side (I assume the content-type in the case is Application/Octet-Stream), below is some details by my thought:
An Endpoint like "http://myhost/backend/" which provides business functionality;
A proxy which pass messages through the endpoint;
I attempt to write an OutSequence to check the Content-type: if the Content-Type matches Application/Octet-Stream, invoke my customized class mediator to encrypt the fileStream Streamingly and response.
I have no idea on how to write the class mediator to make it implemented? How could I get/read the file stream from the message as well as how to put the outputStream back to the response while I could only see mc.getEnvelope().getBody() in mediation method? Below is my current mediator which doesn't work.
public boolean mediate(MessageContext mc) {
org.apache.axis2.context.MessageContext amc = ((Axis2MessageContext) mc).getAxis2MessageContext();
try {
String contentID = amc.getAttachmentMap().getAllContentIDs()[0];
DataHandler dh = amc.getAttachment(contentID);
dh.getDataSource().getName();
InputStream is = null;
try {
is = dh.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println("client read:" + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
Many thanks if anybody with experience would kindly help.
Pasted my current solution for anyone else who confronts similar issue.
In the mediator, I read the file content from response stream via OMText.InputStream and use net.lingala.zip4j package to write a zip file(in memory) with the raw file encrypted; Finally I write the zip file content as ByteArray back to the OMElement of the soap message.
public boolean mediate(MessageContext mc) {
System.out.println("========================Mediator log start================================");
org.apache.axis2.context.MessageContext amc = ((Axis2MessageContext) mc).getAxis2MessageContext();
try {
#SuppressWarnings("unchecked")
Map<String, String> responseHeaders = (Map<String, String>) amc.getProperty("TRANSPORT_HEADERS");
String rawFileName = "";
String[] contentDisps = responseHeaders.get("Content-Disposition").split(";");
for (String item : contentDisps) {
System.out.println("item::" + item);
if (item.trim().startsWith(CONTENT_DISPOSITION_FILENAME)) {
rawFileName = item.substring(item.indexOf("\"") + 1, item.length() - 1);
break;
}
}
responseHeaders.put(
"Content-Disposition",
responseHeaders.get("Content-Disposition").replace(rawFileName,
rawFileName.substring(0, rawFileName.lastIndexOf(".")) + ".myzip"));
OMElement binaryPayload =
amc.getEnvelope().getBody()
.getFirstChildWithName(new QName("http://ws.apache.org/commons/ns/payload", "binary"));
OMText binaryNode = (OMText) binaryPayload.getFirstOMChild();
DataHandler dataHandler = (DataHandler) binaryNode.getDataHandler();
InputStream is = dataHandler.getInputStream();
ByteArrayOutputStream responseOutputStream = new ByteArrayOutputStream();
ZipOutputStream zipOutputStream = getZipOutputStreamInstance(responseOutputStream, rawFileName);
// write to zipOutputStream
byte data[] = new byte[BUFFER_SIZE];
int count;
while ((count = is.read(data, 0, BUFFER_SIZE)) != -1) {
zipOutputStream.write(data, 0, count);
zipOutputStream.flush();
}
zipOutputStream.closeEntry();
zipOutputStream.finish();
InputStream in = new ByteArrayInputStream(responseOutputStream.toByteArray());
DataHandler zipDataHandler = new DataHandler(new StreamingOnRequestDataSource(in));
OMFactory factory = OMAbstractFactory.getOMFactory();
OMText zipData = factory.createOMText(zipDataHandler, true);
zipData.setBinary(true);
binaryPayload.getFirstOMChild().detach();
binaryPayload.addChild(zipData);
amc.setProperty("TRANSPORT_HEADERS", responseHeaders);
System.out.println("========================Mediator end==================================");
} catch (Exception ex) {
System.out.println("exception found here:");
ex.printStackTrace();
}
return true;
}

Limiting upload file size in Playframework 2.2.x

Regarding file upload in play framework 2.2.3.
According to update on this question,
adding the following to application.conf should enable upload of files upto 10MB.
parsers.MultipartFormData.maxLength = 10240K
this does not work for me. I get "413, Request entity too large" error code for any file greater than 1MB.
I tried setting another field
parsers.text.maxLength=10M
Still upload fails with 413.
I upload files using XHR with a FormData that a can contain multiple files.
Upload Controller Code :
public Result uploadAttendeeFiles(){
try{
MultipartFormData body = request().body().asMultipartFormData();
List<FilePart> uploadedFiles = body.getFiles();
Map<String, String> returnMessages = new HashMap<String, String>();
String fileName ="", fileExtension="", fieldId = "";
int fileCounter = 0;
if (!CommonUtils.isEmpty(uploadedFiles)) {
for (FilePart filePar : uploadedFiles) {
try {
fileExtension = Files.getFileExtension(filePar.getFilename());
fieldId = body.asFormUrlEncoded().get("fieldId")[fileCounter];
fileName = body.asFormUrlEncoded().get("fileName")[fileCounter++];
InputStream in = new FileInputStream(filePar.getFile());
Object objectId = uploadService.loadFile(in, fileName, fileExtension);
if(objectId != null)
returnMessages.put(fieldId, objectId.toString());
else
returnMessages.put(fieldId, "failed-Failed to save file!");
} catch (IOException e) {
returnMessages.put(fileName+"."+fileExtension, "failed-Error while uploading file!");
e.printStackTrace();
}
}
}
else{
return ok("{\"errormessage\":\"No files selected!\"}");
}
return ok(Json.toJson(returnMessages));
} catch(Exception e) {
e.printStackTrace();
return ok("{\"errormessage\":\"Error while uploading files!\"}");
}
}

How to send file name with NanoHttpd Response

I've successfully achieved file transfer over local network using NanoHttpd. However, I'm unable to send the file name in NanoHttpd Response. The received files have a default name like this: localhost_8080. I tried to attach file name in response header using Content-disposition, but my file transfer failed all together. What am I doing wrong? Here is my implementation:
private class WebServer extends NanoHTTPD {
String MIME_TYPE;
File file;
public WebServer() {
super(PORT);
}
#Override
public Response serve(String uri, Method method,
Map<String, String> header, Map<String, String> parameters,
Map<String, String> files) {
try {
file=new File(fileToStream);
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
MIME_TYPE= URLConnection.guessContentTypeFromName(file.getName());
} catch (IOException ioe) {
Log.w("Httpd", ioe.toString());
}
NanoHTTPD.Response res=new NanoHTTPD.Response(Status.OK, MIME_TYPE, bis);
res.addHeader("Content-Disposition: attachment; filename=", file.getName());
return res;
}
}
Thanks for your help!
You need to specify the response, the MIME type, and the stream of bytes to be sent. After that you just add a header with the file name of the file since its a http method.
Here is a sample code that solves the problem
#Override
public Response serve(String uri, Method method,
Map<String, String> header, Map<String, String> parameters,
Map<String, String> files) {
FileInputStream fis = null;
try {
fis = new FileInputStream(fileName);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
NanoHTTPD.Response res = new NanoHTTPD.Response(Response.Status.OK, "application/vnd.android.package-archive", fis);
res.addHeader("Content-Disposition", "attachment; filename=\""+fileName+"\"");
return res;
}

com.sun.jersey.api.client.UniformInterfaceException (returned a response status of 400)

I am trying to set up file upload example using JAX RS. I could set up the project and successfully upload file in a server location. But i get the following error when file size is more than 10KB (weird!!)
com.sun.jersey.api.client.UniformInterfaceException: POST http://localhost:9090/DOAFileUploader/rest/file/upload returned a response status of 400
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:607)
at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:507)
at com.sony.doa.rest.client.DOAClient.upload(DOAClient.java:75)
at com.sony.doa.rest.client.DOAMain.main(DOAMain.java:34)
I am new to JAX RS and i'm not sure what exactly the issue is. Do i need to set some parameters client side or server side (like size, timeout etc)?
This is the client side code calling webservice:
public void upload() {
File file = new File(inputFilePath);
FormDataMultiPart part = new FormDataMultiPart();
part.bodyPart(new FileDataBodyPart("file", file, MediaType.APPLICATION_OCTET_STREAM_TYPE));
WebResource resource = Client.create().resource(url);
String response = resource.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(String.class, part);
System.out.println(response);
}
This is the server side code:
#Path("/file")
public class UploadFileService {
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition fileDetail) {
String uploadedFileLocation = "e://uploaded/"
+ fileDetail.getFileName();
writeToFile(uploadedInputStream, uploadedFileLocation);
String output = "File uploaded to : " + uploadedFileLocation;
return Response.status(200).entity(output).build();
}
private void writeToFile(InputStream uploadedInputStream,
String uploadedFileLocation) {
try {
OutputStream out = new FileOutputStream(new File(
uploadedFileLocation));
int read = 0;
byte[] bytes = new byte[16000];
out = new FileOutputStream(new File(uploadedFileLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
} } }
Please let me know what settings i have to change for file sizes greater than 10KB?
Thanks!
I use org.apache.commons.fileupload.servlet.ServletFileUpload in a Jersey context, and it works fine., and yes, it set the max file size, sorry I missed this before.
here is a snipet of code I use (this is a multipart form, so there are other fields along with the file)
private LibraryUpload parseLibraryUpload(HttpServletRequest request) {
LibraryUpload libraryUpload;
File libraryZip = null;
String name = null;
String version = null;
ServletFileUpload upload = new ServletFileUpload();
upload.setFileSizeMax(MAX_FILE_SIZE);
FileItemIterator iter;
try {
iter = upload.getItemIterator(request);
while (iter.hasNext()) {
....
if (item.isFormField()) {
....
}else{
BufferedInputStream buffer = new BufferedInputStream(stream);
buffer.mark(MAX_FILE_SIZE);
libraryZip = File.createTempFile("fromUpload", null);
IOUtils.copy(buffer, new FileOutputStream(libraryZip));
...
}
I have encountered the same problem with Jersey. I have activated jersey trace but nothing help me.
I have changed the library by an apache Library and I see than the problem with linked to a repository for temporary files for tomcat. The repository was not exist. For files under 10k, the repository was not used.
So, after the repository creation, I used jersey library and all works fine.

JavaFX: File upload to REST service / servlet fails because of missing boundary

I'm trying to upload a file using JavaFX using the HttpRequest. For this purpose I have written the following function.
function uploadFile(inputFile : File) : Void {
// check file
if (inputFile == null or not(inputFile.exists()) or inputFile.isDirectory()) {
return;
}
def httpRequest : HttpRequest = HttpRequest {
location: urlConverter.encodeURL("{serverUrl}");
source: new FileInputStream(inputFile)
method: HttpRequest.POST
headers: [
HttpHeader {
name: HttpHeader.CONTENT_TYPE
value: "multipart/form-data"
}
]
}
httpRequest.start();
}
On the server side, I am trying to handle the incoming data using the Apache Commons FileUpload API using a Jersey REST service. The code used to do this is a simple copy of the FileUpload tutorial on the Apache homepage.
#Path("Upload")
public class UploadService {
public static final String RC_OK = "OK";
public static final String RC_ERROR = "ERROR";
#POST
#Produces("text/plain")
public String handleFileUpload(#Context HttpServletRequest request) {
if (!ServletFileUpload.isMultipartContent(request)) {
return RC_ERROR;
}
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = null;
try {
items = upload.parseRequest(request);
}
catch (FileUploadException e) {
e.printStackTrace();
return RC_ERROR;
}
...
}
}
However, I get a exception at items = upload.parseRequest(request);:
org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
I guess I have to add a manual boundary info to the InputStream. Is there any easy solution to do this? Or are there even other solutions?
Have you tried just using the InputStream from HttpServletRequest like so
InputStream is = httpRequest.getInputStream();
BufferedInputStream in = new BufferedInputStream(is);
//Write out bytes
out.close();
is.close();