Jersey/Grizzly POST fails for large URI - java

Relevant: this and that
I'm developing a POST webservice (jersey/grizzly, for research purposes only) which should be able to handle large URIs. But if a URI exceeds above 8000 characters I get a 400 Bad Request Exception with no further explanation. I debugged/tracked it down to the grizzly maxHttpHeaderSize attribute. I tried to set this attribute but failed. Here is how I start the server and the request:
GrizzlyServerFactory.createHttpServer(BASE_URI, new PackagesResourceConfig("org.test"));
JSONObject s = new JSONObject(webResource.queryParams(queryParams).post(String.class));
Thank you for your help!
Cheers,
Daniel

The problem is that GrizzlyServerFactory returns already started HttpServer, that's why you can not reconfigure it on the fly.
Here [1] I've created a copy of the GrizzlyServerFactory , which doesn't start HttpServer, so the code like:
HttpServer httpServer = GrizzlyServerFactory.createHttpServer(BASE_URI, rc);
httpServer.getListener("grizzly").setMaxHttpHeaderSize(Integer.MAX_VALUE);
// don't forget to start the server explicitly
httpServer.start();
Hope that will help.
[1] https://github.com/oleksiys/samples/blob/master/jersey-grizzly2-ext/src/main/java/com/sun/jersey/api/container/grizzly2/ext/GrizzlyServerFactory.java

Have You tried with shorter URI? Probably Your server is unable to handle so long URI.
You can read more about it here: What is the maximum length of a URL in different browsers?
Why don't You put request data from URL to request body?

You can create the grizzly http server without starting it now
public static HttpServer createHttpServer(
final URI uri,
final ResourceConfig configuration,
final boolean start)
So basically you create it normally passing false as 3rd argument.
When you get the HttpServer object back you can httpServer.getListener("grizzly").setMaxHttpHeaderSize(Integer.MAX_VALUE);
As was said before and don't forget to start the server manually.

Related

Jetty on Heroku: how to tell in code if https was used

I have some servlets running in Jetty, deployed on Heroku, handling POST requests.
Some, but not all, POST requests MUST come over https. Whether or not a request should be forced to be on https depends on the http body of the POST request.
I need to figure out, from inside the servlet, whether the incoming request used https (SSL) or not, so that I can send the appropriate response. However, nothing I have tried seems to work.
I tried the obvious HttpServletRequest.getProtocol() but that apparently returns the same constant whether the protocol was http or https.
I tried HttpServletRequest.isSecure() however that is returning false even though my test request was sent to a url starting with https://
When I call HttpUtils.getRequestURL( HttpServletRequest ).toString(); I get an apparrently reconstructed url that starts with "http://" even though my test request was sent to a url starting with "https://"
According to the post "Enforce HTTPS with Embedded Jetty on Heroku" heroku has some load balancers, and I should get the value of the "x-forwarded-proto" header. That header is blank.
FYI I am using the default SSL endpoint provided by the heroku api -- I am not using their SSL Endpoint extension, because this url is not being loaded in a browser (so I don't need a custom domain in the url).
Can anyone tell me how to tell if HTTPS was used in the incoming request?
I know nothing about Heroku, but if you're programmatically configuring Jetty (as opposed to using the XML configuration), you likely need to add the SecureRequestCustomizer to your HttpConfiguration. It sets the secure flag on the requests, as well as setting the scheme to HTTPS. You can find examples here, but briefly:
final HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setSecurePort(httpsPort);
final ServerConnector httpConnector = new ServerConnector(server,
new HttpConnectionFactory(httpConfig));
httpConnector.setPort(httpPort);
server.addConnector(httpConnector);
final HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
httpsConfig.addCustomizer(new SecureRequestCustomizer()); // !!!
final HttpConnectionFactory httpsFactory = new HttpConnectionFactory(httpsConfig);
final SslConnectionFactory sslFactory = new SslConnectionFactory(sslCtx,
httpsFactory.getProtocol());
final ServerConnector httpsConnector = new ServerConnector(server,
sslFactory, httpsFactory);
httpsConnector.setPort(httpsPort);
server.addConnector(httpsConnector);
I too found it rather surprising that this poorly documented step was necessary.

Uri not Absolute exception getting while calling Restful Webservice

The below code snippet is using to call my web service using restful API.
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
String uri= "https://127.0.0.1:8443/cas-server-webapp-3.5.0/login";
WebResource resource = client.resource(URLEncoder.encode(uri));
MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
queryParams.add("username", "suresh");
queryParams.add("password", "suresh");
resource.queryParams(queryParams);
ClientResponse response = resource.type(
"application/x-www-form-urlencoded").get(ClientResponse.class);
String en = response.getEntity(String.class);
System.out.println(en);
And getting this exception while running the above code
com.sun.jersey.api.client.ClientHandlerException: java.lang.IllegalArgumentException: URI is not absolute
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:151)
at com.sun.jersey.api.client.Client.handle(Client.java:648)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:680)
I googled many articles and did'nt get where i am doing wrong .
Side note :cas-server-webapp-3.5.0 war deployed on my machine in Apache tomacat7
An absolute URI specifies a scheme; a URI that is not absolute is said to be relative.
http://docs.oracle.com/javase/8/docs/api/java/net/URI.html
So, perhaps your URLEncoder isn't working as you're expecting (the https bit)?
URLEncoder.encode(uri)
For others who landed in this error and it's not 100% related to the OP question, please check that you are passing the value and it is not null in case of spring-boot: #Value annotation.
The problem is likely that you are calling URLEncoder.encode() on something that already is a URI.
Maybe the problem only in your IDE encoding settings. Try to set UTF-8 everywhere:
In an API Key Authorization Scenario...
You may be performing the 2nd REST call after getting an AUTH_TOKEN and ENDPOINT_URL from the first REST call.
Check your concatenation of "<ENDPOINT_URL> + <API_METHOD_URI>", you may be sending only the API_METHOD_URI.
This happened to me using the Streamsets integration platform trying to connect to Oracle's Responsys API.
For me, I was getting this error, when configuation in yaml files, which composed my URL was changed. oops,

Printing the contents of a Restlet web service request

I am implementing a Restful web service using Restlet - I have not found a way to print the content of the HTTP request. I need to check the content of the http request, to get something like this:
POST http://localhost:8080/students
<Student>
<name>Tony<name/>
<age>19<age/>
<Student/>
I am send a custom object the server resource using the following code
ClientResource c = new CLientResource(url);
c.post(student, Student.Class);
I tried to get the HTTP request also with wireshark , I did not find any http requests, I only found TCP connections.
Anybody knows how to print the content of the http request either on client or server side?
You can use the following on the client side :
clientResource.getResponseEntity().getText();
From the javadoc :
Converts the representation to a string value. Be careful when using
this method as the conversion of large content to a string fully
stored in memory can result in OutOfMemoryErrors being thrown.
By the way, HTTP requests are TCP connections.

Access URL with double slash with HttpClient

I'm doing a request on another server like this:
HttpGet req = new HttpGet("http://example.com//foo");
new DefaultHttpClient().execute(req);
However, HttpClient changes example.com//foo to example.com/foo, so the other server (which is not mine) doesn't understand the request.
How can I fix this?
A double-slash is not a legal in the path section of a URI (see RFC2396, sections 3.2, 3.4). The '//' sequence has a defined meaning in the URI, it denotes the authority component (server).
I realize this does not answer your question but the HttpClient is, in fact, behaving in accordance with the HTTP and URL standards. The server your are reading from is not. This appears to be previously reported (https://issues.apache.org/jira/browse/HTTPCLIENT-727) and discarded by the HttpClient team.
It is an illegal URL in fact.
Did you try passing an URI instead of a String?
Did you try / \ \ / ? Or the URL might be equivalent to /default.asp/, /index.html/, /./, /?/, example.com/foo/ or the like.
Otherwise you will need to hack the sources.
I also wanted to do same thing and Apache Http client don't support that.
I managed to get it done using a Netty. I wrote http client using Netty and with that I was able send request with double slash(//) in the path. I used SnoopClient as sample.

SOAP web service calls from Javascript

I'm struggling to successfully make a web service call to a SOAP web service from a web page. The web service is a Java web service that uses JAX-WS.
Here is the web method that I'm trying to call:
#WebMethod
public String sayHi(#WebParam(name="name") String name)
{
System.out.println("Hello "+name+"!");
return "Hello "+name+"!";
}
I've tried doing the web service call using the JQuery library jqSOAPClient (http://plugins.jquery.com/project/jqSOAPClient).
Here is the code that I've used:
var processResponse = function(respObj)
{
alert("Response received: "+respObj);
};
SOAPClient.Proxy = url;
var body = new SOAPObject("sayHi");
body.ns = ns;
body.appendChild(new SOAPObject("name").val("Bernhard"));
var sr = new SOAPRequest(ns+"sayHi",body);
SOAPClient.SendRequest(sr,processResponse);
No response seems to be coming back. When in jqSOAPClient.js I log the xData.responseXML data member I get 'undefined'. In the web service I see the warning
24 Mar 2011 10:49:51 AM com.sun.xml.ws.transport.http.server.WSHttpHandler handleExchange
WARNING: Cannot handle HTTP method: OPTIONS
I've also tried using a javascript library, soapclient.js (http://www.codeproject.com/kb/Ajax/JavaScriptSOAPClient.aspx). The client side code that I use here is
var processResponse = function(respObj)
{
alert("Response received: "+respObj);
};
var paramaters = new SOAPClientParameters();
paramaters.add("name","Bernhard");
SOAPClient.invoke(url,"sayHi",paramaters,true,processResponse);
I've bypassed the part in soapclient.js that fetches the WSDL, since it doesn't work
(I get an: IOException: An established connection was aborted by the software in your host machine on the web service side). The WSDL is only retrieved for the appropriate name space to use, so I've just replaced the variable ns with the actual name space.
I get exactly the same warning on the web service as before (cannot handle HTTP method: OPTIONS) and in the browser's error console I get the error "document is null". When I log the value of req.responseXML in soapclient.js I see that it is null.
Could anyone advise on what might be going wrong and what I should do to get this to work?
I found out what was going on here. It is the same scenario as in this thread: jQuery $.ajax(), $.post sending "OPTIONS" as REQUEST_METHOD in Firefox.
Basically I'm using Firefox and when one is doing a cross domain call (domain of the address of the web service is not the same as the domain of the web page) from Firefox using AJAX, Firefox first sends an OPTIONS HTTP-message (before it transmits the POST message), to determine from the web service if the call should be allowed or not. The web service must then respond to this OPTIONS message to tell if it allows the request to come through.
Now, the warning from JAX-WS ("Cannot handle HTTP method: OPTIONS") suggests that it won't handle any OPTIONS HTTP-messages. That's ok - the web service will eventually run on Glassfish.
The question now is how I can configure Glassfish to respond to the OPTIONS message.
In the thread referenced above Juha says that he uses the following code in Django:
def send_data(request):
if request.method == "OPTIONS":
response = HttpResponse()
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
response['Access-Control-Max-Age'] = 1000
response['Access-Control-Allow-Headers'] = '*'
return response
if request.method == "POST":
# ...
Access-Control-Allow-Origin gives a pattern which indicates which origins (recipient addresses) will be accepted (mine might be a bit more strict than simply allowing any origin) and Access-Control-Max-Age tells after how many seconds the client will have to request permission again.
How do I do this in Glassfish?
Have you actually tested that ws is working properly?
You can use SoapUI for inspecting request/response etc.
When you confirm that ws is working from SoapUI, inspect what is format of raw Soap message. Then try to inspect how it looks before sending with .js method, and compare them.
It might help you understand what is wrong.
Check if this helps
http://bugs.jquery.com/attachment/ticket/6029/jquery-disable-firefox3-cross-domain-magic.patch
it's marked as invalid
http://bugs.jquery.com/ticket/6029
but it might give you some hint
On the other hand, instead to override proper settings for cross-domain scripting might be better if you can create and call local page that will do request to ws and return result.
Or even better, you can create page that will receive url as param and do request to that url and just return result. That way it will be more generic and reusable.

Categories