HTTP Request fail - android

I have to get an HTTP request like this:
http://www.aroundertouch.com/queriesandroid1dot0/project/idProjet/45.484171;;9.050393;;Rotondi Group S.R.L. - Costruzione Macchine Abbigliamento/iphone/354781043339495/lang/en_US
With this code:
url = new URL(query);
Log.d(TAG,url.toString());
connection = url.openConnection();
httpConnection = (HttpURLConnection)connection;
int responseCode = httpConnection.getResponseCode();
// HTTP status okay
if (responseCode == HttpURLConnection.HTTP_OK) {
// preparo stream
in = httpConnection.getInputStream();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.parse(in);
}
// HTTP status fail
else{
throw new Exception("responseCode != 200 OK in "+query);
}
in.close();
httpConnection.disconnect();
_ret = parseXML(dom);
I meet this exception and I suspect that it is caused by an not encoded URL, how can I encode my URL? It isn't automatically encoded by HTTPURLConnection?
Excpetion:
D/dalvikvm(10100): GC freed 3447 objects / 513168 bytes in 47ms
W/System.err(10100): org.xml.sax.SAXParseException: Unexpected end of document
W/System.err(10100): at org.apache.harmony.xml.parsers.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:129)
W/System.err(10100): at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:157)
W/System.err(10100): at granet.arounder.webservice.ThreadDatiCard.doInBackground(ThreadDatiCard.java:76)
W/System.err(10100): at granet.arounder.webservice.ThreadDatiCard.doInBackground(ThreadDatiCard.java:1)
W/System.err(10100): at android.os.AsyncTask$2.call(AsyncTask.java:185)
W/System.err(10100): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
W/System.err(10100): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
W/System.err(10100): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
W/System.err(10100): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
W/System.err(10100): at java.lang.Thread.run(Thread.java:1096)
Thanks a lot.

Yes the data in your URL contains spaces which is bad and probably causing your request to not return what you are expecting to parse, use the built in urlencoder.
http://developer.android.com/reference/java/net/URLEncoder.html

Related

HttpURLConnection .getInputStream() Crashes on Marshmallow not Oreo

The following code works flawlessly on Android 8. On a tablet running 6 it crashes when getting the getinputstream with a file io error. I've tried for HOURS and HOURS without any luck. PLEASE help. Nothing works. Even trying a volley doesn't help. My Web API works great on a computer and a phone.
#Override
protected String doInBackground(String... args) {
StringBuilder result = new StringBuilder();
try {
URL url = new URL("https://api.github.com/users/dmnugent80/repos");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
}
catch(Exception e) {
e.printStackTrace();
}
return result.toString();
}
LOG CAT HERE
06-24 02:01:21.813 22840-22890/com.marcusengineering.recipedatabase
I/System.out: [CDS][DNS] getAllByNameImpl netId = 0 06-24 02:01:21.813
22840-22890/com.marcusengineering.recipedatabase D/libc-netbsd:
[getaddrinfo]: hostname=recipedatabase.gear.host; servname=(null);
netid=0; mark=0
[getaddrinfo]: ai_addrlen=0; ai_canonname=(null); ai_flags=4; ai_family=0 06-24 02:01:21.817
22840-22890/com.marcusengineering.recipedatabase D/libc-netbsd:
[getaddrinfo]: hostname=recipedatabase.gear.host; servname=(null);
netid=0; mark=0 06-24 02:01:21.818
22840-22890/com.marcusengineering.recipedatabase D/libc-netbsd:
[getaddrinfo]: ai_addrlen=0; ai_canonname=(null); ai_flags=1024;
ai_family=0 06-24 02:01:21.824
22840-22890/com.marcusengineering.recipedatabase D/libc-netbsd:
getaddrinfo: recipedatabase.gear.host get result from proxy gai_error
= 0 06-24 02:01:21.824 22840-22890/com.marcusengineering.recipedatabase I/System.out: [CDS]rx
timeout:0 06-24 02:01:21.826
22840-22890/com.marcusengineering.recipedatabase I/System.out:
[socket][0] connection
recipedatabase.gear.host/204.246.56.80:80;LocalPort=43028(0)
[CDS]connect[recipedatabase.gear.host/204.246.56.80:80] 06-24 02:01:21.826 22840-22890/com.marcusengineering.recipedatabase D/Posix:
[Posix_connect Debug]Process com.marcusengineering.recipedatabase :80
06-24 02:01:21.919 22840-22890/com.marcusengineering.recipedatabase
I/System.out: [CDS]port[43028]
[socket][/192.168.1.163:43028] connected 06-24 02:01:21.920 22840-22890/com.marcusengineering.recipedatabase I/System.out: [CDS]rx
timeout:0
[CDS]SO_SND_TIMEOUT:0 06-24 02:01:21.921 22840-22890/com.marcusengineering.recipedatabase I/System.out:
[OkHttp] sendRequest>>
[OkHttp] sendRequest<< 06-24 02:01:21.982 22840-22890/com.marcusengineering.recipedatabase W/System.err:
java.io.FileNotFoundException:
http://recipedatabase.gear.host/RestServiceImpl.svc/jsonfindtable/SELECT
UnitID, UnitName, HiddenFlag FROM TblUnits ORDER BY UnitName FOR JSON
PATH
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:238)
at com.marcusengineering.recipedatabase.MainActivity.getRestFromWebAsString(MainActivity.java:334)
at com.marcusengineering.recipedatabase.MainActivity$MyAsyncInitialLoad.doInBackground(MainActivity.java:252)
at com.marcusengineering.recipedatabase.MainActivity$MyAsyncInitialLoad.doInBackground(MainActivity.java:232)
at android.os.AsyncTask$2.call(AsyncTask.java:295) 06-24 02:01:21.983 22840-22890/com.marcusengineering.recipedatabase
W/System.err: at
java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
FINNNNNNNALY FIGURED IT OUT!.
Not sure which ones were 100% needed but here's what I did to help any other poor souls.
Ensure that your web api is fomratted without the extra wrapping added from WCF, i.e. is plain text. (not critical)
Get rid of spaces in your URL. It appears OREO does this for you. Earlier versions must not. The code to do this is: URL url = new URL(query.replace(" ","%20"));
Happy dance
In totality the call should be as follows:
URL url = new URL(query.replace(" ","%20"));
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
int i = urlConnection.getResponseCode();
InputStream inputs;
if (i < HttpURLConnection.HTTP_BAD_REQUEST) {
inputs = urlConnection.getInputStream();
} else {
// Error
inputs = urlConnection.getErrorStream();
return "-1";
}
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null) {
result.append(line);
}
To set the formatting to raw string in the WCF see the following.
In the *****.cs
[OperationContract]
[WebGet( UriTemplate = "jsonFindTableBare/{id}")]
Stream DoWork(string id);
In the svc.cs
public Stream DoWork(String id)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
String str = "YOUR RESPONSE HERE";
WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
return new MemoryStream(Encoding.UTF8.GetBytes(str));
}
Thanks for all the help, Mangal. Appreciate it.
You should first check response code to also handle the error input stream.
InputStream inputs;
if (urlConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
inputs = urlConnection.getInputStream();
} else {
// Error
inputs = urlConnection.getErrorStream();
}
then call
InputStream in = new BufferedInputStream(urlConnection);
I had also faced some app crashing experience because of handling error stream direclty.
Please do check always, It's a good practice.

HttpsUrlConnection EOFException

I'm using the following code for post requests
public String executeHttpPost(String uri, String data) {
HttpURLConnection conn = null;
URL url = null;
String s = null;
try {
url = new URL(uri);
conn = (HttpURLConnection) url.openConnection();
if (conn instanceof HttpsURLConnection) {
Log.d("HTTPS", "HttpsUrl");
}
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
DisplayResponseHeaders(conn);
s = readStream(conn.getInputStream());
Log.d("body", s);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
s = null;
e.printStackTrace();
} finally {
conn.disconnect();
}
return s;
}
When I use it over http, all works good , but over https I get
java.io.EOFException
at libcore.io.Streams.readAsciiLine(Streams.java:203)
at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:573)
at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:821)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)
libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)
ru.fors.remsmed.fragment.NetHelper.executeHttpPost(NetHelper.java:234)
ru.fors.remsmed.LoginActivity$UserLoginTask.doInBackground(LoginActivity.java:424)
ru.fors.remsmed.LoginActivity$UserLoginTask.doInBackground(LoginActivity.java:1)
android.os.AsyncTask$2.call(AsyncTask.java:287)
java.util.concurrent.FutureTask.run(FutureTask.java:234)
android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
java.lang.Thread.run(Thread.java:856)
threadid=14: thread exiting with uncaught exception (group=0x40a71930)
I found the issue about recycling connections bug in httpsurlconnection and possible solution :
if (Build.VERSION.SDK != null && Build.VERSION.SDK_INT > 13) {
conn.setRequestProperty("Connection", "close");
}
But it isn't work for me.
Try to change your code like this:
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded; charset: UTF-8");
byte[] output = data.getBytes("UTF-8");
conn.setFixedLengthStreamingMode(output.length);
os = conn.getOutputStream();
os.write(output);
os.flush();
os.close();
DisplayResponseHeaders(conn);
if (conn.getResponseCode() == 200) { // or other 2xx code like 204
s = readStream(conn.getInputStream());
Log.d("body", s);
}
else {
// handle error conditions like 404, 400, 500, ...
// now it may be necessary to read the error stream
InputStream errorStream = conn.getErrorStream();
// ...
}
AFAIK you should always close all streams you opened. I'm not sure whether conn.disconnect() is doing that for you.
If you want to code your HTTP(S) requests more conveniently, you can have a look at DavidWebb where you have a list of libraries helping you to avoid using cumbersome HttpURLConnection.
That EOFException suggests the response is malformed - perhaps lacking a blank line after the headers. Some HTTP client code is more forgiving in that case, for me iOS could handle my server responses fine but I was getting EOFException on Android using HttpURLConnection.
My server was using python SimpleHTTPServer and I was wrongly assuming all I needed to do to indicate success was the following:
self.send_response(200)
That sends the initial response header line, a server and a date header, but leaves the stream in the state where you are able to send additional headers too. HTTP requires an additional new line after headers to indicate they are finished. It appears if this new line isn't present when you attempt to get the result body InputStream or response code etc with HttpURLConnection then it throws the EOFException (which is actually reasonable, thinking about it). Some HTTP clients did accept the short response and reported the success result code which lead to me perhaps unfairly pointing the finger at HttpURLConnection.
I changed my server to do this instead:
self.send_response(200)
self.send_header("Content-Length", "0")
self.end_headers()
No more EOFException with that code. It's possible the "Connection: close" solutions trigger some behaviour on certain servers that might work around this (eg ensuring the response is valid before closing) but that wasn't the case with the python SimpleHTTPServer, and the root cause turned out to be my fault.
NB: There are some bugs on Android pre-Froyo (2.2) relating to keep-alive connections - see the blog post here: http://android-developers.blogspot.co.uk/2011/09/androids-http-clients.html. I'm yet to see convincing evidence of bugs with newer versions of Android.

Android SAXParseException: Unexpected end of document

I get this exception while parsing XML, but not always. After error When I try again immediately, it works. But why I get sometomes this error ?
Here is my code and error too.
StringEntity entity = new StringEntity(author, "UTF-8");
DefaultHttpClient httpClient = new DefaultHttpClient();
SharedPreferences logIn = context.getSharedPreferences("Data", Context.MODE_PRIVATE);
HttpPost httppost = new HttpPost(logIn.getString("Url", ""));
httppost.setEntity(entity);
httppost.addHeader("Accept", "text/xml");
httppost.addHeader("Content-Type", "text/xml");
HttpResponse response = httpClient.execute(httppost);
HttpEntity r_entity = response.getEntity();
xmlRecords = EntityUtils.toString(r_entity);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlRecords));
Document doc = db.parse(is);
NodeList workItemsNode = doc.getElementsByTagName("Items");
for (int i = 0; i < workItemsNode.getLength(); i++) {
//Some Code here
}
Exception
org.xml.sax.SAXParseException: Unexpected end of document
at org.apache.harmony.xml.parsers.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:125)
at com.mobile.syrinx.services.SynchroniseWorkItemsService.FillLists(SynchroniseWorkItemsService.java:101)
at com.mobile.syrinx.services.SynchroniseWorkItemsService.doInBackground(SynchroniseWorkItemsService.java:65)
at com.mobile.syrinx.services.SynchroniseWorkItemsService.doInBackground(SynchroniseWorkItemsService.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:252)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1081)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:574)
at java.lang.Thread.run(Thread.java:1020)
1) Verify that you're receiving valid XML. If you're consuming XML provided to you from a webservice, well who knows what you're getting. Invalid XML can cause problems for a lot of these parsers. The fac that this only occurs sometimes makes me think that is most likely the culprit.
The DocumentBuilder documentation is here:
http://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilder.html#parse(org.xml.sax.InputSource)
You can see that the SAX exception is thrown when there is an error parsing the xml, this implies that the xml is invalid somehow. The exception should be caught and handled acordingly.
2) Are the files you are parsing originating on different OS's than the one you're acting on? This has caused problems for me in the past, where a windows file caused errors to parsers on linux systems. This shouldn't be the problem here I don't think, but it is possible.

Android Unit Tests

I am trying to write a AndroidTestCase for one of my classes that make connection to a server and parse the returned JSONObject. When I test the functionality in the UI, the file works fine and the correct information are parsed and displayed. When I input the URL into my browser, I get the correct JSONObject back. However, when I try to get the JSONObject through a AndroidTestCase and simply verifying that it's not null, I get IOException when it tries to get the corresponding JSONObject for an url. I verified that the url it's using is correct. Here's the stack trace.
java.net.UnknownHostException: api.penncoursereview.com
at java.net.InetAddress.lookupHostByName(InetAddress.java:506)
at java.net.InetAddress.getAllByNameImpl(InetAddress.java:294)
at java.net.InetAddress.getAllByName(InetAddress.java:256)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.<init>(HttpConnection.java:69)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.<init>(HttpConnection.java:48)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection$Address.connect(HttpConnection.java:322)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnectionPool.get(HttpConnectionPool.java:89)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getHttpConnection(HttpURLConnectionImpl.java:285)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.makeConnection(HttpURLConnectionImpl.java:267)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.retrieveResponse(HttpURLConnectionImpl.java:1018)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:512)
at edu.upenn.cis.cis350.backend.Parser.retrieveJSONObject(Parser.java:34)
at edu.upenn.cis.cis350.test.ParserTest.test_retrieveJSONObject(ParserTest.java:22)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:529)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1448)
Any idea why the code works in simulator but not in test?
Thanks in advance for the help!
edit:
Here is the relevant method:
public JSONObject retrieveJSONObject(String path){
try{
URL url = new URL(path);
Log.w("Parser: retrieveJSONObject", "url=" + url);
URLConnection connection = url.openConnection();
String line;
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while ((line = reader.readLine()) != null) {
builder.append(line);
}
Log.v("Length",builder.toString());
return new JSONObject(builder.toString());
}
catch(IOException e) {
Log.w("Parser: retrieveJSONObject", "IOException: Bad Url");
e.printStackTrace();
return null;
} catch (JSONException e) {
Log.w("Parser: retrieveJSONObject", "JSONException: mis-formatted JSON");
e.printStackTrace();
return null;
}
}
Line 34 is the line initializing the BufferedReader.
I guess what you are missing is the INTERNET permission.
Considering that your method is defined static in Utils class, the following test works.
public void testRetrieveJSONObjectWithUrl() {
final String url = "http://www.bom.gov.au/fwo/IDV60901/IDV60901.94868.json";
assertNotNull(Utils.retrieveJSONObject(url));
}

Sending JSON from Android to .NET WCF with international characters. How?

I'm getting exceptions when I'm trying to POST and my JSON has some international characters.
This is code that I use:
HttpPost request = new HttpPost(serviceURL + url);
request.addHeader("Authorization", "Basic " + Preferences.getAuthorizationTicket(mContext));
request.addHeader("DeviceSerialNumber", Utility.getDeviceSerialNumber(mContext));
request.addHeader("OSVersion", "Android v" + Build.VERSION.RELEASE);
StringEntity entity = new StringEntity(requestData);
entity.setContentType("application/json;charset=UTF-8");
entity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,"application/json;charset=UTF-8"));
request.setEntity(entity);
ResponseHandler<String> handler = new BasicResponseHandler();
response.Body = mHttpClient.execute(request, handler);
response.Code = HttpURLConnection.HTTP_OK;
response.Message = "OK";
And this is error I'm getting:
org.apache.http.client.HttpResponseException:
Bad Request at
org.apache.http.impl.client.BasicResponseHandler.handleResponse(BasicResponseHandler.java:71)
at
org.apache.http.impl.client.BasicResponseHandler.handleResponse(BasicResponseHandler.java:59)
at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:657)
at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:627)
at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:616)
at
com.idatt.common.AsyncProcessor.processPOST(AsyncProcessor.java:550)
at
com.idatt.common.AsyncProcessor.PostMail(AsyncProcessor.java:367)
at
com.idatt.common.AsyncProcessor.doInBackground(AsyncProcessor.java:120)
at
com.idatt.common.AsyncProcessor.doInBackground(AsyncProcessor.java:28)
at
android.os.AsyncTask$2.call(AsyncTask.java:185)
at
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
at
java.util.concurrent.FutureTask.run(FutureTask.java:137)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
at
java.lang.Thread.run(Thread.java:1096)
When requestData doesn't have any international (russian, polish, etc) letters than it works fine. What do I miss? Or better yet how do I get traffic from emulator captured in Fiddler or something?
I believe you should specify UTF-8 charset when you create StringEntity:
StringEntity entity = new StringEntity(requestData,"utf-8");
http://developer.android.com/reference/org/apache/http/entity/StringEntity.html#StringEntity(java.lang.String, java.lang.String)

Categories

Resources