When handling a Jetty response I want to know on which port the request originated on?
public static void main(String[] args) {
Server server = new Server();
server.setConnectors(new Connector[] {connectorUnsecure, connectorSecure});
ServletContextHandler handler = new ServletContextHandler();
handler.setContextPath("/");
handler.addServlet(MyServlet.class, "/*");
server.setHandler(handler);
server.start();
server.join();
}
public abstract class MyServlet extends HttpServlet {
#Override
protected final void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Find out on which connector port the request came from.
// (The request.getRequestURL() does not contain the port at all times.)
}
}
When using a custom Handler, I could use something like:
public class CustomHandler extends AbstractHandler {
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// baseRequest.getConnection().getConnector().getPort()
}
}
However, I don't want to use a custom handler.
Is it possible to obtain the connector and its port when using a plain HttpServlet?
Thanks!
There's 5 methods on javax.servlet.http.HttpServletRequest that might be of use for you.
.getLocalAddr() - the server address the request is being processed on (could be IPv4 or IPv6)
.getLocalPort() - the server port the request is being processed on
.getRemoteAddr() - the client address the request is being processed on (could be IPv4 or IPv6)
.getRemotePort() - the client port the request is being processed on
.getHeader("Host") - the requested HTTP Host (and port) that the client thinks its talking to. (part of the HTTP spec, and especially useful for virtual hosts)
Note: the HTTP Request Host header can also be obtained via the .getRequestURI() method.
String serverAddr = URI.create(request.getRequestURI()).getHost();
Related
I have a task to examine incoming HTTP requests and do some processing on the header and request body then store that locally.
If I understand correctly, I can do that with an apache module for Apache servers and an IIS extension for IIS. I'm not clear on what I would use for Java based application servers.
Any help/guidance would be appreciated.
If you will use a Java application server, then you should handle this in a Servlet Filter. Here's an example:
#WebFilter("/app/*")
public class LoginFilter implements Filter {
#Override
public void init(FilterConfig config) throws ServletException {
//Set init params and load any resources to be used in this class.
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
//Here you will pre and post process the request-response cycle.
//Pre process is before executing "chain.doFilter(req, res);"
//Post process is after executing "chain.doFilter(req, res);"
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
String someRequestHeader = request.getHeader("<header-you-want-or-need>");
//do what you need to do
chain.doFilter(req, res);
}
#Override
public void destroy() {
//Close/free any resources used in this class.
}
}
More info:
The Java EE 7 Tutorial. 17 Java Servlet Technology. 17.6 Filtering Requests and Responses
Maybe you could use a HttpServlet.
Also have a look at the tutorial.
I have been playing around with java servers and servlets. However one question still remains.
Lets say I write a server like this:
class server {
public static void main(String[] args){
int port = 8080;
try{
ServerSocket ss = new ServerSocket(port);
Socket s = ss.accept();
}catch(Exception e){
System.out.println("Something went wrong");
}
}
}
this will listen for httprequest on port 8080.
Now lets say I have a servlet that looks like this:
public class HelloWorld extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<HTML>");
out.println("<HEAD><TITLE>Hello World</TITLE></HEAD>");
out.println("<BODY>");
out.println("<BIG>Hello World</BIG>");
out.println("</BODY></HTML>");
}
}
I can easily use an already existing server like tomcat or glassfish to deploy this servlet. But is it possible to deploy this from the simple server here above?
No, you need a Servlet implementation or if you want to re-invent the wheel create your own. For instance Catalina is the Tomcat servlet implementation.
No. You need java implementation that handle servlet's code and return html. Basically glassfish or tomcat is a server which listens to your request, run java code at back end and return result. On superficial level, tomcat and glassfish use basic server to capture requests. However there are a lot more things to do.
In your simple server, there is nothing to handle java code written in servlet.
Your server will return text of servelet instead of running it.
not a easy way.
servlet need a java container implementation,like tomcat or glassfish。 if you think tomcat or glassfish is too heavy, can try jetty.
public class HelloHandler extends AbstractHandler
{
public void handle(String target,Request baseRequest,
HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
baseRequest.setHandled(true);
response.getWriter().println("<h1>Hello World</h1>");
}
}
public static void main(String[] args) throws Exception
{
Server server = new Server(8080);
server.setHandler(new HelloHandler());
server.start();
server.join();
}
you also can write a simple Servlet implementation by netty.
I'm using Grizzly to serve a Jersey application, while using Logback for my logging needs. Please not that there are no Servlets involved here, I fire up everything "by hand" using a piece of code like this:
final URI uri = /* this is a configuration option */
this.server = new HttpServer();
final NetworkListener nl = new NetworkListener(
"grizzly", uri.getHost(), uri.getPort());
server.addListener(nl);
final GuiceComponentProviderFactory gcpf =
new GuiceComponentProviderFactory(rc, inj);
final HttpHandler processor = ContainerFactory.createContainer(
HttpHandler.class, rc, gcpf);
this.server.getServerConfiguration().addHttpHandler(
processor, uri.getPath());
server.start();
Now I would like to use Logback's MDC feature to make the socket address of the clients visible in the log records. For this purpose I would need some place to hook up a listener to the HTTP processing which gets notified about incoming requests (where I can put the address into the MDC) and when a request is done (so I can clean up the MDC). One approach I followed is to hook up a Container*Filter instance with Jersey, which looked like this:
class MdcFilter implements
ContainerRequestFilter, ContainerResponseFilter {
#Override
public ContainerRequest filter(ContainerRequest request) {
MDC.put("http-client", "foo" /* no way to get the address here */);
return request;
}
#Override
public ContainerResponse filter(
ContainerRequest request,
ContainerResponse response) {
MDC.remove("http-client");
return response;
}
}
Unfortunately, a Jersey ContainerRequest does not provide information about the connected client (which cam as a real surprise).
I suspect a similar interface should exist with Grizzly itself, but I was unable to dig it out.
For Grizzly, the relevant API is called HttpServerProbe. Using this, it comes down to something like this:
final HttpServer server = new org.glassfish.grizzly.http.server.HttpServer();
server.addListener(new NetworkListener("grizzly", "localhost", 8080));
server.getServerConfiguration().addHttpHandler(
new StaticHttpHandler("/var/www/"), "/");
server.getServerConfiguration().getMonitoringConfig().getWebServerConfig()
.addProbes(new HttpServerProbe.Adapter() {
#Override
public void onRequestReceiveEvent(
HttpServerFilter filter,
Connection connection,
Request request) {
System.out.println(request.getRemoteAddr());
MDC.put("http-client", request.getRemoteAddr());
}
#Override
public void onRequestCompleteEvent(
HttpServerFilter filter,
Connection connection,
Response response) {
MDC.remove("http-client");
}
}
server.start();
Note that there are more events which might be relevant, like suspend, resume and cancel. These should probably be handled as well, especially if long-polling (aka Comet, aka whatnot) is used. But basically this is the place to hook into.
In your MdcFilter, try to inject the HttpServletRequest into your class and use that as you would normally to call getRemoteAddr() or any other such function as in:
class MdcFilter implements
ContainerRequestFilter, ContainerResponseFilter {
#Context
protected HttpServletRequest r;
#Override
public ContainerRequest filter(ContainerRequest request) {
MDC.put("http-client", "foo" r.getRemoteAddr());
return request;
}
#Override
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
MDC.remove("http-client");
return response;
}
}
I tested this out using a similar approach to "firing things up by hand" and it worked out for me in that case. I assume it would work for you as well.
I was reading that "With every Request to your web application, client's IP is sent too. So all you need to do is to have Filter over Requests and you can store the IP. "
If this is so,how can I do this ? I mean what is the method that can tell me the IP sent in the request ?
Create a Filter class that implements javax.servlet.Filter, and fetch the IP from ServletRequest using getRemoteAddr():
public final class ExtractIpFilter implements Filter {
private FilterConfig filterConfig = null;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String ip = request.getRemoteAddr();
// do something with the IP
}
}
If your client is behind a proxy, try using request.getHeader("x-forwarded-for") instead, though this may or may not work depending on the configuration of the proxy.
I'm calling servlets which has implemented CometProcessor interface, and whenever I try to call the servlets with get request, I'm getting the above error. May I know the reason?
public class ChatServlets
extends HttpServlet implements CometProcessor {
public void event(CometEvent event)
throws IOException, ServletException {
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
if (event.getEventType() == CometEvent.EventType.BEGIN) {
response.getWriter().println("Welcome ");
} else if (event.getEventType() == CometEvent.EventType.READ) {
response.getWriter().println("Bye");
}
}
}
From this document:
IMPORTANT NOTE: Usage of these features requires using the APR or NIO HTTP connectors. The classic java.io HTTP connector and the AJP connectors do not support them.
By default you get classic java.io HTTP connector configured in your server.xml. Have you changed it to NIO connector?