My question is clear, in a web server request without a file name like
http://whatever.com/path_1/path_b/
when the web server response is obtained with the "welcome-file-list" (in the web.xml of Tomcat app) with the default possible pages (deafult.html, index.html, etc.).
Is there a way of knowing wich exactly file, or the file name, is server by the web server?
I need to check the file in a filter, but in the request and/or response objects doesn't seem to be available
Thanks
No you can't. the purpose of hiding the physical details of file and its access behind a web-server is to provide a streamlined and secured access to the resources of a server.
Well, I've tried this solution, but I don't know if it is too much "resource-consuming".
In my servlet filter, check the welcome file list of files for the first existing one.
String fullURL = httpRequest.getRequestURL().toString();
String realPath = this.servletContext.getRealPath(filePath);
// if path is not a filename
if (fullURL.endsWith("/")){
// welcome file list
for (String wf : (String[])servletContext.getAttribute("org.apache.catalina.WELCOME_FILES")) {
// first encountered - first used
if ((new File(realPath+"\\"+wf)).exists()) {
// el primero que exista serĂ¡ el utilizado
fullURL += wf;
realPath += "\\"+wf;
break;
}
}
}
Related
It's a standard (possibly trivial) situation, but I cannot find detailed information on the topic.
Suppose we have a web application A (http://my-webapp) and a file server F (http://file-server).
For clarity:
A is run on Jetty 9;
F is visible for Jetty server, and NOT visible for a client.
What is the best practice to show in A a picture stored on F?
Suppose client makes a request http://my-webapp/pictures/123, where 123 - any id, which somehow points to a picture stored as http://file-server/storage/xxx123.jpg, and expects to see the picture in the browser.
"Best practice" covers a lot of ground.
For load and performance reasons, it's a good idea to use a web server (like NGINX or Apache) rather than an application server to serve static assets. Most production environments have this set up, using a web server to proxy requests to the application server when necessary.
If you have such a setup, you could map the images drive on F as a drive on your web server, and use a .htaccess rewrite rule to deal with file name logic.
If that's not possible because the file name logic cannot be captured in a regex or similar, you could write a servlet on A to issue a redirect to a "regular" web location. Something along the lines of:
client requests http://my-webapp/pictures/123
servlet translates /pictures/123 to http://my-webapp/static_pictures/xxx123
servlet issues 302 redirect to http://my-webapp/static_pictures/xxx123
client follows redirect
I strongly recommend you do not use a servlet to read the file from F and then stream that to the browser; this consumes large amounts of memory on your application server, and may slow down or even fail depending on your local network conditions. Your application's performance will almost certainly deteriorate very quickly under load.
I propose the following solution as a minimal example that could be a good starting point.
Redirection by .htaccess seems to be doing similar things on the low level.
Actually the problem is supposed to be solved by web application server itself without intervention of external tools (like Apache httpd or Nginx).
1. Declare servlet in web.xml
<servlet>
<servlet-name>pictures</servlet-name>
<servlet-class>myapplication.servlets.HiddenFileServlet </servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pictures</servlet-name>
<url-pattern>/pictures/*</url-pattern>
</servlet-mapping>
2. Implement the servlet
public class HiddenFileServlet extends HttpServlet
{
#Inject
MyService myService; // a service for paths finding on http://file-server
#Override
protected void doGet( HttpServletRequest req, HttpServletResponse resp ) throws IOException
{
String requestedUri = req.getRequestURI();
String fileName = myService.getFileName( requestedUri );
String mime = getServletContext().getMimeType( fileName );
if ( mime == null )
{
resp.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
return;
}
else
{
resp.setContentType( mime );
}
// path on http://file-server/storage
URL fileFullPath = myService.getInternalPath( requestedUri );
URL file = new URL( fileFullPath );
try (
InputStream in = file.openStream();
OutputStream out = resp.getOutputStream()
)
{
org.apache.commons.compress.utils.IOUtils.copy( in, out );
}
}
}
How can I determine if an url is referring to a file or directory. the link http://example.com/test.txt should return that it is a file an http://example.com/dir/ is a directory
I know you can do this with the Uri class but this objects IsFile function only works with the file:/// scheme. And I am working with the http:// scheme. Any idea's?
Thanks
I'm not sure why this question was left unanswered/neglected for a long time. I faced the same situation in server-side java (reckon it would be similar for Android flavour). The only input information is a URL to the resource and we need to tell if the resource is a directory or file. So here's my solution.
if ("file".equals(resourceUrl.getProtocol())
&& new File(resourceUrl.toURI()).isDirectory()) {
// it's a directory
}
Hope this helps the next reader.
Note: please see #awwsmm comment. It was my assumption when provided the answer above. Basically, it doesn't make sense to test if a remote resource is a directory or anything. It is totally up to the site to decide what to return for each request.
It won't work because protocol would be http:// not file://.
class TestURL{
public static boolean isDirectory(URL resourceUrl){
if ("file".equals(resourceUrl.getProtocol())
&& new File(resourceUrl.toURI()).isDirectory()) {
true;
}
return false;
}
public static void main(String[] args){
System.out.println(TestURL.isDirectory("http://example.com/mydir/"));
}
}
I think a directory http://example.com/some/dir will redirect to http://example.com/some/dir/, a file will not.
ie one can examine the http Location field in the HEAD response:
$ curl -I http://example.com/some/dir | grep Location
Location: http://example.com/some/dir/
In my case I needed to download a file with HTTPS and there was occasions that server was misconfigured to redirect the request and thus would download only http data.
In my case I was able to "decide" whether the requested resource was file or not was inspecting "content type" / aka MIME type.
String[] allowedMimeTypes = new String[] { "application/octet-stream", "image/gif",
"text/css", "text/csv", "text/plain", "text/xml" };
URL website = new URL("https://localhost/public/" + file);
HttpsURLConnection huc = (HttpsURLConnection) website
.openConnection();
if (!Arrays.asList(allowedMimeTypes).contains(huc.getContentType())) {
throw new Exception("Not a file...");
}
When the response contained text/html;charset=utf-8 or similar I was able to determine that it was indeed not a file.
Also note that these MIME types are usually quite configurable on server side.
My problem seems a little bit weird but I'm unable to find a solution.
I have a Java servlet that has to connect via POST to a PHP file with a URL without extension.
Here is a part of the code in the Java servlet:
/**
* The POST client (for authentication and data retrieval)
* #param entity
* #return Server Response
*/
private Response postRequest(Representation entity) {
Request r = new Request();
r.setResourceRef("http://xxx.ac.at/privis/chameleoninterface");
r.setMethod(Method.POST);
r.setEntity(entity);
Response response = new Client(Protocol.HTTP).handle(r);
System.out.println("\nServer Response: " + response.getStatus() + "\n");
return response;
}
Behind the URL
http://xxx.ac.at/privis/chameleoninterface
It should connect with the PHP-file chameleoninterface.php and it should in turn open.
IMPORTANT: I'm not allowed to add .php at the end of the URL.
The code is working without any problems due to previous checks with the file extension at the end.
Is there any other possibility of solving this problem?
Thanks,
Arci
Two ways:
You can use url rewrite to map /privis/chameleoninterface to /privis/chameleoninterface.php
You can put index.php file that has all the code from chameleoninterface.php in a directory named chameleoninterface [this is the simplest way to do it]
Hey,
Maybe the title is not the best choice, but I really don't know how to better describe the problem.
The thing is when you point your browser to url that contains #
http://anydomain.com/test/elsem/1234#dogeatdog
and for some reason (ie. there is a business logic) you want to redirect to other page
http://anydomain.com/test/els/1234
the #dogeatdog will be added to new url.
I found this behavior while developing wicket app, but just now I tested it with simple pure java servlet. Can someone explain it to me?
Here is the code just in case I'm doing something wrong:
private void process(HttpServletRequest req, HttpServletResponse res)
{
res.setContentType("text/plain");
try
{
HttpSession session = req.getSession();
Object as = session.getAttribute("as");
if (as == null)
{
log.info("redirecting");
session.setAttribute("as", 1);
res.sendRedirect("/test/");
}
else
{
log.info("writing");
PrintWriter out = res.getWriter();
out.write("after redirect "+as);
out.flush();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
Hash fragments (#a_hash_fragment) never leave the browser, they are not part of HTTP request.
What the web server gets in this case is GET /test/elsem/1234, and it responds with redirect 3xx code and the new url /test/els/1234, which your browser picks and appends #dogeatdog. Makes sense now?
UPDATE: Thanks to Zack, here's a W3C document that exactly explains how this (should) work:
http://www.w3.org/Protocols/HTTP/Fragment/draft-bos-http-redirect-00.txt
From the sendRedirect Javadoc:
Sends a temporary redirect response to the client using the specified
redirect location URL. This method can accept relative URLs; the
servlet container must convert the relative URL to an absolute URL
before sending the response to the client. If the location is relative
without a leading '/' the container interprets it as relative to the
current request URI. If the location is relative with a leading '/'
the container interprets it as relative to the servlet container root.
Because of repetitive use of "relative" in the Javadoc, I suspect the new URL is using what it can from the old URL and then building from there...
In the brief amount of what I've read, forwarding should be used if possible instead of redirect.
See this for a good explanation of forward verses redirect.
See this for straight-forward examples of forwarding requests to Servlets or JSPs.
Of course, with forwarding, the original URL will remain intact so that may not be what you're looking for...
EDIT
With information from milan, I found some more information regarding URL fragments (the stuff after "#" - I didn't know that was their official name until corresponding with milan).
There's another SOF post that has some good information concerning this and possibly the best answer: URL Fragment and 302 redirects
I have "+1'd" milan for giving good direction on this...
I have abandoned my earlier quest to make the applet communicate directly with the database, even though users and webpages have said that it's possible. I am now trying to get my applet to pass information (String and boolean format) entered in textfields or indicated by checkboxes, and give this to the servlet, which then stores it appropriately in the database. I've got the applet front end - the GUI - built, and the servlet - database connection also built. The only problem is the link between the two, applet and servlet. How would one pass String data from an applet to a servlet?
Thanks,
Joseph G.
First up, you have to acknowledge that you can only communicate with the server from where your applet was downloaded from, that includes the port number, unless you want to mess around with permissions, applet signing and all that malarky. This also isn't just an Applet restriction, the same applies to Flash and JavaScript (though in the case of JavaScript there are tricks to get around it).
Using either the "getCodeBase()" or "getDocumentBase()" method on your Applet will get you a URL from which you can get the component parts required to build a new URL that will let you call a servlet.
Thus, your Applet must be being served from the same server that your servlet is hosted on.
e.g. if your Applet is in the following page:
http://www.example.com/myapplet.html
...it means you can make calls to any URL that starts with
http://www.example.com/
...relatively easily.
The following is a crude, untested, example showing how to call a Servlet. This assumes that this snippet of code is being called from within an instance of Applet.
URL codeBase = getCodeBase();
URL servletURL = new URL(codeBase.getProtocol(), codeBase.getHost(), codeBase.getPort(), "/myServlet");
// assumes protocol is http, could be https
HttpURLConnection conn = (HttpURLConnection)servletURL.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
PrintWriter out = new PrintWriter(conn.openOutputStream());
out.println("hello world");
out.close();
System.out.println(conn.getResponseCode());
Then in your servlet, you can get the text sent by overriding doPost() and reading the input stream from the request (no exception handling shown and only reads first line of input):
public void doPost(HttpServletRequest req, HttpServletResponse res) {
BufferedReader reader = req.getReader();
String line = reader.readLine();
System.out.println("servlet received text: " + line);
}
Of course, that's just one approach. You could also take your inputs and build up a query string like this (URLEncoding not shown):
String queryString = "inputa=" + view.getInputA() + "&inputb=" + view.getInputB();
and append that to your URL:
URL servletURL = new URL(codeBase.getProtocol(), codeBase.getHost(), codeBase.getPort(), "/myServlet?" + queryString);
However, it seems fairly common to build up some kind of string and stream it to the servlet instead these days.
A recommended format would be JSON as it's semi-structured, while being easy to read and there are plenty of (de)serializers around that should work in your Applet and in your servlet. This means you can have a nice object model for your data which you could share between your Applet and Servlet. Building up a query string of complex inputs can be a mind bender.
Likewise, you could actually use Java serialisation and stream binary to your Servlet which then uses Java serialisation to create the appropriate Java objects. However, if you stick to something like JSON, it'll mean your servlet is more open to re-use since Java serialisation has never been implemented outside of Java (that I am aware of).
Hm, I guess the applet and the servlet run in two separate Java processes. In that case you'll have to use some remoting technology, e.g. an http call to localhost. In fact, that is what servlets are mainly used and implemented for: Accept and process http requests.