Static content in my C:\ drive being aliased away by jetty ResourceHandler - jetty

I am using emmedded jetty in my java project. For some reason, the path I am sending into resourceHandler is c:\ (lower case) and it is being aliased to C:\ (upper case). Because of this my static content is not being served.
I read some docs that indicated that jetty compares the absolute path and canonical path to detect aliases. In the log I see:
[qtp15485575-19] INFO org.eclipse.jetty.server.handler.ResourceHandler - file:/c:/filepath aliased to file:/C:/filepath
Anyone have any ideas on how to resolve?
Update: logged bug to eclipse for this: https://bugs.eclipse.org/bugs/show_bug.cgi?id=471526
Here's their response:
"it is indeed very annoying, but is forced on us by the poor security model of the servlet spec.
IF the spec had said that all URIs were denied unless explicitly allowed, we would not need to check for aliases. But instead it has a model where it allows all URIs except those that are specifically denied.
Thus if a security constraint is put on /secretfile.txt we have to make sure that any aliases of that file are also constrained... and do so in an FS independent way. That means on various operating systems we might need to block:
/sEcRetFile.TXT
/secretfile.txt
/SECRE~01.TXT
/secretfile.txt##0
etc. etc. etc.
So to be sure, we have implemented the alias system.
Normally we don't get problems with c: and C: because that should be normalized when configuring the context, so the correct one should be used. But filesystems do change their behaviour between releases, so it can be very annoying.
I think this is handled somewhat better in jetty 9.3 where we can use the Path classes to better examine parts of the path."
So probably the best bet is to use Jetty 9 if you can and use Joakin's fix if it is still an issue.

Give your ResourceHandler a full, absolute, and real path.
package jetty.resource;
import java.io.File;
import java.nio.file.Path;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.util.resource.PathResource;
public class ResourceHandlerFromFSExample
{
public static void main(String[] args) throws Exception
{
Server server = new Server(8080);
Path webRootPath = new File("src/test/webroot").toPath().toRealPath();
System.err.println("WebRoot is " + webRootPath);
ResourceHandler handler = new ResourceHandler();
handler.setBaseResource(new PathResource(webRootPath));
handler.setDirectoriesListed(true);
server.setHandler(handler);
server.start();
server.join();
}
}
And btw, DefaultServlet is still a better choice for static file serving.

Related

Configure Javalin (Jetty) max request size (414 URI too long)

How do you configure Javalin to change the max request size, specifically the config to increase the max size of the query parameters on the request (avoiding 414 URI too long)?
I get 414 URI is too long when I exceed what looks like a default size of 8KB so would like to configure my Javalin server to increase that slightly.
I think it uses Jetty under the hood which has a HttpConfiguration.requestHeaderSize variable that may control it. Or there's a HttpParser._maxHeaderBytes which is checked before throwing the URI_TOO_LONG_414 exception.
I can't see how it can all be wired up...
Bearing in mind all the advice and warnings listed here... Assuming you have Javalin defined as follows in your main method:
Javalin app = Javalin.create(config -> {
config.jetty.server(MyJetty::create);
}).start();
Then you can create MyJetty to customize this and any other settings you may want to use.
A very basic example:
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
public class MyJetty {
public static Server create() {
Server server = new Server();
HttpConfiguration httpConfiguration = new HttpConfiguration();
httpConfiguration.setRequestHeaderSize(8192); // use your value here
HttpConnectionFactory httpCF = new HttpConnectionFactory(httpConfiguration);
ServerConnector httpConnector = new ServerConnector(server, httpCF);
httpConnector.setPort(8080); // use your port here
server.addConnector(httpConnector);
return server;
}
}
This only sets up a simple insecure HTTP connection - but shows one way to change the HttpConfiguration value for Javalin. You can use the same approach for other connectors you may want to configure, including ones using SSL/TLS.
I am assuming the latest version of Javalin (version 5) since there were some syntax changes from Javalin 4 to 5 - and also the version of Jetty changed from 9 to 11.
If you are using Javalin 4, the config syntax is a bit different:
config.server(MyJetty::create);
But I don't think the Jetty code changes (for this specific setting, at least).
Only change the HttpConfiguration, it will inform the HttpParser.
You should be leery of doing this because ...
many browsers do not support that large of a query.
3rd party internet security software on laptops will reject that exchange.
you open yourself to various old school DoS (Denial of Service) attacks related to hashmap/hashcode abuse. (to minimize this issue, use Java 17 or newer)
If you move to HTTP/2 (or HTTP/3) many servers will reject the extension of the maximum request headers (at the HTTP level) that would be needed to support this massive request path.
Also, depending on what technology Javalin is using, you might need to also increase the ContextHandler maxFormContentSize and/or maxFormKeys.
If you have reached this need, it screams of abuse of the HTTP spec, you should investigate moving to a traditional HTTP POST with Content-Type: application/x-www-form-urlencoded instead.

Using a HTTP Module on a Virtual Directory in IIS

I have a default website in my IIS where I have created one virtual directory "wsdls".
I would want to gather statistics on how many requests are triggered to my virtual directory. This would need a request interception at web server level and gather statistics. "HTTPModule" was one of the many solutions I have considered which is suitable for such scenario. Hence I have started building one.
For testing purpose, I wanted to create a HTTP Module and apply it on a particular extension files (say *.wsdl) and on every GET request of any .wsdl files in this virtual directory, I will want to redirect the application to "www.google.com". This would demonstrate a good example of how HTTP Module can be used and deployed on IIS.
HTTPModule which is written using Visual Studio is shown below,
namespace Handler.App_Code
{
public class HelloWorldModule : IHttpModule
{
public HelloWorldModule(){
}
public String ModuleName{
get { return "HelloWorldModule"; }
}
// In the Init function, register for HttpApplication
// events by adding your handlers.
public void Init(HttpApplication application){
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
application.EndRequest +=
(new EventHandler(this.Application_EndRequest));
}
private void Application_BeginRequest(Object source,
EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Redirect("www.google.com");
}
private void Application_EndRequest(Object source, EventArgs e)
{
//Nothing to be done here
}
public void Dispose() { }
}
}
Now I have done a build of this project for x64 version and I am able to browser successfully the "dll" file. Now I have to register this dll in IIS and whenever I try to access the *.wsdl files, the requests automatically divert to "www.google.com". Here is the next step I have done,
Then I have enabled the Handler mappings as shown below,
I am assuming that is it!! Nothing more to be done. I should be able to intercept the requests for all HTTP requests which are of the form "*.wsdl". This means whenever I access any wsdl from the server, control should be going back to google(Because of the logic written in begin request ). But unfortunately, I failed in achieving it. What can be done here?
One thing I noticed is that when you are trying to redirect to an external URL use
http://
So change
context.Response.Redirect("www.google.com");
to
context.Response.Redirect("http://www.google.com", true);
I could solve the problem what I am facing and below are the observations which were missing in my understanding and which helped me in solving my problem:
Locating proper web.config file :
Every website in IIS will be having a web.config file to have control over the application.
Since I am working with "Default Website", this refers to the directory "C:\\inetpub\\wwwroot"
There will be a "web.config" file which would be present in this director. Please create it if not already present.
Modifying web.config :
Once you have identified the file which needs to be modified, just add necessary module configuration to web.config
In this case, we would want to add a Module to the default website, the probably setting would be shown below,
Adding contents to bin directory :
Now if you try to run the application, the IIS would not find any dll or executable to run and hence we would need to keep the executables at a particular location.
Create a director if not already present with the name "bin" at the root of the directory and place all the dlls which you would want this website to execute. Sample shown below,
General Points to be considered:
Proper access must be given for the folder which consists of dll.
It is ideally not suggested to modify the entire website. It would be ideal if one works only on their web application.
If web.config is not found, we can create one.
If bin is not present in the web root directory, we can create one.

How do I subclass/override Ember.Logger?

I am implementing remote logging ability in my Ember app, where I want to push everything that gets sent to the log console to a remote logging service (e.g. Loggly).
I believe that what I need to do is override Ember.Logger's methods to redirect log output to the remote logging service, but I can't figure out how to do that.
The documentation for Ember.Logger simply states:
Override this to provide more robust logging functionality.
How do I "override this"? I've tried doing Ember.Logger.reopenClass() and it complains with Ember.Logger.reopenClass is not a function.
Where would I do this? In an initializer? In a service? Other?
Ember.Logger is not an Ember class. It's just an object with some methods on it.
You can override it by something like
Ember.Logger.log = function(...
You can put this wherever you want. I might put it at the top of app.js.
Expanding upon and updating #user663031 response...
As of Nov 2017, the status of Ember.Logger is up in the air. It was not included in Ember's module API, and there isn't yet an RFC for the future.
It is possible use a debug utility directly, e.g. ember-debug-logger, and extend those prototypes separate from Ember.Logger.
However, I opted to overwrite Ember.Logger directly because it allows me to include any logging tool that I like (as opposed to debug util) without having to modify the log statements scattered throughout the code.
As I use bunyan on the backend, opted to log with browser-bunyan, which incidentally has the same info, warn, error as Ember.Logger.
YMMV, but this is the minimal example that worked for me...
// app/app.js
import LOG from './logger-bunyan';
if (config.APP.LOG_BUNYAN) {
Ember.Logger = LOG;
}
// app/logger-bunyan.js
import bunyan from 'npm:browser-bunyan';
const LOG = bunyan.createLogger({
name: 'emberApplication',
});
export default LOG;
// config/environment.js
if (environment === 'development') {
ENV.APP.LOG_BUNYAN = true;
}
// app/component/WhereIWantToLog.js
Logger.warn('bunyan logged warning message')

Redirecting root context path or binding it to a servlet or mapping it with a welcome-file

I am using Jetty-9 in embedded mode and need only one web application. Consequently I would like the root URL to go to the homepage of that application, i.e. something like
http://localhost:4444/
should end up in a servlet. I start out with:
ServletContextHandler scContext =
new ServletContextHandler(ServletContextHandler.SESSIONS);
scContext.setContextPath("/");
None of the following worked, neither
scContext.addServlet(ListsServlet.class, "/");
nor
scContext.setWelcomeFiles(new String[]{"/lists})
where /lists is mapped to the ListsServlet servlet. All I get is a 403 (Forbidden).
I do not use the DefaultServlet, which seems to handle welcome files. But since the ServletContextHandler has setWelcomeFiles I expected it to contain the logic to use them.
Any ideas?
For the 403 Forbidden error, you have some security setup that is not allowing you to access the handlers/servlets.
Eliminate that security (for now), verify that the rest is working, then add security a bit later to lock down specifics.
If you want to see some the suggestions below at work, consider looking at the code example in the answer from another stackoverflow: How to correctly support html5 <video> sources with jetty.
Welcome files are appended to the incoming request path if there is nothing present at that location. For example requesting a directory and then a welcome-file of 'index.html' is appended to the request path.
While this would work ...
scContext.setWelcomeFiles(new String[]{"lists"})
// Add Default Servlet (must be named "default")
ServletHolder holderDefault = new ServletHolder("default",DefaultServlet.class);
holderDefault.setInitParameter("resourceBase",baseDir.getAbsolutePath());
holderDefault.setInitParameter("dirAllowed","true");
holderDefault.setInitParameter("welcomeServlets","true");
holderDefault.setInitParameter("redirectWelcome","true");
scContext.addServlet(holderDefault,"/");
It's likely not what you are aiming for, as you said the root path only.
The above would also make changes to requests like /foo/ to /foo/lists
Instead, it might make more sense to use a Rewrite rule + handler instead of the welcome-files approach.
RewriteHandler rewrite = new RewriteHandler();
rewrite.setHandler(scContext);
RewritePatternRule rootRule = new RewritePatternRule();
rootRule.setPattern("/");
rootRule.setReplacement("/list");
rootRule.setTerminating(true);
rewrite.addRule(rootRule);
server.setHandler(rewrite);
This RewritePatternRule simply changes any request path / to /list and then forwards that request to the wrapped ssContext (if you want to see the /list on the browser, change it to a RedirectPatternRule instead.

why does reverse() prepend a server path?

I have several instances of my project running on my server, like so:
http://0.0.0.0/one
http://0.0.0.0/two
I also have an activation view that is accessible via:
http://0.0.0.0/one/activate/u/1/c/123
When I do reverse() on this view from django shell, the url given to me as:
/activate/u/1/c/123
So it does not include the /one server path. However, when I use reverse() to look up the path of the page to send in an email somewhere else in the project, reverse() seems to return the full server path + the view path, like so:
/one/activate/u/1/c/123
Does anyone have any idea of why this is happening?
reverse() is supposed to include this server path, so that you can just use it in a link and it'll work without having to change anything else in your code. But manage.py shell doesn't set the appropriate path prefix; that code happens in the wsgi/etc handler. This is Django bug #16734 (which I incidentally reported :p).
You can work around this by calling django.core.management.base.set_script_prefix manually, presumably in your settings.py. For example:
# when running through wsgi, this will get overriden
# but it's needed for manage.py
from django.core.urlresolvers import set_script_prefix
set_script_prefix('/one/')