Request methods on https-server - java

I don't know whether my title is correctly articulated, but I have following problem:
I have a self-written Java webserver, that handles incoming client requests. It works fine with all the request methods (GET, POST, HEAD, OPTIONS, DELETE, ...). It also works fine with sending files and stuff when I use http.
GET and POST also work when I call a page over https, but all the other request methods do not work (Nothing has changed within in the Javascript, that sends the requests to the server ... it just runs with SSL). I can't seem to find anything as to why that is the case. Do the request methods work differently when I add SSL? I thought it is merely an addition to make the communication more safe? Am I wrong?
EDIT: There are also differences between different browsers ... most don't even get to send the request, chrome got to readyState = 4 :( btw, I tested with Chrome 2.0, Firefox 3.0.11, Opera 9.63, IE7, IE8, Safari 3.2.1.
Hope someone can shed some light.

The request methods should work the same, as you expect be it HTTP or HTTPS.
It is really difficult for us to help you out because
you have a home grown web server which nobody knows but you, and
you've not included any error message from the client or logs from the server. "other request methods do not work" is just not descriptive enough. You are going to have to be much more detailed than that.
Assuming a connection issue, my I suggest you try your client on a well know web server to see if it can connect? The problem could be in the client.

The problem was in the call for the function!
The function is defined as follows:
function getHead( url, targetDiv ){
// generate the HTTPREQUESTOBJECT ... let's call it 'req'
req.open( "HEAD", url, true );
// some more magic happens with the response
}
I changed the call for the function from:
onclick="getHead( 'http://localhost/Home', 'optionsdiv' )
to:
onclick="getHead( 'localhost/Home', 'optionsdiv' )
The first call is of course only for http, not for https! so switching that made it work :)
Another method I found to work as well, was following: I add a try-catch like this:
try{
req.open( "HEAD", "https://"+url, true );
}
catch( err ){
req.open( "HEAD", "http://"+url, true );
}
Works almost perfectly on my end excpet the little browser-differences which drive me nuts!

Related

How to build HTTP DELETE request with JSON encoded body using AsyncHttpClient

I need to write a HTTP client which to communicate with Floodlight OpenFlow controller via its REST API.
For testing I did it in python, and it worked OK. But now I'm in a situation where it has to be done in Java, of which I'm admittedly still at the beginner's level. One of my apps uses AsyncHttpClient to dispatch async GET requests, and works just fine. Now as a Floodlight's REST client, it has to do POST and DELETE with JSON encoded body. My code for an async POST request works very much as expected.
But no luck with DELETE.
Somehow it doesn't write JSON string into its request body.
The code is almost identical with POST. For debugging, I don't feed an AsyncCompletionHandler instance to execute() method.
System.out.println(ofEntry.toJson()); // this returns {"name": "xyz"} as expected.
Future<Response> f = httpClient.prepareRequest(new RequestBuilder("DELETE")
.setUrl("http://" + myControllerBaseUrl + urlPathFlowPostDelete)
.setHeader("content-type", "application/json")
.setBody(ofEntry.toJson())
.build()).execute();
System.out.println(f.getStatusCode()); // returns 200.
System.out.println(f.getResponseBody()); // returns {"status" : "Error! No data posted."}.
Just to make sure, I peeped into packet dump with wireshark, and found out the server isn't lying :)
The author of the library has written an extensive amount of relevant, valuable information, but unfortunately I can't find example code specifically for building a DELETE request.
I'd very much appreciate any suggestions, pointers, and of course pinpoint solutions!
Not sure that replying to my own question is appropriate here, but I have just found a related thread at the floodlight-dev Google group.
Problem with Static Flow Pusher DELETE REST method
So this could be a problem with Floodlight REST API which requires message body for a DELETE request to identify what to be deleted, whereas AHC is simply compliant with RFC2616.
I will follow the thread at Google group, and see how it will conclude among developers.

Open an authenticated image served by django from java using Apache http client

I Am serving an authenticated image using django. The image is behind a view which require login, and in the end I have to check more things than just the authentication.
Because of a reason to complicated to explain here, I cannot use the real url to the image, but I Am serving it with a custom url leading to the authenticated view.
From java the image must be reachable, to save or display. For this part I use Apache httpclient.
In Apacahe I tried a lot of things (every example and combination of examples...) but can't seem to get it working.
For other parts of the webapp I use django-rest-framwork, which I succesfully connected to from java (and c and curl).
I use the login_reuired decorator in django, which makes the attempt to get to the url redirect to a login page first.
Trying the link and the login in a webviewer, I see the 200 code (OK) in the server console.
Trying the link with the httpclient, I get a 302 Found in the console.... (looking up 302, it means a redirect..)
this is what I do in django:
in urls.py:
url(r'^photolink/(?P<filename>.*)$', 'myapp.views.photolink',name='photolink'),
in views.py:
import mimetypes
import os
#login_required
def photolink(request, filename):
# from the filename I get the image object, for this question not interesting
# there is a good reason for this complicated way to reach a photo, but not the point here
filename_photo = some_image_object.url
base_filename=os.path.basename(filename_photo)
# than this is the real path and filename to the photo:
path_filename=os.path.join(settings.MEDIA_ROOT,'photos',mac,base_filename)
mime = mimetypes.guess_type(filename_photot)[0]
logger.debug("mimetype response = %s" % mime)
image_data = open(path_filename, 'rb').read()
return HttpResponse(image_data, mimetype=mime)
by the way, if i get this working i need another decorator to pass some other tests....
but i first need to get this thing working....
for now it's not a secured url.... plain http.
in java i tried a lot of things... using apache's httpclient 4.2.1
proxy, cookies, authentication negociation, with follow redirects... and so on...
Am I overlooking some basic thing here?...
it seems the login of the website client is not suitable for automated login...
so the problem can be in my code in django....or in the java code....
In the end the problem was, using HTTP authorization.
Which is not by default used in the login_required decorator.
adding a custom decorator that checks for HTTP authorization did the trick:
see this example: http://djangosnippets.org/snippets/243/

Write proxy/wrapper class for own service in jersey

I want to access a full rest service with basic http auth running.
However there is no way to for the javascript browser client to suppress the authenticate box when a wrong credential is provided.
I thought about different methods to solve this problem
someone suggested to remove the WWW-Authenticate Header with a filter (i dont think this is a clean approach)
i could rewrite my app to not use Basic Http Auth at all (i think this is too much trouble)
i could write a proxy that talks to my regular service
I like the last approach the best.
I keep my regular Rest Interface, but also have the option to use this interface with clients that are not that flexible.
Furthermore I can later proxy Http Requests unsupported by some browsers.
The idea is to have a /api/proxy/{request} path that proxies to /api/{request} and returns a Facebook-Graph-like JSON query { data: {data}, error: {error}}
This is the stub of the Proxy class
#Path("proxy")
public class ProxyResource {
#GET()
#Path("{url: [a-zA-Z/]*}")
public String get(#Context Request request, #PathParam("url") String url) {
// remove proxy/ from path
// resend request
// verify result
}
}
I can access the Request (which seems to be a ContainerRequest). How can I modify the request without building it from scratch to resend it.
Edit: when somebody knows a better approach i am delighted to hear about it.
As I started to digg deeper into this, i found out that not the 401 was the problem. The www-authenticate header sent back from the server caused the browser to open the login box.
If somebody is interested I've written a little nodejs proxy to remove a www-authenticate from all server requests.
https://gist.github.com/ebb9a5052575b0a3f41f
As this is not the answer to my original question I will leave it open.

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.

Login to site with HttpClient Post

I am trying to make a program that logs into a site and performs some automated activities. I have been using HttpClient 4.0.1, and using this to get started: http://hc.apache.org/httpcomponents-client/primer.html.
On this particular site, the cookies are not set through a "set-cookie" header, but in javascript.
So far, I am unable to achieve the login.
I've tried the following things:
add headers manually for all request headers that appear in firebug
NameValuePair[] data = {
new BasicNameValuePair("Host",host),
new BasicNameValuePair("User-Agent"," Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7"),
new BasicNameValuePair("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"),
new BasicNameValuePair("Accept-Language","en-us,en;q=0.5"),
new BasicNameValuePair("Accept-Encoding","gzip,deflate"),
new BasicNameValuePair("Accept-Charset","ISO-8859-1,utf-8;q=0.7,*;q=0.7"),
new BasicNameValuePair("Keep-Alive","300"),
new BasicNameValuePair("Connection","keep-alive"),
new BasicNameValuePair("Referer",referer),
new BasicNameValuePair("Cookie",cookiestr)
};
for(NameValuePair pair : data){
loginPost.addHeader(pair.getName(),pair.getValue());
}
creating BasicClientCookies and setting using setCookieStore. unfortunately, i can't figure out how to test if the cookies are actually being sent. also, is there a way to test what other automatic parameters are being sent? (like which browser is being emulated, etc).
The response I'm getting is: HTTP/1.1 417 Expectation Failed
I'm still new to this, so does anyone know off-hand what the problem could be? If not, I'll post more details, code, and the site.
You need WireShark or Fiddler. The first is a network analyser (so you'll see what's going on at a very low level); the second acts as a proxy - less transparent, but higher level.
That way you can look in detail at what happens when you log in with a browser, and what's happening when you try doing the same thing in code.
I'd echo the comment above - use Wireshark to get a clear view of what is being sent from your client. I've just debugged a similar problem myself with Wireshark. Essential.
If you haven't done so I would suggest studying the examples in http://hc.apache.org/httpcomponents-client/examples.html especially "Form based logon".
I'd avoid setting the Http headers using BasicNameValuePair, HttpClient should give you the basics. Modify further with HttpParams and HttpConnectionParams/HttpProtocolParams. The example conn/ManagerConnectDirect shows how to modify headers.
You can use FireBug's "net' feature to see what is happening when you log in with your browser. This way you should be able to figure out which method generates the cookie value, and how it should be set (which path, name). Use this to set the cookie on HttpClient yourself like:
method.setRequestHeader("Cookie", "special-cookie=value");

Categories