AndroidL sending data to my chat server, getting truncated - android

I'm trying to make a simple chat server. It works fine on the iphone, but not all the chats are going through on the android.
My idear was to use the http protocol so I can use the standard sfkd on the iphone and android to talk to my server
I'm using the URLConnection connection class on the android.
When I was tacing the code on my server, I noticed that I was getting the length of the post data sent in the header. I'm not setting any length value on the URLConnection class. I figured since I was not setting the size in the header that is why its not working. I could not find any info about this.
code that reads in haeder on my server
I have my server code and android code below,
public int ReadHeader()
{
// read in one line
int PageId=0;
// try{
request = new StringBuffer(1000);
System.out.println("get connection reading in header \r");
//InputStream in = new BufferedInputStream( connection.getInputStream() );
StopFlag=false;
String out;
// the first line shouls have the page
out=ReadLine();
int p;
p=out.lastIndexOf("stop");
if (p!=-1)
PageId=1;
p=out.lastIndexOf("enter");
if (p!=-1)
PageId=2;
p=out.lastIndexOf("add");
if (p!=-1)
PageId=3;
p=out.lastIndexOf("exit");
if (p!=-1)
PageId=4;
p=out.lastIndexOf("update");
if (p!=-1)
PageId=5;
int MessageSize=0;
do{
out=ReadLine();
// check for content size
// GET SIZR OF DATA SENT
if (out.contains("Length"))
{
System.out.println("found length \r");
int pes=out.indexOf(' ');
String Length=out.substring(pes+1);
System.out.println("found size");
System.out.println(Length);
//MessageSize=(int)Length;
MessageSize= Integer.parseInt( Length) ;
//MessageSize=36;
}
} while(out!="finish header" && out!="");
System.out.println("finsih header \r");
ClientMessage=ReadSize(MessageSize);
/*
} catch(IOException ec)
{
System.out.println(ec.getMessage());
}
*/
return PageId;
}
// CODE ON ANDROID
String data = URLEncoder.encode("username", "UTF-8") + "=" + URLEncoder.encode( cGlobals.UserName, "UTF-8"); data += "&" + URLEncoder.encode("comment", "UTF-8") + "=" + URLEncoder.encode( s, "UTF-8");
cGlobals.Message=""; // THIS IS NOT TKING IN ANY INFO ABOUT THE LENGTH OF data URLConnection conn = url.openConnection();
// set timeouts to 5 seconds
// conn.setConnectTimeout(1000*5);
// conn.setReadTimeout(5*1000);
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
wr.close();

Related

Android - Best practices for uploading images to the server

I have some code that sends string bytes to the server then in mvc c# i take these string bytes convert it into raw bytes and then save the bytes to file. This works great but the problem when i am sending 4 images of string bytes inside of HttpURLConnection the mvc server comes back with saying File Not Found Exception.
So i found out when i sent large images it would fail with this exception, and when i sent images lower that 3080000 bytes it sent the images and saved them to the server.
So now im deciding to show a message to the user displaying a dialog box about the file limit, is this good to do?
This is my code:
Client
try {
if (imgS!=null && imgS.size()>0) {
for (int i = 0; i < imgS.size(); i++) {
if(i == 0){
image1 = Base64.encodeToString(imgS.get(i).bytes, Base64.DEFAULT);
}
if(i == 1){
image2 = Base64.encodeToString(imgS.get(i).bytes, Base64.DEFAULT);
}
if(i == 2){
image3 = Base64.encodeToString(imgS.get(i).bytes, Base64.DEFAULT);
}
if(i == 3){
image4 = Base64.encodeToString(imgS.get(i).bytes, Base64.DEFAULT);
}
}
}
if (!isDelivered) {
deliveredId = 2;
}
if (params[0] != null && (params[0].equals("0.00") || !params[0].equals(""))) {
priceTmp = Double.valueOf(params[0]);
}
if (params[6] != null && (params[6].equals("0.00") || !params[6].equals(""))) {
postageTmp = Double.valueOf(params[6]);
}
String responseText = "";
SharedPreferences preferences = getActivity().getSharedPreferences(PREFERENCE, Context.MODE_PRIVATE);
String json = String.format("{\"p_u_id\": \"%s\",\"price\": \"%.2f\"," +
"\"title\": \"%s\"" +
",\"description\": \"%s\",\"category\": \"%d\",\"tags\": \"%s\"" +
",\"image1\": \"%s\",\"image2\": \"%s\",\"image3\": \"%s\",\"image4\": \"%s\"" +
",\"postcode\": \"%s\",\"postage\": \"%.2f\",\"isDelivered\": \"%d\"}",
preferences.getString("userId", "0"),
priceTmp,
params[1],
params[2],
selectedCategory,
params[4],
image1,
image2,
"",
"",
params[5],
postageTmp,
deliveredId
);
long b = image1.getBytes().length + image2.getBytes().length +image3.getBytes().length + image4.getBytes().length;
if(b > 3080000){
return "FileLimit";
}else{
URL url = new URL("http://xxx/Home/xxxx");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json"); // have tried without this
conn.setRequestProperty("Content-Length", json.getBytes().length + "");
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write(json.getBytes("UTF-8"));
os.close();
conn.connect();
InputStream is = conn.getInputStream();
//here we read and print the response send by server; assuming that response type is text/html (MIME Type)
StringBuilder sb = new StringBuilder();
int ch;
//-1: end of stream
while ((ch = is.read()) != -1) {
sb.append((char) ch);
}
responseText = sb.toString();
conn.disconnect();
JSONObject obj = new JSONObject(responseText);
pid = obj.getInt("id");
serverImage1 = obj.getString("image1");
serverImage2 = obj.getString("image2");
json = String.format("{\"p_id\": \"%d\",\"image1\": \"%s\"," +
"\"image2\": \"%s\",\"p_u_id\": \"%s\"}",
pid,
image3,
image4,
preferences.getString("userId", "0")
);
url = new URL("http://xxx/Home/xxxx");
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json"); // have tried without this
conn.setRequestProperty("Content-Length", json.getBytes().length + "");
conn.setDoOutput(true);
os = conn.getOutputStream();
os.write(json.getBytes("UTF-8"));
os.close();
conn.connect();
is = conn.getInputStream();
//here we read and print the response send by server; assuming that response type is text/html (MIME Type)
sb = new StringBuilder();
ch = 0;
//-1: end of stream
while ((ch = is.read()) != -1) {
sb.append((char) ch);
}
responseText = sb.toString();
return responseText;
}
} catch (Exception e) {
int i = 0;
}
What i have done here is send the first two images to the server then send the next two images after the first two images were sent. This was funny because still if i send images two big the server will come back with an exception again.
So is it good to show a message to the user about file limit?
And how do other apps like shpock n Ebay work when they allow mulitple file uploads?
I tried using some Android Libraries but was unsusseccful.
Would like to know a way of sending maxiumum of four files without showing the user a file limit and just send the 4 images directly.
MVC
if(image.Length > 0)
{
byte[] bytes = Convert.FromBase64String(image);
if (!System.IO.Directory.Exists(Server.MapPath("~/App_Data/products/" + uid)))
{
System.IO.Directory.CreateDirectory(Server.MapPath("~/App_Data/products/") + uid);
}
if (!System.IO.Directory.Exists(Server.MapPath("~/App_Data/products/" + uid + "/" + pid)))
{
System.IO.Directory.CreateDirectory(Server.MapPath("~/App_Data/products/") + uid + "/" + pid);
}
string path = Path.Combine(Server.MapPath("~/App_Data/products/" + uid + "/" + pid), guid + "" + ".jpg");
System.IO.File.WriteAllBytes(path, bytes);
}
When you have a Image you can upload it to a Cloud Database like Firestore or Amazon S3 or whatever and then you send the link instead of the bytes!
Is it a good idea to show file limit to user? Yes it is. Better than errors popping up for them.
Why is it not working for larger than 3MB images? Well, if you look at the Microsoft docs, your Convert.FromBase64String method puts the data into an unsigned 8bit integer array. An unsigned int maxes out at 4.29 Million, so because you have base64 encoded, your image is actually 33% bigger, because it has a ratio of 4:3 when you base64 encode.
Convert.FromBase64String(String) Method
Base64 Padding file size increases
Thus, you cant upload anything bigger than ~3MB.
How do other companies do multi file upload? Well they just call the same file upload endpoint, asynchronously for each file. So if you send 4 files, it will make 4 requests at the same time, and these requests will slowly upload the image (you can usually see each files individual progress bar indicator).

Http post to server from Android app does not work

I have an Android app that sends a http post to a remote server:
protected Void doInBackground(Void... params) {
// Get the message from the intent
Intent intent = getIntent();
String message = intent.getStringExtra(MapsActivity.EXTRA_MESSAGE);
double longitude = intent.getDoubleExtra(MapsActivity.EXTRA_LONGITUDE, 0.0);
double latitude = intent.getDoubleExtra(MapsActivity.EXTRA_LATITUDE, 0.0);
Log.d("doInBackground", message);
Log.d("doInBackground", String.valueOf(longitude));
Log.d("doInBackground", String.valueOf(latitude));
URL url = null;
HttpURLConnection client = null;
try {
// Establish http connection
url = new URL("http://******.com/");
client = (HttpURLConnection) url.openConnection();
client.setDoOutput(true);
client.setDoInput(true);
client.setRequestMethod("POST");
client.connect();
OutputStreamWriter writer = new OutputStreamWriter(client.getOutputStream());
String output;
output = URLEncoder.encode("message", "UTF-8")
+ "=" + URLEncoder.encode(message, "UTF-8");
output += "&" + URLEncoder.encode("longitude", "UTF-8") + "="
+ URLEncoder.encode(String.valueOf(longitude), "UTF-8");
output += "&" + URLEncoder.encode("latitude", "UTF-8") + "="
+ URLEncoder.encode(String.valueOf(latitude), "UTF-8");
Log.d("doInBackground(output)", output);
Log.d("doInBackground(code)", String.valueOf(client.getResponseCode())); // Return 200
writer.write(output);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
client.disconnect();
}
return null;
}
In the server, I have:
<?php
$m = urldecode($_POST['message']);
$long = urldecode($_POST['longitude']);
$lat = urldecode($_POST['latitude']);
print " ==== POST DATA =====
Message : $m
Longitude : $long
Latitude : $lat";
?>
client.getResponseCode() returns 200, I think that means my connection was successful? But the website still shows nothing. What might cause the problem?
I got
E/GMPM: getGoogleAppId failed with status: 10
E/GMPM: Uploading is not possible. App measurement disabled
might this be the problem?
What do you mean by the website doesn't show anything? You cannot see the print when you reload the web site because you are not saving it anywhere, you are simply printing out the values on that one single request. To debug you can write the post params to a file instead to see if they are coming through or better yet log the returned object on the android side.

DownloadWebpageTask only handles webpage content smaller than 4048 charaters? (Android)

I'm following the tutorial to download content from webpage. http://developer.android.com/training/basics/network-ops/connecting.html#download (code is copied below so you don't have to go to this link)
It use len = 500 in this example and I change it to big value such as 50000 but while experimenting I realize this method will only download the first 4048 characters of a webpage no matter how large I set len to be. So I'm wondering if I should use another method to download web content.
Actually I'm not downloading normal webpage, I've put a php script on my server to search in my database then encode a json array as the content of the page, it's not very large, about 20,000 characters..
Main codes from the above link:
// Given a URL, establishes an HttpUrlConnection and retrieves
// the web page content as a InputStream, which it returns as
// a string.
private String downloadUrl(String myurl) throws IOException {
InputStream is = null;
// Only display the first 500 characters of the retrieved
// web page content.
int len = 500; // I've change this to 50000
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
int response = conn.getResponseCode();
Log.d(DEBUG_TAG, "The response is: " + response);
is = conn.getInputStream();
// Convert the InputStream into a string
String contentAsString = readIt(is, len);
return contentAsString;
// Makes sure that the InputStream is closed after the app is
// finished using it.
} finally {
if (is != null) {
is.close();
}
}
}
// Reads an InputStream and converts it to a String.
public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
Reader reader = null;
reader = new InputStreamReader(stream, "UTF-8");
char[] buffer = new char[len];
reader.read(buffer);
return new String(buffer);
}
Are you sure it's not just LogCat truncating the message?
(Android - Set max length of logcat messages)
Try:
Printing out line by line in your readIt method
Doing this (Displaying More string on Logcat)
Saving to SD card and looking at the file
Actually doing what you want to do with it (put it in a TextView or whatever)

issue in httpurlconnection getting status 500

I am trying to login through url and i am getting status code 500 in httpurlconnevtion
public static String excutePost(String targetURL, String urlParameters)
{
URL url;
HttpURLConnection connection = null;
try {
//Create connection
url = new URL(targetURL);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Length", "" +
Integer.toString(urlParameters.getBytes().length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setRequestProperty("Accept-Encoding", "");
connection.setUseCaches (false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Send request
DataOutputStream wr = new DataOutputStream (
connection.getOutputStream ());
wr.writeBytes (urlParameters);
wr.flush ();
wr.close ();
System.out.println("status :"+connection.getResponseCode());
System.out.println("getErrorStream() :"+connection.getErrorStream());
//Get Response
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer response = new StringBuffer();
while((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
return response.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if(connection != null) {
connection.disconnect();
}
}
}
and my params are
String urlParameters =
"pwd1=" + URLEncoder.encode("DEMO123", "UTF-8") +
"&badge=" + URLEncoder.encode("1233", "UTF-8");
i am getting logcat
status :500
getErrorStream() :libcore.net.http.FixedLengthInputStream#417bc5c0
thank you
**EDITED 2**
I have also try with
DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
// Add badge
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
dos.writeBytes("Content-Disposition: form-data; name='badge';");
dos.writeBytes(LINE_END + LINE_END);
dos.writeBytes("1233");
dos.writeBytes(LINE_END);
// Add password
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
dos.writeBytes("Content-Disposition: form-data; name='pwd1';");
dos.writeBytes(LINE_END + LINE_END);
dos.writeBytes("DEMO123");
dos.writeBytes(LINE_END);
500 denotes an Internal Server Error. There is probably no error on your side, it's on the server. Even if you are sending something incorrectly and it's causing the server to return 500, it's still a server problem.
Edit:
Okey, the server should rather return something like 400 Bad Request instead of 500 Internal Server Error but I found your error now:
connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
...
//Send request
DataOutputStream wr = new DataOutputStream (connection.getOutputStream ());
wr.writeBytes (urlParameters);
The problem here is that your first get the the bytes from urlParameters using getBytes which (quoting javadoc):
Encodes this String into a sequence of bytes using the platform's default charset
And then you write the bytes using DataOutputStream.writeBytes which (quoting javadoc):
Each character in the string is written out, in sequence, by discarding its high eight bits.
In summary, your Content-Length doesn't match the data. So the server returns you the
java.io.IOException: exceeded content-length limit of 20 bytes
Solution:
//consider urlParameters.getBytes("UTF-8") method instead of using default encoding
byte[] bodyData = urlParameters.getBytes();
connection.setRequestProperty("Content-Length", Integer.toString(bodyData.length));
...
//Send request
InputStream out = connection.getOutputStream();
out.write(bodyData);
Edit 2:
Edit 1 is definitely valid, however, looking over the problem again, I believe the error is definitely caused by the server. I think the server is returning a bad Content-Length header and, when the data is read on Android, the system realizes there is more data coming from the server than it should be by the Content-Length and throws an exception, also replacing the status code by 500 because it really is a server error.
Edit 3:
connection.setRequestProperty("Content-Language", "en-US");
connection.setRequestProperty("Accept-Encoding", "");
Instead of setting Content-Language which is not neccessary here, you should set Content-Encoding to UTF-8 and instead of empty Accept-Encoding, you should add the real expected MIME-type. I believe this is a server error, but you maybe it won't appear if you set the request headers correctly.
Status code 500 means Internal Server Error. Why this is thrown at you, only the server behind targetURL knows.
Verify that you're making correct usage of the API. Taking a look at the response's body (besides the status code) may provide a hint.

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