Sending special characters (ë ä ï) in POST body with DataOutputStream in Android - android

Im currently working on an Android app with heavy server side communication. Yesterday I got a bug report saying that the users aren't able to send (simple) special characters such as ëäï.
I searched but didn't find anything helpful
Possible duplicate ( without answer ):
https://stackoverflow.com/questions/12388974/android-httpurlconnection-post-special-charactes-to-rest-clint-in-android
My relevant code:
public void execute(String method) {
HttpsURLConnection urlConnection = null;
try {
URL url = new URL(this.url);
urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setRequestMethod(method);
urlConnection.setReadTimeout(30 * 1000);
urlConnection.setDoInput(true);
if (secure)
urlConnection.setRequestProperty("Authorization", "Basic " + getCredentials());
if (body != null) {
urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
urlConnection.setFixedLengthStreamingMode(body.length());
urlConnection.setDoOutput(true);
DataOutputStream dos = new DataOutputStream(urlConnection.getOutputStream());
dos.writeBytes(body);
dos.flush();
dos.close();
}
responseCode = urlConnection.getResponseCode();
message = urlConnection.getResponseMessage();
InputStream in = null;
try {
in = new BufferedInputStream(urlConnection.getInputStream(), 2048);
} catch (Exception e) {
in = new BufferedInputStream(urlConnection.getErrorStream(), 2048);
}
if (in != null)
response = convertStreamToString(in);
} catch (UnknownHostException no_con) {
responseCode = 101;
}catch (ConnectException no_con_2){
responseCode = 101;
}catch(IOException io_ex){
if(io_ex.getMessage().contains("No authentication challenges found")){
responseCode = 401;
}else
responseCode = 101;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (urlConnection != null)
urlConnection.disconnect();
}
}
body is a String ;-)
Hope we can solve this together
UPDATE:
Tried:
writeUTF()
need a server capable of understanding the modified UTF-8
byte[] buf = body.getBytes("UTF-8");
dos.write(buf, 0, buf.length);
strings work but no special chars
update: Got it working with StringEntity(* string, "UTF-8") then parse the result to a byte[] and write it with dos.write(byte[])!
--

Setting the encoding of the StringEntity did the trick for me:
StringEntity entity = new StringEntity(body, "UTF-8");
seen here: https://stackoverflow.com/a/5819465/570168

i am not totally sure buy try this utility for your case
URLEncoder.encode(string, "UTF-8")

I faced this problem in android while passing a json with special char (ñ).
In my WebApi method, [FromBody] param is giving null, it seems it can't parse the json.
I got it working by getting bytes as UTF-8 then writing it in DataOutputStream (Client-side fix).
byte[] b = jsonString.getBytes("UTF-8");
os.write(b, 0, b.length);

Related

Why am I getting 500 response code on passing wrong email or password to service in android?

I have been running into a very strange problem. I am trying to implement log in service in my app. When I pass right email and password service returns response as expected(means no error comes) but when I delibrately pass wrong email or password geInputStream() method throws FileNotFoundException. I don't know what is the reason behind this.Further more, before calling getInputStream() method i checked status code as well(this is the case when I am passing wrong email and password intentionally).The status code was 500. I checked for 500 and that was internal server error. My question is why is that so? I mean when intentionally passing wrong email or password why internal server occurred? One more thing I would like to mention that I have checked the same service on post man it is working fine as expected. If i pass wrong email or password postman returns the expected error. Below is the code I am using
private String invokeWebservice() {
String data = null;
HttpURLConnection conn = null;
BufferedReader in = null;
try {
String webservice = Constants.BASE_URL + serviceName;
LogUtility.debugLog("webservice just called "+ webservice);
URL url = new URL(webservice);
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setUseCaches(false);
if (isPost) {
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
Writer writer = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), "UTF-8"));
if (jsonObject != null)
writer.write(jsonObject.toString());
writer.close();
}
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer sb = new StringBuffer("");
String l = "";
String nl = System.getProperty("line.separator");
while ((l = in.readLine()) != null)
sb.append(l + nl);
in.close();
data = sb.toString();
return data;
} catch (Exception e) {
LogUtility.errorLog("exception while calling web service");
} finally {
try {
if (conn != null)
conn.disconnect();
if (in != null)
in.close();
} catch (Exception ex) {
// LogUtility.errorLogWithException(ex, ex.getMessage());
}
}
return data;
}
Any help?
After spending some time now I was able to solve my problem.Posting my answer for others. Passing wrong email and password to the service was right and server was consuming those parameters as well and because there was an error(because email and password) that is why it was returning 500 code. So, I checked for status code if it was 200 then I used getInputStream() method and else i called getErrorStream() method. By this way i got the stream that has property for error(this property contains error detail). Below is the code i used
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
in = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
} else {
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
}
Hope it helps other as well.

How to avoid to Time out Exception?

I'm trying to create an android application which depends on JSON responses. Sometimes it takes a lot of time for the server to respond and ends in a time out exception. Therefore I would like to add a restriction like my webservice call should abort after 20seconds if there is no response. Can you please help me achieving this idea.
Thanks in Advance.
You're not giving much details on the actual implementation that you have.
However, messing with the timeout seems like it may be an emergency fix to an underlying problem that should be fixed.
However, using websockets for transport could be a possible (and probably more elegant) solution. They provide a persistent connection between client and server once created.
Using websockets on Android and IOS
There are several ways to achieve the goal.
We can using HttpURLConnection to do the http request.
public String doPost() {
if (!mIsNetworkAvailable) {
return null;
}
try {
URL url = new URL(mURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
for (String key : mHeadersMap.keySet()) {
conn.setRequestProperty(key, mHeadersMap.get(key));
}
conn.setRequestProperty("User-Agent", "Android");
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setRequestProperty("Content-Type", "application/json");
conn.getOutputStream().write(mContent);
conn.getOutputStream().flush();
int rspCode = conn.getResponseCode();
if (rspCode >= 400) {
return null;
}
byte[] buffer = new byte[8 * 1024];
BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
while ((len = bis.read(buffer)) > 0) {
baos.write(buffer, 0, len);
}
baos.flush();
final String result = new String(baos.toByteArray());
baos.close();
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
setConnectTimeout :Sets the maximum time in milliseconds to wait while connecting.
setReadTimeout:Sets the maximum time to wait for an input stream read to complete before giving up.
Reference: http://developer.android.com/reference/java/net/URLConnection.html

Heroku not processing multipart form POST from Android

I have an API on rails 4 that accepts HTTP requests in the form of a file upload. Everything works fine on Localhost but on Heroku the POST request doesn't seem to do anything.
This is what my Android POST request looks like:
public static byte[] postData(String operation, byte[] binaryData) {
String urlString = baseUrl + "/" + operation;
String boundary = "uahbkjqtjgecuaoehuaebkjahj";
byte[] postData = null;
URLConnection urlConnection;
DataInputStream responseDataInputStream;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
StringBuffer startBuffer = new StringBuffer("--").append(boundary).append("\r\n");
startBuffer.append("Content-Disposition: form-data; name=\"data\"; ").append("filename=\"data.dat\"\r\n");
startBuffer.append("Content-Type: application/octet-stream\r\n\r\n");
StringBuffer endBuffer = new StringBuffer("\r\n--").append(boundary).append("--\r\n");
String startRequestData = startBuffer.toString();
String endRequestData = endBuffer.toString();
try {
URL url = new URL(urlString);
urlConnection = url.openConnection();
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
urlConnection.setUseCaches(false);
urlConnection.setConnectTimeout(5000); //5 seconds
urlConnection.setReadTimeout(5000);//5 seconds
urlConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
urlConnection.connect();
DataOutputStream _request = new DataOutputStream(urlConnection.getOutputStream());
// Write the start portion of the request
byteArrayOutputStream.write(startRequestData.getBytes());
postData = byteArrayOutputStream.toByteArray();
_request.write(postData);
// Write the Binary Packet
_request.write(binaryData);
// Write the end portion of the request
byteArrayOutputStream.reset();
byteArrayOutputStream.write(endRequestData.getBytes());
postData = byteArrayOutputStream.toByteArray();
_request.write(postData);
_request.flush();
_request.close();
// Read in the response bytes
InputStream is = urlConnection.getInputStream();
responseDataInputStream = new DataInputStream(is);
byteArrayOutputStream.reset();
byte[] buffer = new byte[responseDataInputStream.available()];
while (responseDataInputStream.read(buffer) != -1) {
byteArrayOutputStream.write(buffer);
buffer = new byte[responseDataInputStream.available()];
}
byte[] responseData = byteArrayOutputStream.toByteArray();
return responseData;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (SocketTimeoutException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return new byte[0];
}
My rails controller
skip_before_filter :verify_authenticity_token
respond_to :raw
before_filter :read_file
def read_file
data = params[:data].tempfile
data_compressed = ''
File.open(data, 'r') do |file|
file.each do |line|
data_compressed.concat(line)
end
end
#json_data = Zlib::Inflate.inflate(data_compressed)
end
def an_action
#processing stuff
response = Zlib::Deflate.deflate(j_response)
send_data #json_response.to_s
end
Heroku logs shows that the controller action is hit but nothing more from the logs
2015-05-05T22:39:29.860161+00:00 heroku[router]: at=info method=POST path="/api/login" host=[my app].herokuapp.com request_id=9d9c91b1-2ce2-4db5-9b54-3dea0322e211 fwd="197.237.24.179" dyno=web.1 connect=4ms service=12ms status=500 bytes=1683
2015-05-05T22:40:40.952219+00:00 heroku[router]: at=info method=POST path="/api/signup" host=[my app].herokuapp.com request_id=4adac44c-66e6-4001-a568-8eb913176091 fwd="197.237.24.179" dyno=web.1 connect=4ms service=8ms status=500 bytes=1683
After shifting my focus from Heroku to the Android code I figured out that there was an endless loop at this section of the code:
while (responseDataInputStream.read(buffer) != -1) {
byteArrayOutputStream.write(buffer);
buffer = new byte[responseDataInputStream.available()];
}
When theres nothing to read the return value is 0 instead of -1. So I updated it to:
while (responseDataInputStream.read(buffer) > 0) {
byteArrayOutputStream.write(buffer);
buffer = new byte[responseDataInputStream.available()];
}
Something strange is that on localhost the first piece of code works and it should work on production too. The documentation states that -1 is returned if the end of stream is reached DataInputStream.read(). Maybe thats a discussion for another day, for now I'm using the second piece of code.
EDIT
This issue has haunted me for weeks and after alot of googling and tweaking of the code I would like to point out that this approach was the WRONG route. The code worked on a WIFI connection but always failed on 3G. So i'll list the code changes that finally worked.
use HttpURLConnection instead of URLConnection. Reason here
Increased the size of Connect and Read timeouts from 5000 to 30000 and 120000 respectively.
Revert the while condition to while (responseDataInputStream.read(buffer) != -1)

POSTing JSON and retrieving a response in Android

I am trying to post a JSON message to a site and to retrieve a JSON message back.
java.net.ProtocolException: method does not support a request body: POST
Does anyone know what is wrong? Thanks in advance
HttpURLConnection conn=null;
try{
URL url=new URL(urlString);
String userPassword = userName +":" + passWord;
byte[] bytes=Base64.encode(userPassword.getBytes(),Base64.DEFAULT);
String stringEncoding = new String(bytes, "UTF-8");
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty ("Authorization", "Basic " + stringEncoding);
conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
Log.i("Net", "length="+conn.getContentLength());
Log.i("Net", "contentType="+conn.getContentType());
Log.i("Net", "content="+conn.getContent());
conn.connect();
}catch(Exception e){
Log.d("Url Formation Connection", e.toString());
}
//output{
try{
String requestString="{“ ";
wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(requestString.toString());
wr.flush();
//input{
BufferedReader rd = null;
String response=" ";
is = conn.getInputStream();
rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer responseBuff = new StringBuffer();
while ((line = rd.readLine()) != null) {
// Process line...
responseBuff.append(line);
}
response = responseBuff.toString();
Log.d("response", response);
}catch(Exception e){
Log.d("buffer error", e.toString());
}finally {
if (is != null) {
try {
wr.close();
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
It could be that the server you're connecting to doesn't allow POST operations. I would try a GET request first, to see if you have permissions for that web service method.
Also, you could try your luck with a simpler HttpClient, although I haven't tested this solution myself: http://www.geekmind.net/2009/11/android-simple-httpclient-to.html
Just a guess but can you try setting:
conn.setDoOutput(false);
The documentation says: "Optionally upload a request body. Instances must be configured with setDoOutput(true) if they include a request body." HttpURLConnection
Since you do not have anything in your body, might as well set it to false.
The documentation Android has for setRequestMethod is minimal, however your error states that POST is not a valid method. Try using PUT instead:
conn.setRequestMethod("PUT");
Also see this post for any tweaks you may need to make.

POST with Basic Auth fails on Android but works in C#

I have an app I am developing that requires me to post data to a 3rd party API. I have been struggling with authentication since the beginning and kept putting off further and further, and now I'm stuck.
I have tried using an Authenticator, but have read all about how there appears to be a bug in certain Android versions: Authentication Example
I have tried several different options, including the Apache Commons HTTP Library with no success. After all of this, I decided to make sure that the API wasn't the pain point. So I wrote a quick WinForms program to test the API, which worked perfectly on the first try. So, the idea that I'm working from and the API I working with both seem fine, but I am in desperate need of some guidance as to why the Java code isn't working.
Examples follow:
C# Code that works everytime:
System.Net.ServicePointManager.Expect100Continue = false;
// Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create(addWorkoutUrl);
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
string postData = "distance=4000&hours=0&minutes=20&seconds=0&tenths=0&month=08&day=01&year=2011&typeOfWorkout=standard&weightClass=H&age=28";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Set the ContentType property of the WebRequest.
request.Headers["X-API-KEY"] = apiKey;
request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes("username:password"));
request.ContentType = "application/x-www-form-urlencoded";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
MessageBox.Show(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
MessageBox.Show(responseFromServer);
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
Java code for Android that currently returns a 500:Internal Server Error, though I believe this is my fault.
URL url;
String data = "distance=4000&hours=0&minutes=20&seconds=0&tenths=0&month=08&day=01&year=2011&typeOfWorkout=standard&weightClass=H&age=28";
HttpURLConnection connection = null;
//Create connection
url = new URL(urlBasePath);
connection = (HttpURLConnection)url.openConnection();
connection.setConnectTimeout(10000);
connection.setUseCaches(false);
connection.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) ");
connection.setRequestProperty("Accept","*/*");
connection.setRequestProperty("X-API-KEY", apiKey);
connection.setRequestProperty("Authorization", "Basic " +
Base64.encode((username + ":" + password).getBytes("UTF-8"), Base64.DEFAULT));
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", "" + Integer.toString(data.getBytes("UTF-8").length));
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.write(data.getBytes("UTF-8"));
wr.flush();
wr.close();
statusCode = connection.getResponseCode();
statusReason = connection.getResponseMessage();
//At this point, I have the 500 error...
I figured out the problem, and the solution finally after stumbling across the root cause as mentioned in the comment above.
I was using Base64.encode() in my example, but I needed to be using Base64.encodeToString().
The difference being that encode() returns a byte[] and encodeToString() returns the string I was expecting.
Hopefully this will help somebody else who is caught by this.
Here's a nicer method to do to the POST.
install-package HttpClient
Then:
public void DoPost()
{
var httpClient = new HttpClient();
var creds = string.Format("{0}:{1}", _username, _password);
var basicAuth = string.Format("Basic {0}", Convert.ToBase64String(Encoding.UTF8.GetBytes(creds)));
httpClient.DefaultRequestHeaders.Add("Authorization", basicAuth);
var post = httpClient.PostAsync(_url,
new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "name", "Henrik" },
{ "age", "99" }
}));
post.Wait();
}
I have tried this in java
import java.io.*;
import java.net.*;
class download{
public static void main(String args[]){
try{
String details = "API-Key=e6d871be90a689&orderInfo={\"booking\":{\"restaurantinfo\":{\"id\":\"5722\"},\"referrer\":{\"id\": \"9448476530\" }, \"bookingdetails\":{\"instructions\":\"Make the stuff spicy\",\"bookingtime\": \"2011-11-09 12:12 pm\", \"num_guests\": \"5\"}, \"customerinfo\":{\"name\":\"Ramjee Ganti\", \"mobile\":\"9345245530\", \"email\": \"sajid#pappilon.in\", \"landline\":{ \"number\":\"0908998393\",\"ext\":\"456\"}}}}";
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("admin", "1234".toCharArray());
}
});
HttpURLConnection conn = null;
//URL url = new URL("http://api-justeat.in/ma/orders/index");
URL url = new URL("http://api.geanly.in/ma/order_ma/index");
conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput (true);
conn.setRequestMethod("POST");
//conn.setRequestMethod(HttpConnection.POST);
DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
outStream.writeBytes(details);
outStream.flush();
outStream.close();
//Get Response
InputStream is = conn.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer response = new StringBuffer();
while((line = rd.readLine()) != null) {
System.out.println(line);
}
rd.close();
System.out.println(conn.getResponseCode() + "\n\n");
}catch(Exception e){
System.out.println(e);
}
}
}
this could help.

Categories

Resources