Java OutputStream produces wrong directory path and characters - java

i'm using OutputStream to create a pdf file for download as follow:
byte[] infoFile = info.getBytes();
String infoName = info.getFileName();
String contentType = info.getContentType();
response.setContentType(contentType);
response.setHeader("Content-disposition", "attachment;filename=\"" + infoName + "\"");
response.setContentLength(infoFile.length);
// till now no problem, the file name is ok
OutputStream out = response.getOutputStream();
out.write(infoFile);
//here, as soon as the previous line is executed a file is generated with wrong characters
// ex. D:__Profiles__User__Downloads__infoFile.pdf
Here the file produced is something like "D:__Profiles__User__Downloads__infoFile.pdf"
while i expect the file "D:\Profiles\User\Downloads\infoFile.pdf"
What's wrong?

What's wrong?
Your expectation that the filename in a Content-disposition header should have path information.
From RFC 6266 section 4.3
Recipients MUST NOT be able to write into any location other than
one to which they are specifically entitled. To illustrate the
problem, consider the consequences of being able to overwrite
well-known system locations (such as "/etc/passwd"). One strategy
to achieve this is to never trust folder name information in the
filename parameter, for instance by stripping all but the last
path segment and only considering the actual filename (where 'path
segments' are the components of the field value delimited by the
path separator characters "" and "/").
And similarly in the Mozilla docs
The filename is always optional and must not be used blindly by the application: path information should be stripped, and conversion to the server file system rules should be done.
Basically you should only be specifying infoFile.pdf. It's up to the user which directory that file is saved in.

Related

Is there a way to get the path of a File with "/" instead of "\"?

I am making an HTTP Server in Java so that (on start) it finds all files in a directory (and it's sub-directories) and adds them to the server. But when getting the path of a file and trying to give it to HttpServer.createContext(), it throws a java.lang.IllegalArgumentException: Illegal value for path or protocol. (with the string argument, say "\folder/index.html"). To get this value, I used
file.getParent().substring(24) + "/" + file.getName()
I used substring because I had to exclude the folder the web server is in. The illegal character is the backslash. I have tried extending File to change separator and separatorChar, but that only created 2 new variables. While using String.replace() didn't seem to have any effect. Is there a different method than File.getParent or File.getPath that I can use, or is there a way to use String.replace that I am not seeing?
EDIT:
String.replace() seems to be the best answer... But I am not completely sure how to use it.
EDIT 2: For some reason the backslash isn't showing up, so I changed it.
You have to use the java System.getProperty.
Notice that, in this context, "file.separator" is a key which we are
using to get this property from current system executing the java VM.
Insteady of using a slash (/), you should choose a platform agnostic file separator, as an example it should be:
String separator = System.getProperty("file.separator");
System.out.println(separator);
// unix / , windows \
Have a look at Paths.get(...)
Try Paths.get(".") // current working directory.
Or tell it, on which path it should start:
Use System.getProperty("user.dir"), for current loged in user, home directory.
String pathStr = "/";
Path homeDir = Paths.get(System.getProperty("user.dir"))
Getting from the user directory into the data directory: homeDir.get("data")
Path dataPath = Paths.get(System.getProperty("user.dir"));
File dataFile = dataPath.toFile();
Now use operations on dataFile, to check what files and directories there are, on that location of the file system.

Java - find jar file of class (or classes directory)

I can request the URL for the jar file or classes directory where Java loaded a class from:
Class clazz = ...
URL url = clazz.getProtectionDomain().getCodeSource().getLocation();
but how to correctly convert this to a File (or Path) - especially with respect to some characters of the path escaped in URLs? I've tried this:
String fileName = URLDecoder.decode(url.getFile(), "UTF-8");
File jarFileOrClassesDir = new File(fileName);
but this causes problems if there is a + inside the path (the + is replaced with a space).
but this causes problems if there is a + inside the path (the + is replaced with a space).
This is standar behavior of URLDecoder. See more information at JavaDoc [1], plus (+) is mentioned there as well.
Solution using Paths
Using Paths#get(URI) [2] should preserve all "special" symbols and you can pass directly URI which can be retrieved directly from URL using URL#toURI() [3].
So in summary:
final var filePath = Paths.get(url.toURI()); // We can extract any information from Path e.g. fileName.
shoud work as expected.
[1] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URLDecoder.html
[2] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/Paths.html#get(java.net.URI)
[3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URL.html#toURI()

How Can I read text file in liferay?

I have tried to read a file from controller class with this code
ReadFile readFile = new ReadFile();
String text = readFile.readFile("\resources\testing.txt");
renderRequest.setAttribute("text", text);
I have fetched it from view.jsp as
<%
String content = (String)request.getAttribute("text");
%>
But I am getting file not found exception. What is the way to get file content.
In a Java string, \ starts an escape sequence and "\r" and "\t" are escaped characters. For example "\t" is a string with the tab character. If you literally need \t in a string, you'll have to escape the backslash
doSomething("\\resources\\testing.txt");
or just eliminate the hassle: Java operates well when you use the forward slash as directory separator
doSomething("/resources/testing.txt");
Note that this refers to a file in the root directory of whatever drive the current path is on, it might be C:\resources\testing.txt or D:\resources\testing.txt - unless your ReadFile implementation manipulates the path somehow (which I leave up to your judgement). You can test this independent of Liferay, just in a command line application. The exception gets thrown way before your jsp gets displayed (I've changed the tags to flag the relevance)
This is pure Java, completely independent of Liferay.
The problem is with your relative path of resources file (testing.txt), that needs to be absolute. And to create absolute path, first you would require, portletContext which you can get from request, as following:
MVC Portlet:
PortletContext portletContext = request.getPortletSession().getPortletContext();
Where request is either renderRequest / actionRequest object. While in JSF, you can get request from externalContext, as following:
JSF Portlet:
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
PortletRequest request = (PortletRequest) externalContext.getRequest();
PortletContext portletContext = request.getPortletSession().getPortletContext();
Also, as suggested by Olaf Kock, if you use \, you would require to escape it, otherwise use /. I prefer to use File.separator, as it returns slash as per OS (I think!).
String relativeFilePath = File.separator + "resources" + File.separator + "testing.txt";
Now, you can get absolute path using portletContext as,
String absoluteFilePath = portletContext.getRealPath(relativeFilePath);
And then, rest of your code goes, as:
ReadFile readFile = new ReadFile();
String text = readFile.readFile(absoluteFilePath);
renderRequest.setAttribute("text", text);
Since you're getting a FileNotFoundException, Are you sure you're pointing to the proper file route? Have you tried with the absolute path? What SO are you using? Because maybe the file separators ("\") are the cause of your problem.
HIH.
Regards.

Variable with mDBapi.putfile?

Im trying to use the dropbox api to upload a file from a list view. My code is:
File file = new File(mFileMag.getCurrentDir() + "/" + item);
inputStream = new FileInputStream(file);
Entry newEntry = mDBApi.putFile(file, inputStream, //This is my issue
file.length(), null, null);
My question is, can a variable not be used with mDBapi.putfile? Am I forced to use a hardcoded string? Trying to use my file variable results in:
"The method putFile(String, InputStream, long, String, ProgressListener) in the type DropboxAPI is not applicable for the arguments (File, FileInputStream, long, null, null)"
The docs for this call state:
public DropboxAPI.Entry putFile(java.lang.String path,
java.io.InputStream is,
...
path - the full Dropbox path where to put the file, including directories and filename.
is - the InputStream from which to upload.
So, 'path' should be a string of the desired remote path (on Dropbox), and 'is' is how the actual file content is retrieved.
It looks like you're trying to pass the file object itself as 'path', but instead you should be able to just build the the string for the desired path however you wish (which may include the original name.)

How to get the name of a TAR in a GZIP as well as the number of TARs

I was wondering if there is any Java API to get the name of the TAR file in a GZIP file as well as the number of TAR files in it. (Not sure if multiple TARs are allowed in a GZIP)
This is how I access the files/directories in a TAR file
FileInputStream fis = new FileInputStream(new File(sourceFile));
GZIPInputStream gin = new GZIPInputStream(fis);
TarInputStream tin = new TarInputStream (gin);
TarEntry tarEntry = tin.getNextEntry();
I need to check if I'm untarring the appropriate TAR file, so that's why I need the info about the name. I also need to make sure there is only one TAR file, hence I need the number of TARs.
Although GZIP files can contain some metainformation including the original filename that will not help you in reality. That filename is not valid in many cases because gzip(1) did not know the name when creating the file because it got the data not from the filesystem but via a pipe-filehandle.
Therefore the usual convention is, that the name of the gzip-file is the same as the original filname with either ".gz" appended or optionally replacing the ".tar" suffix with ".tgz".
On the good side: A GZIP file can contain only one datastream (aka. file in this case) hence only one TAR file. This of course excludes malicious cases where someone concatenates several files, calls gzips on the result and names it ".tar.gz" or ".tgz".
The answer to the second part is that is that a GZIP file only contains one file. If (hypothetically) it did contain more than one file (tar or otherwise), there would be no easy way to separate them.

Categories

Resources