I have a web-service provider(Java), which imports a .doc file to the NotesDocument. The problem occurs with files with Russian characters in their names - they aren't correctly transferred.
For example, if the filename will be equal to Безымянный.doc, it will be transferred as Áåçûìÿííûé.doc.
File directory = new File("C:\\Attachments 1C");
String filename = "Безымянный.doc"
String path = directory + "\\" + filename;
Stream outStream = sess.createStream();
sess.setConvertMIME(true);
MIMEEntity body = newDoc.createMIMEEntity("rtBody");
Stream inStream = sess.createStream();
if (inStream.open(path, "binary")) {
if (inStream.getBytes() > 0) {
do {
byte[] buffer = inStream.read(32767);
outStream.write(buffer);
} while (!inStream.isEOS());
inStream.close();
MIMEEntity child = body.createChildEntity();
String fileSuffix = path.substring(path.lastIndexOf(".")+1);
child.setContentFromBytes(outStream, fileSuffix, MIMEEntity.ENC_IDENTITY_BINARY);
MIMEHeader header = child.createHeader("Content-Disposition");
header.setHeaderVal("attachment; filename=\"" + filename + "\"");
header = child.createHeader("Content-ID");
header.setHeaderVal(path);
outStream.truncate();
}else
return "empty file";
}else
return "couldn't open the file";
How to fix this?
The standards for this are not quite final and the behavior will depend on what browser is being used. See the question and answers to this previous question on StackOverflow for a detailed explanation and for information about what works with various browsers.
The problem is solved by encoding the filename using MimeUtility(others don't work):
String filenameEndoded = MimeUtility.encodeText(filename,"Cp1251","B");
Related
Fortify SCA tool find an issue called Portability Flaw: File Separator, but with the source of those issues, there is none hardcoded file separator such as "/" or "\", only file extensions such as "." exists.
Our customer used Fortify SCA to scan their legacy system source codes. Fortify found Portability Flaw: File Separator issues. It said that the file names which declared in a String array contain hard-coded file separator (this string array is the source of the problem), but I can't see any file separator such as "/" or "\" in those file name strings.
public static final String SYS_SPRAT = File.separator; //this is declared as a class attribute
String[] fileNames = { //fortify points out here is the source of this issue
"",
"2.5.1aaaaa.pdf",
"2.5.2bbbbb.pdf",
"2.5.3ccccc.pdf",
.......
"5.1.4甲甲甲甲甲.pdf",
};
String fileName = null;
File file = null;
int iParam = Integer.parseInt(sParam);
if (iParam >= 1 && iParam <= 26) {
fileName = fileNames[iParam];
String filePath = SYS_SPRAT + "home" + SYS_SPRAT + "xxx" + SYS_SPRAT + "ooo" + SYS_SPRAT + "Resource" + SYS_SPRAT + fileName;
file = new File(filePath);
else {
addFacesMessage("wrong parameter");
return null;
}
I still can't figure out why there is an issue. Is it a false positive? (but why?)
It seems that Fortify may be overly strict here. Even their website says that using File.separator like this should be ok.
I can't see any portability problem using File.separator. Even on OpenVMS systems, where file paths are in the format devicename:[directory.subdirectory]file.ext;version, the Java runtime internally translates between a / separator and the proper VMS format.
First, double-check using a "Find" tool that you don't have any \ or / characters in any of the strings in filenames[] (don't just rely on visual inspection). If there is definitely no such character, then proceed with the suggestion below.
Try avoiding File.separator altogether. Instead, try using Paths.get:
public static final Path RESOURCE_DIR = Paths.get(
"home", "xxx", "ooo", "Resource");
String[] fileNames = {
"",
"2.5.1aaaaa.pdf",
"2.5.2bbbbb.pdf",
"2.5.3ccccc.pdf",
.......
"5.1.4甲甲甲甲甲.pdf",
};
String fileName = null;
File file = null;
int iParam = Integer.parseInt(sParam);
if (iParam >= 1 && iParam <= 26) {
fileName = fileNames[iParam];
file = RESOURCE_DIR.resolve(filePath).toFile();
else {
addFacesMessage("wrong parameter");
return null;
}
Is Fortify ok when you do this?
I am trying to detect the File Extension of a file passed as an InputStream, the extension is detected correctly but the file tends to become corrupted after that. Here is my method for detecting Extension -
public static Optional<String> detectFileExtension(InputStream inputStream) {
// To provide mark/reset functionality to the stream required by Tika.
InputStream bufferedInputStream = new BufferedInputStream(inputStream);
String extension = null;
try {
MimeTypes mimeRepository = getMimeRepository();
MediaType mediaType = mimeRepository.detect(bufferedInputStream, new Metadata());
MimeType mimeType = mimeRepository.forName(mediaType.toString());
extension = mimeType.getExtension();
log.info("File Extension detected: {}", extension);
// Need to reset input stream pos marker since it was updated while detecting the extension
inputStream.reset();
bufferedInputStream.close();
} catch (MimeTypeException | IOException ignored) {
log.error("Unable to detect extension of the file from the provided stream");
}
return Optional.ofNullable(extension);
}
private static MimeTypes getMimeRepository() {
TikaConfig config = TikaConfig.getDefaultConfig();
return config.getMimeRepository();
}
Now when I am trying to save this file after extension detection again using the same InputStream like -
byte[] documentContentByteArray = IOUtils.toByteArray(inputStream);
Optional<String> extension = FileTypeHelper.detectFileExtension(inputStream);
if (extension.isPresent()) {
fileName = fileName + extension.get();
} else {
log.warn("File: {} does not have a valid extension", fileName);
}
File file = new File("/tmp/" + fileName);
FileUtils.writeByteArrayToFile(file, documentContentByteArray);
It creates a file but a corrupted one. I guess after stream consumption in detectFileExtension the stream is not getting reset properly. If someone has done this before some guidance would be great, thanks in advance.
I fixed it by not using the same input stream again and again.
I created a new stream to pass for extension detection and the initial stream for creating the file.
byte[] documentContentByteArray = IOUtils.toByteArray(inputStream);
//extension detection
InputStream extensionDetectionInputStream = new ByteArrayInputStream(documentContentByteArray);
Optional<String> extension = FileTypeHelper.detectFileExtension(inputStream);
if (extension.isPresent()) {
fileName = fileName + extension.get();
} else {
log.warn("File: {} does not have a valid extension", fileName);
}
extensionDetectionInputStream.close();
//File creation
File file = new File("/tmp/" + fileName);
FileUtils.writeByteArrayToFile(file, documentContentByteArray);
If there is a better way to do that by reusing the same stream it would be great and I'll gladly accept that answer, for now, I am marking this as the accepted answer.
Hi to you all java experts.
I have this piece of code I could finally put together that works: (it's mostly java with a little ADF code)
public String upload(){
UploadedFile myfile = this.getFile();
FacesContext fctx = FacesContext.getCurrentInstance();
ServletContext servletCtx =
(ServletContext)fctx.getExternalContext().getContext();
String imageDirPath = servletCtx.getRealPath("/");
String nomdefichier = myfile.getFilename();
String mimetype = nomdefichier.substring(nomdefichier.length() - 3);
try {
InputStream inputStream = myfile.getInputStream();
BufferedImage input = ImageIO.read(inputStream);
File outputFile =
new File( System.getProperty("user.home") + File.separator + this.path + File.separator + nomdefichier);
ImageIO.write(input, mimetype, outputFile);
} catch (Exception ex) {
// handle exception
}
FacesMessage message =
new FacesMessage(mimetype + "Successfully uploaded file " + nomdefichier +
" (" + myfile.getLength() + " bytes)" + mimetype);
fctx.addMessage(null, message);
return null;
}
This codes uploads a picture just fine. I would really like to know if there is a file equivalent to ImageIO.write so that I could upload PDF, DOCX and such.
Thanks in advance for any response.
Best regards.
Marc Arbour
A simplified version of your code could be written as follows (omitting some of the JSF related stuff).
InputStream in = myFile.getInputStream();
Files.copy(in, Paths.get(yourPath));
You can write a byte array or an InputStream to a file with the java.nio.file.Files class (since Java 1.7).
// Saving data from an inputstream to a file:
Files.copy(inputStream, targetPath, copyOptions...);
// Saving a byte array to a file:
Files.write(path, byteArray, openOptions...);
I tried to specify attachments.path property in my application.conf file, but this had no effects.
In the documentation of play 2.0.1 I didn't find anything explaining how to change uploaded files directory.
Am I missing something?
Although there is no such variable in application.conf you can easily add it and use in your method. Call it as you wish ie:
new line in application.conf:
myUploadPath = "/home/your-account/some/custom/upload/folder/"
according to the documentation sample:
public static Result upload() {
MultipartFormData body = request().body().asMultipartFormData();
MultipartFormData.FilePart picture = body.getFile("picture");
if (picture != null) {
String fileName = picture.getFilename();
String contentType = picture.getContentType();
File file = picture.getFile();
// added lines
String myUploadPath = Play.application().configuration().getString("myUploadPath");
file.renameTo(new File(myUploadPath, fileName));
return ok("file saved as " + myUploadPath + fileName);
} else {
flash("error", "Missing file");
return redirect(routes.Application.uploadform());
}
}
Using this approach you can or even should perform filename clash check before renaming, to prevent random overwriting.
I have written a Java web application that allows a user to download files from a server. These files are quite large and so are zipped together before download.
It works like this:
1. The user gets a list of files that match his/her criteria
2. If the user likes a file and wants to download he/she selects it by checking a checkbox
3. The user then clicks "download"
4. The files are then zipped and stored on a servera
5. The user this then presented with a page which contains a link to the downloadable zip filea
6. However on downloading the zip file the file that is downloaded is 0 bytes in sizea
I have checked the remote server and the zip file is being created properly, all that is left is to serve the file the user somehow, can you see where I might be going wrong, or suggest a better way to serve the zip file.
The code that creates the link is:
<%
String zipFileURL = (String) request.getAttribute("zipFileURL"); %>
<p>Zip File Link</p>
The code that creates the zipFileURL variable is:
public static String zipFiles(ArrayList<String> fileList, String contextRootPath) {
//time-stamping
Date date = new Date();
Timestamp timeStamp = new Timestamp(date.getTime());
Iterator fileListIterator = fileList.iterator();
String zipFileURL = "";
try {
String ZIP_LOC = contextRootPath + "WEB-INF" + SEP + "TempZipFiles" + SEP;
BufferedInputStream origin = null;
zipFileURL = ZIP_LOC
+ "FITS." + timeStamp.toString().replaceAll(":", ".").replaceAll(" ", ".") + ".zip";
FileOutputStream dest = new FileOutputStream(ZIP_LOC
+ "FITS." + timeStamp.toString().replaceAll(":", ".").replaceAll(" ", ".") + ".zip");
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(
dest));
// out.setMethod(ZipOutputStream.DEFLATED);
byte data[] = new byte[BUFFER];
while(fileListIterator.hasNext()) {
String fileName = (String) fileListIterator.next();
System.out.println("Adding: " + fileName);
FileInputStream fi = new FileInputStream(fileName);
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(fileName);
out.putNextEntry(entry);
int count;
while ((count = origin.read(data, 0, BUFFER)) != -1) {
out.write(data, 0, count);
}
origin.close();
}
out.close();
} catch (Exception e) {
e.printStackTrace();
}
return zipFileURL;
}
A URL cannot access any files (directly) under WEB-INF. I'd suggest using a servlet to return the file from whatever location it was saved to
Would also suggest saving the file outside the context of your webapp