I'm trying around with the HttpURLConnection for quite some time now and I tried several solution posted here and on other places, but nothing seems to work.
I have the following architecture:
A Ruby on Rails Web Service (Rest interface with JSON)
An iPhone Client with RestKit
An Android Client with HttpURLConnection
The iPhone Client works like a charm. It connects to the web service with RestKit.
Now the Android Client is a completely different story. I always get a 401 Unauthorized message from the server (which results in a local FileNotFoundException).
The strange thing is, that the iPhone Client gets the same error, but RestKit somehow manages the handle it by sending the same request again. I tried that of course, but I just get the same error twice.
On the Rails Log Output it looks like this:
Started POST "/api/v1/login" for 127.0.0.1 at 2012-05-03 12:44:56 +0200
Processing by Api::V1::ApiController#session_login as JSON
Parameters: {"device"=>{"model"=>"Simulator", "system"=>"Android", "version"=>"Hugo", "name"=>"Android Simulator"}, "email"=>"florian.letz#simpliflow.com", "api"=>{"device"=>{"model"=>"Simulator", "system"=>"Android", "version"=>"Hugo", "name"=>"Android Simulator"}, "email"=>"florian.letz#simpliflow.com", "action"=>"session_login", "controller"=>"api/v1/api"}}
Filter chain halted as :require_login_from_http_basic rendered or redirected
Completed 401 Unauthorized in 0ms (ActiveRecord: 0.0ms)
The exact same message occurs when the iPhone Client connect's but then suddenly a magical second request occurs and it goes through.
On the Android Client I do the following:
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod(HTTP_POST);
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Accept-Encoding", "gzip, deflate");
String userpassword = email + ":" + password;
con.setRequestProperty("Authorization", "Basic " + new String(Base64.encodeBase64(userpassword.getBytes())));
String body = jsonLogin.toString();
byte[] body_bytes = body.getBytes();
con.setRequestProperty("Content-Length", "" + Integer.toString(body_bytes.length));
con.setRequestProperty("Content-Language", "en-US");
con.setInstanceFollowRedirects(false);
con.setUseCaches (false);
con.setDoInput(true);
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream (con.getOutputStream ());
wr.write(body_bytes);
wr.flush ();
wr.close ();
InputStream is = con.getInputStream();
And on the last line the exception occurs.
I've read some things about redirects, but there is no redirect implemented at the server and I do not receive one on the client. I just get the 401 Unauthorized. The code in the web service and the iphone client indicate a quite simple workflow. Just send the data and receive the answer. I don't know where the SECOND login call comes from when the iPhone connects.
Does anyone here have any idea what the problem could be?
Thanks a lot!
EDIT #1:
I have identified the "magical" second request. The RestKit Log shows the following:
Asked if canAuthenticateAgainstProtectionSpace: with authenticationMethod = NSURLAuthenticationMethodDefault
This then results in the second request with quite a buch of headers I cannot make any sense of.
So do you know a way to implement this in Android?
Related
I am trying to send XML data with POST request to the server. But getting 500 error.
URL url = new URL(AFConstants.ServerEndPoint);
HttpURLConnection http = (HttpURLConnection) url.openConnection();
http.setRequestMethod("POST");
http.setRequestProperty("Content-Type",
"application/xml;charset=utf-8");
http.setDoOutput(true);
http.setDoInput(true);
http.connect();
DataOutputStream dataOutputStream = new DataOutputStream(http.getOutputStream());
String encoded = URLEncoder.encode(xml,"UTF-8");
dataOutputStream.writeBytes(encoded);
dataOutputStream.flush();
dataOutputStream.close();
Any ideas what is going wrong?
String xml contains this:
<?xml version=“1.0” encoding=“utf-8"?>
<AddSalesOrder revision=“8.0” environment=“Production” lang=“en-US” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=“C:\Data2\Ntp\shoprvparts\AddSalesOrder.xsd”>
<ApplicationArea>
...
</ApplicationArea>
<DataArea>
<Add confirm=“Always”/>
<SalesOrder>
<Header>
</Header>
<Line>
<LineNumber>1</LineNumber>
<OrderItem>
...
</OrderItem>
<OrderQuantity uom=“string”></OrderQuantity>
</Line>
</SalesOrder>
</DataArea>
</AddSalesOrder>
500 Internal Server Error or HTTP 500 - Internal Server Error
Cause of HTTP 500 Errors
Most of the time, "wrong" means an issue with the page or site's programming, but there's certainly a chance that the problem is on your end
so i think there will be error logs on the server and if you have access you can provide the server logs and will be easy to identify the problem
I am attempting to connect to my server using basic authentication, but when I set the Authorization header, it causes getInputStream to throw a fileNotFound exception.
Here is the relevant code:
URL url = new URL(myurl);
//set up the connection
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);//this is in milliseconds
conn.setConnectTimeout(15000);//this is in milliseconds
String authHeader = getAuthHeader(userID,pass);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setRequestProperty("authorization", authHeader);
//starts the query
conn.connect();
int response = conn.getResponseCode();
is = conn.getInputStream(); //throws the fileNotFound exception
Here is the thrown exception:
java.io.FileNotFoundException: http://<myIPaddress>/login/
Weirdly enough, I have found that the fileNotFound exception is only thrown if I try to set the request property to "authorization" or "Authorization" or any variation of that word. it is not thrown if I set it to "content-type" or "authosodifjsodfjs" (a random string), as here:
conn.setRequestProperty("content-type",authHeader)//no exception thrown
conn.setRequestProperty("authosodifjsodfjs",authHeader)//no exception thrown
If I don't set this header, I am able to connect to the server with this code and get the proper access-denied message that I am expecting.
I am also able to connect to the server and login properly if I use python's "requests" module, so it is not a problem with the server.
so my question is as follows:
1) what, if anything, am I doing wrong when setting the request property as "authorization"? how do I set the auth header properly?
2) if this is a bug with HttpURLConnection, how do I file a bug report?
Thank you.
edit: it was recommended to switch from:
conn.setRequestProperty("Authorization", authHeader);
to:
conn.addRequestProperty("Authorization", authHeader);
This did not fix the problem. It is still throwing the same exception.
EDIT:
still not sure why "Authorization" and "authorization" are causing fileNotFounExceptions, but using all caps seems to work properly. here is the shiny new working code:
conn.setRequestProperty("AUTHORIZATION",authHeader);
so it looks like it needs to be all caps. "HTTP_" will be automattically added to the front of this header, so the header that the server will see is "HTTP_AUTHORIZATION", which is what it should be.
Here is part of my OAuth code which sets Authorization header:
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setRequestProperty("User-Agent", "MyAgent");
httpUrlConnection.setConnectTimeout(30000);
httpUrlConnection.setReadTimeout(30000);
String baseAuthStr = APIKEY + ":" + APISECRET;
httpUrlConnection.addRequestProperty("Authorization", "Basic " + baseAuthStr);
httpUrlConnection.addRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpUrlConnection.connect();
How can I receive Pushbullet notes/images/profile details via API-Key on Android? My main problem is the SSL security in that point. (BTW: I'm pretty much a beginner in Android and only know the basics.)
The auth looks like this:
https://apikey#api.pushbullet.com/v2/users/me
I'm successfully requesting the content of a webpage (e.g. wikipedia.org) via
try {
URL url = new URL("https://www.wikipedia.org");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
StringWriter writer = new StringWriter();
IOUtils.copy(in, writer);
theString = writer.toString();
textView.setText(theString);
} catch (Exception e) {
textView.setText("Error: "+e "String content: " +theString);
}
but when I'm requesting, for example, my profile details I'm always getting a
javaio FileNotFoundException
If you run your requests through https://www.runscope.com you can often see what the request is that your client is actually making (they have a free plan for trying it out).
If I had to guess I would say it's likely the authorization is not working correctly. Are you able to get that page using curl? It should look something like:
curl -u <apikey>: https://api.pushbullet.com/v2/users/me
Assuming that works, try something like
urlConnection.setRequestProperty("Authorization", "Bearer <apikey>");
or however it is you set headers on your HTTP requests. This is more explicit than relying on the https://password#domain url thing.
i'm trying to get the source code from a site using this code
conn = (HttpURLConnection)url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(20000);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.addRequestProperty("User-Agent", "Mozilla/5.0");
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
int response = conn.getResponseCode();
if (response = 307){
String locationHeader = conn.getHeaderField("Location");
URL redirectURL = new URL(locationHeader);
...
}
when the server responds with a 307 code i create a new connection with the same parameters as above with the new url given by the server.
this code works fine while following the first 2 redirects, at the third the server gives a relative url that forces a MalformedURLException when my code executes ' new URL(locationHeader); '.
so i tried to fix that adding the ' http://servername/ ' to the ' locationHeader ' string but doing that creates a loop cause the server then redirects to the first url of his redirection chain.
since my browser gets the source code from that server with no problems is there a way to achieve that with HttpURLConnection?
if someone is interested thanks to Fiddler i worked out a solution to this issue.
first i changed the "User-Agent" property to mimic the one of Mozilla then i manually tweaked the cookie the serer was sending in its reply with the relative path.
that did the trick. thank you Fiddler.
I've encountered a rather strange error. I've written an android application that uploads an simple text file to a server. The code for the connection is as follows:
try {
URL = new URL(myURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary="+"---");
DataOutputStream output = new DataOutPutstream(connection.getOutputStream());
output.writeBytes(<my post request>);
output.flush();
output.close();
connection.connect();
}
When I run this method, the post request is never sent over to the server. Nothing shows up on wireshark and if I look in logcat, there are no errors and the connection gets made fine, the POST message is just never sent. However, if I add a simple line right after the connection.connect() such as:
connection.getResponseCode();
Suddenly the POST message gets sent over no problem. What's going on here? Am I required to get a response code in order for the message to get sent over?
Why do you have to call URLConnection#getInputStream to be able to write out to URLConnection#getOutputStream?
In short you must call getInputStream() and close it. getResponseCode() is also working because it requires an established connection.
You do not need to call
connection.connect();
which is redundant.
You can get working sample from here: http://www.xyzws.com/Javafaq/how-to-use-httpurlconnection-post-data-to-web-server/139
You set doInput to true. Maybe the url connection waits for an input because of that. Try to set it to false. But I could also be wrong. It is just a guess.