HttpServerRequest: request is handled several times - java

I wrote the following code:
public static void handleRequest(HttpServerRequest request, Vertx vertx) throws FileNotFoundException {
if (request.method() == HttpMethod.GET) {
if (request.path().equals("/healthcheck")) {
returnResponse(request, "I'm alive!!!\n", true);
System.out.println("OK");
return;
}
...
}
returnResponse(request, "Not Valid Request", false);
System.out.println("This request cannot be handled");
}
The weird part is that once I get a GET request with path "/healthcheck", I get in console both:
OK
and
This request cannot be handled
I'd expect to get only "OK", and then the method has to return.
Do you know how to make it happen?

You may be getting more than one request and one of them is not a get request. Can you monitor the server by inserting Log Statements

I finally found out that my browser does send two requests.
The first request is the GET localhost:8080/healthcheck and the second one is GET localhost:8080/favicon.
GET localhost:8080/favicon doesn't satisfy the condition, and the code prints "This request cannot be handled".

You are trying to handle a Preflighted request.
According to MDN
Preflighted requests unlike simple requests (discussed above),
"preflighted" requests first send an HTTP OPTIONS request header to
the resource on the other domain, in order to determine whether the
actual request is safe to send. Cross-site requests are preflighted
like this since they may have implications to user data
try this instead
public static void handleRequest(HttpServerRequest request, Vertx vertx) throws FileNotFoundException {
if(request.method() == HttpMethod.OPTIONS) {
return;
}
if (request.method() == HttpMethod.GET) {
if (request.path().equals("/healthcheck")) {
returnResponse(request, "I'm alive!!!\n", true);
System.out.println("OK");
return;
}
...
}
returnResponse(request, "Not Valid Request", false);
System.out.println("This request cannot be handled");
}

Related

Unable to respond to HEAD requests in Java

I am writing a personal web server.
When I send the GET request to the system, the system responds well.
But when I send the HEAD request, I get the following problems:
sun.net.httpserver.ExchangeImpl sendResponseHeaders
WARNING: sendResponseHeaders: being invoked with a content length for a HEAD
request java.io.IOException: response headers not sent yet at
jdk.httpserver/sun.net.httpserver.PlaceholderOutputStream.checkWrap(ExchangeImpl.java:448)
at
jdk.httpserver/sun.net.httpserver.PlaceholderOutputStream.write(ExchangeImpl.java:458)
at
ir.utux.service.HandleHttpResponse.writeResponse(HandleHttpResponse.java:32)
This is the code I wrote to manage the response, to simplify HEAD and GET together.
public void writeResponse(SettingModal settingModal) {
try {
switch (requestHeader.getMethod()) {
case HEAD,GET -> {
response.getResponseHeaders().set("Server", "utux HttpServer");
response.getResponseHeaders().set("Connection", "close");
response.getResponseHeaders().set("Transfer-encoding", "chunked");
response.getResponseHeaders().set("Content-Type", ContentType.HTML);
response.sendResponseHeaders(HttpStatus.SC_OK, "".length());
response.getResponseBody().write("".getBytes(StandardCharsets.UTF_8));
response.getResponseBody().flush();
response.getResponseBody().close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
I found the problem
BODY should not be sent in response to HEAD requests.

httpservelet response not returning sendError status code

I am trying to determine why a webserver response that initially throws an exception in processing; then returns a 200 OK client side. The details are as follows:
a request is sent to the webserver from the web application and if an error occurs an exception is caught and the relevant code &/or message is returned as follows:
public void dispatchRequest(HttpServletRequest req, HttpServletResponse
res)
{
if (method.equalsIgnoreCase("get")) {
doGet(req, res);
} else {
res.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
return;
}
}
void doGet(HttpServletRequest request, HttpServletResponse response)
throws
IOException,
HTTPServerException {
handleGetClient(request, response);
}
#SuppressWarnings("unchecked")
private void handleGetClient(HttpServletRequest request,
HttpServletResponse
response)
throws IOException, HTTPServerException {
...
} catch (IOException e) {
logger("I/O Error during playback with parameters (additional
parameters logged) {0}: {1}",traceParams,e.toString());
logger(Level.FINER, "I/O Error during playback with parameters {0}:
{1}", parameters, e.getMessage());
logger(Level.FINER, "I/O Error during playback with parameters {0}:
{1}", parameters, e);
sendError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
...
}
protected void sendError(HttpServletResponse response, int errCode) {
response.setContentType("text/plain");
try {
response.sendError(errCode,"ERROR");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
The handleGetClient method handles the process and in the event of an error throws exceptions which are caught. The method then uses the sendError method to set the error code returned and when log debugging I could see that this was set to in this specific error (500). But once the call returns to the dispatchRequest method the httpservletResponse status is actually (200). I cannot see where this happening and why. Initially I thought I could just change the method to int to return the error code but I am limited to the changes I can make on this code.
Any ideas?
You could try one of the following:
response.resetBuffer ();
response.setStatus (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.flushBuffer ();
or if you have an error page matching the 500 code in your web.xml:
response.reset ();
response.setError (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
You could also consider using an exception mapper, for any generic error, so instead of playing yourself with the error code, you could just throw an exception which would take care of the status code return.
i.e: throw new InternalServerException ("Your message");
Possibly a return statement might be in the catch block that eventually ends up in normal functioning of sending response. I am only stating a possibility. More you can do is check what is being returned after the request is processed successfully from server (either after exception handling or normal functioning).
Either your pasted code is missing a piece or the original code does not set the actual error on the response object. Somewhere is the sendError method there should be a line like:
response.setStatus(errCode);
Once you have started streaming response to the client, you can no longer change the response code, since it is returned in the first line of response and can never be changed afterwards. Same thing with response headers - once you've started streaming body content, you can't change them.
Now, servlet containers use buffering. This means that you can write some data to response and then change your mind (as #MehdiB. has indicated). But once you have overflown that buffer, the data is written to client (first status code, then headers, then body) and you can no longer change status at this point.
The probable solution here is to avoid writing body until you are sure there are no errors. If your body is long, but you can figure out its full lenght, you can add Content-Length header - in this case client will know if you don't deliver the response in whole without relying on status codes.
I remember in my practice adding servlet filters which will intercept HttpServletResponse to make sure that servlets behave nicely with regards to this constraint.

Elasticsearch Rest Client - ConnectionClosedException when calling performRequestAsync

I'm having a problem on HttpAsyncRequestExecutor.
I'm using elasticsearch Java Rest Client and I'm always getting a ConnectionClosedException (see below) when I call the performRequestAsync:
// variables (all with valid format):
// endpoint is just a List<String> with "14655/_search"
// params is just a Map<String, String> with
// "pretty", "true"
// "search_type", "query_then_fetch"
// entity is just a HttpEntity entity with the Json body request
final int numRequests = endpoints.size();
final CountDownLatch latch = new CountDownLatch(numRequests);
try (Timer.Context ctx = this.requestTimer.time()) {
for (final String endpoint : endpoints) {
// ERROR hapens here:
restClient.performRequestAsync("GET", endpoint, params, entity,
new ResponseListener() {
#Override
public void onSuccess(final Response response) {
if (response != null) {
responses.add(response);
latch.countDown();
}
}
#Override
public void onFailure(final Exception exception) {
latch.countDown();
logger.error("could not get search results for....",exception);
exception.printStackTrace();
}
});
}
}
Exception here:
org.apache.http.ConnectionClosedException: Connection closed
at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.endOfInput(HttpAsyncRequestExecutor.java:341)
at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:263)
at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:116)
at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:164)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:339)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:317)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:278)
at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:590)
at java.lang.Thread.run(Thread.java:745)
I don't know what is the real cause for the connection close. The exact same request works well in kopf and returns valid search results.
Plus, I don't call any restClient.close() or anything similar.
Any ideas where the problem might be?
Is the end of the input the cause to get a closed connection state (according to org.apache.http.nio.protocol.HttpAsyncRequestExecutor.endOfInput(conn))? If yes, what input is that?
Thanks
UPDATE:
I suspect the problem is related to Tomcat's HttpClient, because this code works correctly in an integration test (that is, returns results)... But it does not work (get the same ConnectionClosedException) when I make a REST request through a tomcat deployed "interface"
Any lights on this?
The problem was the port was wrong. For REST requests the port should be 9200 (and not 9300 like it was configured). More info on elasticsearch ports.
I wish elasticsearch could make a more explicit error log or a hint like "are you connecting with the right port?" for when one tries to access the 9300 port with anything other than the built-in clients.

Jersey CORS working for GET but not POST

My Jersey CORS request is not functioning for POST, but works for GET requests. The headers are being mapped to Jersey requests as shown in the below screenshot of a GET request to the same resource.
However, doing a POST to the below method makes me end up with XMLHttpRequest cannot load http://production.local/api/workstation. Origin http://workstation.local:81 is not allowed by Access-Control-Allow-Origin.
Here's a screenshot of network activity:
Details on failed POST request:
Here's my resource:
#Path("/workstation")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public class WorkstationResource {
#InjectParam
WorkstationService workstationService;
#POST
public WorkstationEntity save (WorkstationEntity workstationEntity) {
workstationService.save(workstationEntity);
return workstationEntity;
}
#GET
#Path("/getAllActive")
public Collection<WorkflowEntity> getActive () {
List<WorkflowEntity> workflowEntities = new ArrayList<WorkflowEntity>();
for(Workflow workflow : Production.getWorkflowList()) {
workflowEntities.add(workflow.getEntity());
}
return workflowEntities;
}
}
My CORS filter:
public class ResponseCorsFilter implements ContainerResponseFilter {
#Override
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
Response.ResponseBuilder responseBuilder = Response.fromResponse(response.getResponse());
responseBuilder
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD");
String reqHead = request.getHeaderValue("Access-Control-Request-Headers");
if(null != reqHead && !reqHead.equals(null)){
responseBuilder.header("Access-Control-Allow-Headers", reqHead);
}
response.setResponse(responseBuilder.build());
return response;
}
}
My Jersey configuration in my Main class:
//add jersey servlet support
ServletRegistration jerseyServletRegistration = ctx.addServlet("JerseyServlet", new SpringServlet());
jerseyServletRegistration.setInitParameter("com.sun.jersey.config.property.packages", "com.production.resource");
jerseyServletRegistration.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", "com.production.resource.ResponseCorsFilter");
jerseyServletRegistration.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature", Boolean.TRUE.toString());
jerseyServletRegistration.setInitParameter("com.sun.jersey.config.feature.DisableWADL", Boolean.TRUE.toString());
jerseyServletRegistration.setLoadOnStartup(1);
jerseyServletRegistration.addMapping("/api/*");
While I thought this was a CORS issue, turns out it was a Jersey issue...
org.glassfish.grizzly.servlet.ServletHandler on line 256 handles an exception...
FilterChainInvoker filterChain = getFilterChain(request);
if (filterChain != null) {
filterChain.invokeFilterChain(servletRequest, servletResponse);
} else {
servletInstance.service(servletRequest, servletResponse);
}
} catch (Throwable ex) {
LOGGER.log(Level.SEVERE, "service exception:", ex);
customizeErrorPage(response, "Internal Error", 500);
}
In my log, all I see is service exception: with nothing after it. When I debug this line, I end up seeing the error javax.servlet.ServletException: org.codehaus.jackson.map.JsonMappingException: Conflicting setter definitions for property "workflowProcess": com.production.model.entity.WorkstationEntity#setWorkflowProcess(1 params) vs com.production.model.entity.WorkstationEntity#setWorkflowProcess(1 params) which gives me something I can actually work with.
It's hard to tell and hard to debug since it's the browser that produces that error upon inspecting the response (header).
Even upon very close inspection your code looks fine and sane except that Access-Control-Allow-Headers is or may be set twice in filter(). While RFC 2616 (HTTP 1.1) Section 4.2 does basically permit it given certain conditions are met I wouldn't gamble here. You have no control over how browser X version N handles this.
Instead of setting the same header twice with different values rather append the 2nd set of values to the existing header.

GET request using GWT to retrieve XML data?

Oh hello there, fellow SO members,
I have a web service that returns XML data using a simple get request that goes like this :
http://my-service:8082/qc/getData?paramX=0169&paramY=2
the service returns raw xml in the page according to the parameters' values.
I am trying to retrieve this data from a GET request in GWT using RequestBuilder, Request, etc.
However, the response gives me empty text, a Status code of ZERO (which doesn't mean anything and isn't supposed to happen), and so on.
Here's the simplified code that doesn't work.
public class SimpleXML implements EntryPoint {
public void onModuleLoad() {
this.doGet("http://my-service:8082/qc/getData", "0169", "2");
}
public void doGet(String serviceURL, String paramX, String paramY) {
final String getUrl = serviceURL + "?paramX=" + paramX + "&idTarification=" + paramY;
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, getUrl);
try {
Request response = builder.sendRequest(null, new RequestCallback() {
#Override
public void onResponseReceived(Request request, Response response) {
response.getStatusCode(); // Gives me 0 (zero) :(
}
#Override
public void onError(Request request, Throwable exception) {
// ... doesn't matter for this example
}
});
} catch (RequestException e) {
// ... doesn't matter for this example
}
}
}
I don't get why this wouldn't work, since this is REALLY simple, I've seen tutorials and they all show me this way of doing things..
Thanks in advance
The reason is, that browsers do not allow cross-site requests with AJAX (see Same Origin Policy).
This means, that you can only call a service on the same server, same port (using the same protocol) as your HTML page. If you want to perform cross-site requests, you can use JSONP, as explained in http://code.google.com/webtoolkit/doc/latest/tutorial/Xsite.html.

Categories

Resources