As per Google recommendation, I am using HttpsURLConnection for my api-level 15 project.
My test case is very simple :
URL url = new URL(STATS);
HttpsURLConnection we = (HttpsURLConnection)url.openConnection();
InputStream in = new BufferedInputStream(we.getInputStream());
When I connect to my server over WiFi, everything works fine.
When I connect to my server over 3g, I am getting an error in my Apache logs :
Hostname 202.139.83.152 provided via SNI and hostname myserver.com provided via HTTP are different
Now the 202.139.83.152 address is the proxy address of my mobile providers APN.
I have dumped out the 'Client Hello' packet of both requests and the Handshake Protocol/Extension:server_name field contains the target hostname (myserver.com) for the wifi request but the APN proxy address for the 3g request.
Is this :
Something I have coded incorrectly
Something I have configured incorrectly on my phone (Samsung Galaxy S3)
Something I have configured incorrectly on my server
Something evil my mobile provider is doing
A bug in the Android libraries
My server is using a dedicated ip address for this vhost.
I can successfully make a request over 3g using a simple subclass of DefaultHttpClient but as my min API level is 15, I was hoping to go down the 'preferred' path.
Any suggestions would be very greatfully received. I've spent way too much time trying to get this basic thing working.
My colleague who is handling the iPhone development for this project shakes his head because his code 'just works out of the box'.
It turns out that this is a known issue.
I have found a workaround although I'm not sure how robust it is. What works for me so far is to disable the Proxy when making the connection :
HttpsURLConnection http = (HttpsURLConnection) url.openConnection(Proxy.NO_PROXY);
I hope this helps someone.
Here is my server side workaround for Apache (working for the last year on Apache2 - Apache/2.2.14).
Recompiled Apache/mod_ssl.so after having changed ssl_engine_kernel.c by removing the "return HTTP_BAD_REQUEST;" for the strcmp(host, servername) check :
if (strcmp(host, servername)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"Hostname %s provided via SNI and hostname %s provided"
" via HTTP are different", servername, host);
//return HTTP_BAD_REQUEST; // REMOVE THIS LINE
You will still get the error log message but not the error 400 response code.
Related
I've tried running an app that fetches JSON data from the internet through an HTTP Request object, It showed
java.net.UnknownHostException: Unable to resolve host “api.github.com”: No address associated with hostname
as the Exception for every trial. Later I checked the internet connectivity in the AVD by running a browser. I wasn't able to access any site.
Is there any settings that I'll have to change in the AVD Manager so that I can access the in the Internet through the Virtual Device.
Help me out, Thanks in Advance.
If that is your exact error, I see what's wrong just from that.
Android API's, unlike any modern browser, requires explicit declaration of http or https.
You have to make sure the URL contains either of those protocols which you either can do by adding it into the URL manually, or adding this code before you create the volley request:
if(!url.startsWith("http://") && !url.startsWith("https://")){
url = "http://" + url;
}
You could replace it with HTTPS, but not all sites have https, so it's a generally good idea to default it to HTTP to not get errors from that. If you supply https but there's no HTTPS certificate, the website will most likely refuse the connection.
In my case , I received such error when the Emulator could not connect to the internet.
(Try browsing the internet using the Emulator to test its internet connection. suggested in https://teamtreehouse.com/community/unknownhostexception-unable-to-resolve-host-apidarkskynet-no-address-associated-with-hostname)
I am using android nv-websocket-client library (both 2.0 and 1.31 versions) and I am trying to open a wss: connection; however, the connection fails with 503 Service not available error message.
Upon investigating I found that HAProxy requires the clients to use the SNI extension, otherwise such error is returned regardless of the Host: header (I am using HAProxy as a loadbalancer).
Upon investigating further (with tcpdump/wireshark) I found that the client does not send SNI, a wrong certificate is returned (for a different domain), yet the client continues with the TLS connection and actually sends the HTTP request (as if no certificate checking was performed?).
My code is basically:
ws = new WebSocketFactory().createSocket(wsurl);
ws.addHeader("Authorization", "Bearer " + Config.getToken());
ws.addListener(this);
ws.connectAsynchronously();
I didn't find an easy way to set up the SSLSocketFactory, however it seems to me that the code in nv-websocket-client just uses the SSLSocketFactory.getDefault(), which should be correct? SSLCertificateSocketFactory seems to be deprecated in favour of this approach.
Am I missing some key piece about SSL setup, is this and Android bug or is this and Android 'feature'?
I want to proxy network traffic for an Android emulator.
I can't seem to get it to work.
My emulator is booted up using this:
emulator #Nexus_5X_API_23 -http-proxy 10.0.1.17:8888
The IP and port points to what Charles reports in the Help menu.
The SSL certificate is installed. I can open the emulator browser and Charles shows me all traffic. The browser updates as usual.
All seems good so far.
Now I attempt to run my app. My first network call goes out successfully through Charles. The response returns and Charles displays it. However the response isn't passed to the app successfully.
I've set a breakpoint in the error callback and I can see a com.android.volley.NoConnectionError which is caused by java.io.IOException: unexpected end of stream on Connection.
Why doesn't Charles pass the result back back properly to the app?
Do I need to do what's defined at the end of the configuration page on Charles?
HttpHost httpproxy = new HttpHost("192.168.0.101", 8888, "http");
httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,httpproxy);
This doesn't seem correct - what am I missing?
In order to help solving
java.io.IOException: unexpected end of stream on Connection
issue please answer the questions in the comments.
As regards to
HttpHost httpproxy = new HttpHost("192.168.0.101", 8888, "http");
httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,httpproxy);
it will not help you just like that.
In fact this is another way to apply a proxy which IMO is even better than '-http-proxy' because you can apply it anywhere not only for an emulator and it is only for this app build.
You need to apply the proxy in the Http Stack you use. for example:
public class ProxyHurlStack extends HurlStack {
#Override
protected HttpURLConnection createConnection(URL url) throws IOException {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("10.0.1.17", 8888));
HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
return conn;
}
}
and then for you debug build you can use smth like:
requestQueue = Volley.newRequestQueue(context, new ProxyHurlStack());
The only way to this is that install the SSL (Secure Socket Layer) certificate at server end then no need to set any Charles proxy.
Every enterprise has two development environments,
Development ( http ) : doesn't need any SSL certificate
Production ( https ) : needs SSL certificate
When production environment installs the SSL certificate then android emulator and Volley library automatically detects the network connection and your were able to consume the apis/web services as expected.
No other solution to this problem.
I have two domains: foo.net and bar.com. They both have SSL certificates, and they work well in all desktop and mobile browsers. They are hosted on the same server configured with nginx.
However, when I make a request to a domain from within a native android app, it somehow gets the certificate from the wrong domain! This results in an IO Exception:
request = new HttpPost("https://foo.net/api/v1/baz");
request.setHeader("Authorization", "user:pass");
response = httpClient.execute(request);
...
javax.net.ssl.SSLException: hostname in certificate didn't match: <foo.net> != <bar.com> OR <bar.com> OR <www.bar.com>
What would cause android/java to try using the certificate from bar.com when every other measure seems to indicate that the server is correctly configured? Nothing appears in the nginx access or error log. There is no mention of bar.com anywhere in my android project.
Edit: I'm not sure why, but it appears that the server is using the certificate for bar.com for the server IP https://198.245.xx.xxx
The most likely cause for this problem is that the server uses Server Name Indication to choose which certificate to send. If the client doesn't support SNI, the server cannot choose which certificate to send during the SSL/TLS handshake (before any HTTP traffic is sent). SNI is required when you want to use multiple certificates on the same IP address and port, but not all clients support it (notoriously, IE on any version of Windows XP, and a number of mobile browsers).
You're also visibly using the Apache HTTP Client library (not HttpsURLConnection, for which there can be SNI support with some Android versions.
Support for SNI in the Apache HTTP Client library is quite recent, and certainly hasn't made it into the Android stack.
You may find the workaround described in this article useful (although it seems only to work for Android 4.2+).
Another two options would be:
to use a distinct IP address for each host (so as not to need SNI), if you're in control of server, or
to use another HTTP Client library (e.g. HttpsURLConnection).
A solution for Apache, more like a trick:
the SSL certificates are loaded based on the vhost name from /etc/apache2/sites-enabled. So, to trick that check make sure the problematic certificate is loaded first (remember that the vhosts are loaded by name).
It looks like the certificate of foo.net is misconfigured, and is using the same hostname as bar.com
Try to run an online certificate validation tool, like https://www.digicert.com/help/ on foo.net, just to be sure.
I think that you need to regenerate the certificate of foo.net with the right hostname, or reconfigure ngix to make sure that nginx serve the right certificate for the right host.
I have a python REST API server running on my laptop. I am trying to write a rest client in Android (using Eclipse ADT etc) to contact it using Apache's client (org.apache.http.client) libraries.
The code is really simple, and basically does the following -
HttpGet httpget = new HttpGet(new URI("http://10.0.2.2:8000/user?username=tim"));
HttpResponse response = httpclient.execute(httpget);
However at execute, it exceptions out with a time out exception. I cannot hit the URL even from the browser in the emulator.
Details of the exception
org.apache.http.conn.ConnectTimeoutException: Connect to /10.0.2.2:8000 timed out
However, I tried using the cREST client on Chrome on my laptop, and I am able to query the REST server fine.
Is it possible the machine is not on your network? Ie - it is on the other side of a router, on the internet somewhere? Because addresses starting "10." are reserved as private addresses and not routable.
See http://en.wikipedia.org/wiki/Private_network for more info
I had the same issue and here's how I figured out the cause:
Quit you emulator. Start your local server. In the browser, you should be able to access "http://localhost:8000/user?username=tim" and get some response. If you get a timeout, your server is likely not running. In my case, my python server had a break-point set and it was stuck there. Once I let it run, I was able to see responses on the browser and subsequently in the emulator (using 10.0.2.2).