How to track the HTTP request and response time in jetty - http

I am trying to track the HTTP request and response time in Jetty. I have extended the jetty server and i am able to get the request timestamp using following snippet :
public void handle(HttpChannel connection) throws IOException,
ServletException {
super.handle(connection);
connection.getRequest().getTimeStamp();
}
I need to get the exact time of the response for the request.
How can i achieve it by extending jetty server ?
If any way of doing other than extending jetty. please let me know
Thank you

Since you seem to only be interested in the latency, do this.
The RequestLog mechanism is now to do this.
Instantiate a new RequestLogHandler and add it as the root of your server Handler tree (think nested, not collection).
Add a custom implementation of RequestLog to the RequestLogHandler
In your custom RequestLog.log(Request,Response) method, grab the Request.getTimeStamp() and work out the latency.
This approach is more durable to changes internally in Jetty, and does not require a fork Jetty + modify approach to work.

Related

Async Nonblocking Multicast with Camel

I have two query :
1. Can we have non blocking async routes in camel. I do see async with seda but then if offloads work to other thread that blocks.
2. If so can we use multicast in such routes.
Following is my multistep camel route which seems to work. But not sure if it is async or non blocking async.
from("direct:multiStep")
.to("bean:routeHandler?method=monoReturningMethod1")
.process(new UnwrapStreamProcessor())
.to("bean:routeHandler?method=monoReturningMethod2")
.process(new UnwrapStreamProcessor())
Above works and web request has response from both monoReturningMethod. In this case I want to make sure all process is non blocking.
For multicast I am experimenting with following route. Not sure where to put UnwrapStreamProcessor. I have tried to put it after end() but it does not work. Do I need a custom Processor ? Or how can I tie all Mono returns in one ?
from("direct:incoming")
.multicast()
.parallelProcessing()
.to("bean:routeHandler?method=monoReturningMethod1", "bean:routeHandler?method=monoReturningMethod2")
.end()
I am using apache `camel 3.0.1 with spring boot starter.
#Component("routeHandler")
public class RouteHandler {
Mono<Entity> monoReturningMethod1(Exchange exchange) {
//make some WebClient request which returns Mono.
}
Mono<Entity> monoReturningMethod2(Exchange exchange) {
//make some WebClient request which returns Mono.
}
}
This route handles incoming web request. How to make all route processing non blocking and async. I have tried using process(new UnwrapStreamProcessor()) as process step after monoReturningMehtod and if I do in sequence it works. But it does not work with multicast and give original message overwrite not allowed.
Any suggestions ?
PS : I am initiating my async flow like following :
producerTemplate.asyncSend("RouteName", exchange)
According to this page, all EIPs are supported by the async routing engine, but not all endpoint types (components). Some components have only limited support, i.e. they can only consume or produce asynchronous.
You can use the Threads DSL in your route to tell Camel that from the point forwards, the messages should be routed asynchronous in a new thread.

Spring MVC - log every incoming http request call with payload into database

experts, I would log every incoming http request call with payload into database.
I checked there would be 2 approaches.
use filter or interceptor.
I feel filter is so easier for me to implement.
what would be best approach for my purpose?
please kindly advise.
thank you very much!
if you have a need to do something completely generic (e.g. log all requests), then a filter is sufficient - but if the behavior depends on the target handler or you want to do something between the request handling and view rendering, then the HandlerInterceptor provides that flexibility.
But anyway, just do the way which make you feel easily and simply.
Note:
Interceptor work in spring application context
Servlet work in web context
Use Spring AOP. Use any advice according to your needs.
#Aspect
#Component
public class Test {
#Around("#annotation(mapping) ")
public Object preAuthUserPersmission(ProceedingJoinPoint joinPoint, RequestMapping mapping) throws Throwable {
Object[] parameters = joinPoint.getArgs();
// Your actions on the input parameters
return joinPoint.proceed(joinPoint.getArgs());
}
}

Where to hook up authentication in Grizzly?

I'm using a Grizzly HttpServer which has two HttpHandler instances registered:
under /api/* there is an Jersey REST - style application offering the API of the product, and
under /* there is an StaticHttpHandler which serves static HTML / JavaScript content (which, among other things, talks to the API under /api/
For authentication I'm currently securing only the API using a Jersey ContainerRequestFilter implementing HTTP Basic Auth, which looks quite similar to what is presented in another SO question.
But as requirements changed, now I'd like to require authentication for all requests hitting the server. So I'd like to move the authentication one level up, from Jersey to Grizzly. Unfortunately, I'm completely lost figuring out where I can hook up a "request filter" (or whatever it is called) in Grizzly. Can someone point me to the relevant API to accomplish this?
The easiest solution would leverage the Grizzly embedded Servlet support.
This of course would mean you'd need to do a little work to migrate your current HttpHandler logic over to Servlets - but that really shouldn't be too difficult as the HttpHandler API is very similar.
I'll give some high level points on doing this.
HttpServer server = HttpServlet.createSimpleServer(<docroot>, <host>, <port>);
// use "" for <context path> if you want the context path to be /
WebappContext ctx = new WebappContext(<logical name>, <context path>);
// do some Jersey initialization here
// Register the Servlets that were converted from HttpHandlers
ServletRegistration s1 = ctx.addServlet(<servlet name>, <Servlet instance or class name>);
s1.addMapping(<url pattern for s1>);
// Repeat for other Servlets ...
// Now for the authentication Filter ...
FilterRegistration reg = ctx.addFilter(<filter name>, <filter instance or class name>);
// Apply this filter to all requests
reg.addMapping(null, "/*");
// do any other additional initialization work ...
// "Deploy" ctx to the server.
ctx.deploy(server);
// start the server and test ...
NOTE: The dynamic registration of Servlets and Filters is based off the Servlet 3.0 API, so if you want information on how to deal with Servlet listeners, init parameters, etc., I would recommend reviewing the Servlet 3.0 javadocs.
NOTE2: The Grizzly Servlet implementation is not 100% compatible with the Servlet specification. It doesn't support standard Servlet annotations, or deployment of traditional Servlet web application archive deployment.
Lastly, there are examples of using the embedded Servlet API here
The "hookup" part can be done using a HttpServerProbe (tested with Grizzly 2.3.5):
srv.getServerConfiguration().getMonitoringConfig().getWebServerConfig()
.addProbes(new HttpServerProbe.Adapter() {
#Override
public void onRequestReceiveEvent(HttpServerFilter filter,
Connection connection, Request request) {
...
}
#Override
public void onRequestCompleteEvent(HttpServerFilter filter,
Connection connection, Response response) {
}
});
For the "linking" to the ContainerRequestFilter you might want to have a look at my question:
UnsupportedOperationException getUserPrincipal

SignalR wth gzip compression

Having some problem developing a SignalR client for a Hub hosted in asp.net website with gzip compression enabled. Since we are using IIS compression, the response from SignalR also gets compressed, but, the client does not understand the response and we get a Json parsing error on the client side.
SignalR internally uses HttpWebRequest to make make http requests and HttpWebRequest can be configured to automatically decompress the response using AutomaticDecompression property. So, if somehow I can get hold of the HttpWebRequest object used by SignalR to make the request, I should be able to set the enable automatic decompression.
I thought I should be able to get access to the HttpWebRequest by providing HubConnection.Start with my custom implementation of IHttpClient, IHttpClient.GetAsync takes a prepareRequest action which I thought should give me access to the HttpWebRequest, but, HttpHelper.GetAsync wraps the HttpWebRequest with HttpWebRequestWrapper before passing to prepareRequest and HttpWebRequestWrapper does not provide access to HttpWebRequest.
HttpHelper class is internal so can't use it as well, so, I am not exactly sure how to enable automatic decompression with SignalR.
I can expose the HttpWebRequest in HttpWebRequestWrapper, but, would prefer a simpler solution if one exists. Any thougths?
I am using SignalR version 0.5.1.10822
My auto decompression HttpClient:
public class HttpClientWithAutoDecompression : IHttpClient
{
readonly DefaultHttpClient _httpClient = new DefaultHttpClient();
private readonly DecompressionMethods _decompressionMethods;
public HttpClientWithAutoDecompression(DecompressionMethods decompressionMethods)
{
_decompressionMethods = decompressionMethods;
}
public Task<IResponse> GetAsync(string url, Action<IRequest> prepareRequest)
{
Task<IResponse> task = _httpClient.GetAsync(url,
request =>
{
[ERROR: request is actually HttpRequestWrapper and
does not expose HttpWebRequest]** ]
var httpWebRequest = (HttpWebRequest) request;
httpWebRequest.AutomaticDecompression = _decompressionMethods;
prepareRequest(request);
});
return task.ContinueWith(response =>
{
Log.Debug(this, "Response: {0}", response.Result.ReadAsString());
return response.Result;
});
}
....
}
To the best of my knowledge GZip encoding and streaming do not mix. In the case of the forever frame transport the client wouldn't be able to decode any on the streaming content until the entire response, or at least a significant block of data, is received (due to the way the data is decoded). In the case of web sockets there is not support for encoding of any kind at this time, although there is apparently an extension to the specification for per message encoding being worked on.
That said, if you wanted to attempt to provide support for the LongPolling transport, the only way I can see this being possible is to provide your own SignalR IHttpClient implementation. You can see right now that the DefaultHttpClient class uses HttpHelper::GetAsync which creates the HttpWebRequest internally and you can never get your hands on that because you only have access to the IRequest which is HttpWebRequestWrapper at that point.
By creating your own IHttpClient you can take over the initial instantiation of the HttpWebRequest, set the AutomaticDecompression and then wrap that up yourself with the HttpWebRequestWrapper.

jetty webSocket : java.lang.IllegalStateException: Committed

I am using Jetty Websockets in my Web Application .
When i am trying to redirect to a logoff jsp , i am getting this error
oejs.ServletHandler:/test
java.lang.IllegalStateException: Committed
at org.eclipse.jetty.server.Response.resetBuffer(Response.java:1069)
at javax.servlet.ServletResponseWrapper.resetBuffer(ServletResponseWrapper.java:232)
at org.eclipse.jetty.http.gzip.GzipResponseWrapper.resetBuffer(GzipResponseWrapper.java:273)
at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:199)
at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:98)
This is the way i am redirecting
RequestDispatcher rd = request.getRequestDispatcher("logoff.jsp");
rd.forward(request, response);
This error is not reproduceble , but could you please tell me when it may occur??
java.lang.IllegalStateException: Committed
I thought I'd provide a more general explanation of what the exception means. First off, Jetty should be ashamed by the exception message. It provides little to no help to the developer unless they already know what it actually means. The exception should be something like:
java.lang.IllegalStateException: Response headers have already been sent. Are you trying to return a result after sending content?
Typically this exception happens when you go and call:
resp.getOutputStream(); // or getWriter()
and then later try to do a redirect or something:
resp.sendRedirect("/someOtherUrl");
// or
return new ModelAndView("redirect:/someOtherUrl");
Once you get the OutputStream or Writer so you can write body bytes to the client, Jetty has to commit the response and send the HTTP 200 and associated headers, so it can start returning the body bytes. Once that happens, you then can't do a redirect nor make any other changes to the status code or headers.
The proper thing to do, once you return body bytes, is to return null from the handler instead of a ModelAndView(...) or just change the handler to return void.
You also get this exception when you call the super method in your own method implementation.
Example:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
super.doPost(req, resp); // <-- THIS IS THE PROBLEM
resp.sendRedirect("/someOtherUrl");
}
This occurs because your response has already processed a redirect request, you are trying to modify a committed response.
There are two general ways to solve this:
find out where the first redirect is and try to modify the logic to prevent the "two redirect" scenario from happening.
put a "return" after each of your redirect (personally I recommend this solution).
The reason on my side is using jetty with wrong url:
right: http://localhost:8080
wrong: http://localhost:8080/test
Consider you are running javax.servlet.Filter on Jetty server, and you face the same exception. The issue here can be described exactly as Gray's description (Thanks Gray). Typically this exception happens when you go and call:
resp.getOutputStream(); // or getWriter()
then
chain.doFilter(request, response);
If you called resp.getOutputStream();, make sure you are not using chain.doFilter(request, response); on the same request.
In my case I had some repository in my #Service and I declared it as RepositoryFoo repositoryFoo;, in the beginning of my class
I forgot to add #Autowired or even make it private, so it compiled fine and then when running I had this java.lang.IllegalStateException: Committed ... I wasted some time before figuring out the reason !

Resources