Strange characters in HTTP GET response - android

I'm trying to figure out why special characters in a JSON feed (that looks completely fine when viewed in a browser) will break when used in my Android code. Characters with accent marks, ellipsis characters, curly quote characters and so on are replaced by other characters--perhaps translating it from UTF-8 down to ASCII? I'm not sure. I'm using a GET request to pull JSON data from a server, parsing it, storing it in a database, then using Html.fromHtml() and placing the contents in a TextView.

After much experimentation, I narrowed down possibilities until I discovered the problem is with the Ignition HTTP libraries (https://github.com/kaeppler/ignition). Specifically, with ignitedHttpResponse.getResponseBodyAsString()
Although that's a handy shortcut, that one line results in the broken characters. Instead, I now use:
InputStream contentStream = ignitedHttpResponse.getResponseBody();
String content = Util.inputStreamToString(contentStream);
public static String inputStreamToString(InputStream is) throws IOException {
String line = "";
StringBuilder total = new StringBuilder();
// Wrap a BufferedReader around the InputStream
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
// Read response until the end
while ((line = rd.readLine()) != null) {
total.append(line);
}
// Return full string
return total.toString();
}
Edit: Adding more detail
Here is a minimum test case to reproduce the issue.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
activity = this;
instance = this;
String url = SaveConstants.URL;
IgnitedHttpRequest request = new IgnitedHttp(activity).get(url);
InputStream contentStream = null;
try {
IgnitedHttpResponse response = request.send();
String badContent = response.getResponseBodyAsString();
int start = badContent.indexOf("is Texas");
Log.e(TAG, "bad content: " + badContent.substring(start, start + 10));
contentStream = response.getResponseBody();
String goodContent = Util.inputStreamToString(contentStream);
start = goodContent.indexOf("is Texas");
Log.e(TAG, "good content: " + goodContent.substring(start, start + 10));
} catch (IOException ioe) {
Log.e(TAG, "error", ioe);
}
}
In the log:
bad content: is Texasâ good content: is Texas’
Update: either I'm crazy, or the problem only occurs in the clients' production feed, not their development feed, although the contents look identical when viewed in a browser--showing "Texas’". So perhaps there's some wonky server configuration required to cause this issue... but still, the fix for this issue when it occurs is as I outlined. I do not recommend using response.getResponseBodyAsString();

Related

How to prevent denial of services(DOS) attacks in android?

I have used map in my android application. I passed origin and destination latlon and get data from map url then parse the response.
But while auditing below code as marked for DOS attack stating that "This code might allow an attacker to crash the program or otherwise make it unavailable to legitimate users."
Concern : What if attacker push too large file then it will go on line by line and loop will be run for too long.
Proposed solution : Do not allow to read more than specific file size, so that it won't read file beyond some limit
Here is my code :
String url = "https://maps.googleapis.com/maps/api/directions/json"+ "?" + str_origin + "&" + str_dest + "&" + "sensor=false";
private String downloadDataFromUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpsURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.connect();
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream),1024);
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
data = sb.toString();
br.close();
} catch (Exception e) {
Log.d("Exception", e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
Please provide solution. Thanks in advance.
Edit 1:by calling append() it appends Untrusted data to a StringBuilder instance initialized with the default backing-array size (16). This can cause the JVM to over-consume heap memory space.
If you download from an unknown URL, the data can indeed be arbitrary and BufferedReader.readLine() can encounter a line so long the program cannot handle it. This question indicates that limiting BufferedReader line length may not be trivial.
Number of lines can be too big as well, in which case line count check instead of simple null check in the while loop seems to be enough.
Question is why would you allow the user to input an arbitrary URL and download it without checking. The URL can easily be a several GB binary file. Your first line indicates that you intend to use the Google Maps API, which AFAIK does not return excessively large lines, rendering the DOS concern moot (except in some ultrasecure applications, which I do not think Android is suitable to use for).

how to retrieve data from URL which is not a JSON object into android listView?

I have This URL and I want to fetch all the data present in here in an android list view, I only know how to retrieve data from a JSON object but here I don't even know the format of this data present in the URL.
The format of the URL is:
tvg-logo = url of the logo chanel
group-title = category where you need to display the channel (just for movie not for TV)
After the "," you have the name of the channel
And after the name you have the URL of video
How can I parse my data from the URL so that I can make a list view like that:
i think, you must split the String text by special characters. and keep them in an array. for example,the special character might be "[space character]" or "," or "#".
I hope to help you
This function will get the data from URL and you could split your data as per your requirement and populate UI.
void fetchDataFromUrl() {
try {
URL oracle = new URL("http://cinecosta.com/api_tv.php?pass=yojeju123");
URLConnection yc = oracle.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
The result seems easy to parse actually.Just see the pattern.
#SOMETHING tvg-logo="logo" tvg-categorie="something"
Use regex for split the pattern you want.
Regex
if you are using retrofit as a network library so you can pass the "ResponseBody" in the api callback function. In onSuccess Method We will get the Body And Use the Following the Code.
Interface Class:
Call<ResponseBody> yourFuncationName();
ResponseBody data = (ResponseBody) model.body();
String json = getStringData(data.byteStream());
Function is
public String getStringData(InputStream inputStream) {
BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder total = new StringBuilder();
String line;
try {
while ((line = r.readLine()) != null) {
total.append(line).append('\n');
}
} catch (IOException e) {
e.printStackTrace();
}
return total.toString();
}
Maybe this will helpful for you.
Try with below code, Here I am extracted only url from the api response
String strData = "#EXTM3U #EXTINF:-1 tvg-logo=\"http://www.cinecosta.com/image-appletv/tv/tf1-tv.png\" tvg-categorie=\"TV\",TF1 http://217.182.164.103:25461/live/YnAmpNBQUX/YUCgme6CXS/314.ts #EXTINF:-1 tvg-logo=\"http://www.cinecosta.com/image-appletv/tv/france2.png\" tvg-categorie=\"TV\",France 2 http://217.182.164.103:25461/live/YnAmpNBQUX/YUCgme6CXS/315.ts #EXTINF:-1 tvg-logo=\"http://www.cinecosta.com/image-appletv/tv/france3.png\" tvg-categorie=\"TV\",France 3 http://217.182.164.103:25461/live/YnAmpNBQUX/YUCgme6CXS/316.ts #EXTINF:-1 tvg-logo=\"http://www.cinecosta.com/image-appletv/tv/france4.png\" tvg-categorie=\"TV\",France 4 http://217.182.164.103:25461/live/YnAmpNBQUX/YUCgme6CXS/317.ts #EXTINF:-1 tvg-logo=\"http://www.cinecosta.com/image-appletv/tv/france5.png\" tvg-categorie=\"TV\",France 5 http://217.182.164.103:25461/live/YnAmpNBQUX/YUCgme6CXS/318.ts";
private void convertDataToArray() {
String[] splitArray = strData.split("#EXTINF:-");
ArrayList<String> arrstrUrl = new ArrayList<String>();
ArrayList<String> arrstrMainUrl = new ArrayList<String>();
ArrayList<String> arrstrCategory = new ArrayList<String>();
ArrayList<String> arrstrName = new ArrayList<String>();
for (int i = 1; i < splitArray.length; i++) {
System.out.println("Final=>" + splitArray[i]);
arrstrUrl.add(splitArray[i].split("1 tvg-logo=")[1].split(" ")[0]);
arrstrMainUrl.add("http" + splitArray[i].split("1 tvg-logo=")[1].split("tvg-categorie=")[1].split("http")[1]);
arrstrName.add(splitArray[i].split("1 tvg-logo=")[1].split("tvg-categorie=")[1].split(",")[0]);
arrstrCategory.add(splitArray[i].split("1 tvg-logo=")[1].split("tvg-categorie=")[1].split(",")[1].split("http")[0]);
}
System.out.println("Final Image=>" + arrstrUrl.toString());
System.out.println("Final Main=>" + arrstrMainUrl.toString());
System.out.println("Final Name=>" + arrstrName.toString());
System.out.println("Final Category=>" + arrstrCategory.toString());
}
So this way, you can get parse your data and update your listview.
Note:- You need to write your own logic to parse this data, by checking data pattern.
The solution for this is :
Either you can scrap the data from python libraries like scrapy or beautiful soup then convert it to json and read from the android.
Parse the html using the jsoup lib (https://jsoup.org/) and model the data in the desire format that you want.

On Android, how to read the exact text of a file, when one finishes with a newline, and another doesn't

This is related to a situation I find myself in working with saving text files in Unity on Android, then reading them in native Android.
One of the files we read is a HMACMD5 signature, created with the code,
byte[] bData = System.Text.Encoding.UTF8.GetBytes (data);
byte[] bKey = System.Text.Encoding.UTF8.GetBytes (key);
using (HMACMD5 hmac = new HMACMD5(bKey)) {
byte[] signature = hmac.ComputeHash (bData);
return System.Convert.ToBase64String (signature);
}
And then written to the phone with,
public static void SaveText (string path, string data) {
using (FileStream fs = new FileStream(path, FileMode.Create)) {
using (StreamWriter sw = new StreamWriter(fs)) {
sw.Write (data);
}
}
}
The other string we're saving is a JSON string dump. The signature has a newline character at the end of the string, but the JSON string doesn't. I know I can manually add one, but this question is about reading the accurate file contents.
On Android, based on previous SO answers, I read the file with,
String readFile(File file) {
StringBuilder text = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append("\n");
}
br.close();
}
catch (IOException e) {
MyLogger.e(LOG_TAG, "Error opening file " + file.getPath(), e);
}
return text.toString();
}
I'm manually adding the newline character after every line, but if I do this, I don't accurately read the JSON file, which doesn't have a newline character at the end. If I don't add the newline, I don't accurately read the signature file, which does.
You better then do not use readLine() but read().

google calculator results for android

I am making an android application which requires to send a mathematical question like 1+1 to google's calculator and I need to get that result which is displayed on the web. How can I achieve this on android?
One possibility is to create a URL for the equation you are trying to calculate and then use a URLConnection to open the URL and read the webpage source code to find the answer to the equation.
For example if you have the equation:
2+2
Then the URL to calculate the result with the Google Chrome calculator would be:
https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=2%2B2
You will have to construct the proper query in the URL for the equation you are solving. In this URL the query at the end has the equation 2+2:
q=2%2B2 (where the %2B represents the + sign)
After constructing the URL open it with a URLConnection and read the source. The answer to the equation will be in this element:
<span class="cwcot" id="cwos">4</span>
So you can parse the source in order to find that particular span element and retrieve the result of your equation.
This is probably more work than you expected but it is the only solution I can think of to accomplish what you asked. Also, this approach may be error prone and may break easily. I would consider using a different approach altogether such as launching an intent to use the calculator app on the mobile device (even though this approach has issues as well).
EDIT:
This worked for me (it will output: 2 + 2 = 4):
public static void test() {
try {
String source = getUrlSource();
String span = "<span class=\"nobr\"><h2 class=\"r\" style=\"display:inline;font-size:138%\">";
int length = span.length();
int index = source.indexOf(span) + length;
String equation = source.substring(index, source.indexOf("<", index));
System.out.println( "equation: " + equation);
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getUrlSource() throws IOException {
String url = "https://www.google.com/search";
String charset = "UTF-8";
String param1 = "2+2";
String query = String.format("?q=%s", URLEncoder.encode(param1, charset));
HttpsURLConnection urlConn = (HttpsURLConnection)new URL(url + query).openConnection();
urlConn.setRequestProperty("User-Agent", "Mozilla/5.0");
urlConn.setRequestProperty("Accept-Charset", charset);
BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
String inputLine;
StringBuilder a = new StringBuilder();
while ((inputLine = in.readLine()) != null)
a.append(inputLine);
in.close();
return a.toString();
}

JSONExecption Unterminated String - Android

I am building an app that connects to a blog then gathers the data in JSON. Currently I amgeting this error (sorry about all JSON dat not sure whether to include):
Exception Caught
org.json.JSONException: Unterminated string at character 6564 of {"status":"ok","count":20,"count_total":1727,"pages":87,"posts":[{"id":23419,"url":"http:\/\/blog.teamtreehouse.com\/happy-mothers-day-ones-whove-shaped-web-careers","title":"Happy Mother\u2019s Day! Thanks, Mom, for Helping Us Learn","date":"2014-05-08 11:00:29","author":"Ryan Brinks","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/mothers-dayHaik-Avanian-150x150.jpg"},{"id":23412,"url":"http:\/\/blog.teamtreehouse.com\/technology-brings-people-attitude-public-data-projects","title":"Public Data Brings ‘We the People’ Attitude to Technology","date":"2014-05-08 10:08:22","author":"Kelley King","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/adoptahydrant-150x150.jpg"},{"id":23409,"url":"http:\/\/blog.teamtreehouse.com\/help-students-learn-computer-programming","title":"A Push for More Computer Programming in Public Schools","date":"2014-05-07 15:50:51","author":"Tim Skillern","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/student-computer-class-woodleywonderworks-flickr-150x150.jpg"},{"id":23398,"url":"http:\/\/blog.teamtreehouse.com\/military-veterans-finding-technology-jobs-secure-bet","title":"Technology Jobs a Secure Bet for Military Veterans","date":"2014-05-06 13:45:13","author":"Anayat Durrani","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/durrani-kopser-150x150.jpg"},{"id":23407,"url":"http:\/\/blog.teamtreehouse.com\/typography-sidebars-style-guides-treehouse-show-ep-89","title":"Typography, Sidebars, Style Guides | The Treehouse Show Ep 89","date":"2014-05-06 10:15:43","author":"Jason Seifer","thumbnail":null},{"id":23393,"url":"http:\/\/blog.teamtreehouse.com\/5-tips-creating-perfect-web-design-portfolio","title":"5 Tips for Creating the Perfect Web Design Portfolio","date":"2014-05-05 17:55:08","author":"Nick Pettit","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/how-to-make-a-website-150x150.jpg"},{"id":23381,"url":"http:\/\/blog.teamtreehouse.com\/writing-tips-better-business-marketing","title":"11 Rules for Better Writing, or How Not to Use a Thesaurus","date":"2014-05-01 18:38:32","author":"Tim Skillern","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/pencils-wikimedia-150x150.jpg"},{"id":23387,"url":"http:\/\/blog.teamtreehouse.com\/web-job-perks-unlimited-vacation-catered-lunch-part-amazing-opportunity-weebly-com-programmer","title":"Web Job Perks: Unlimited Vacation, Catered Lunch Part of \u2018Amazing Opportunity\u2019 for Weebly.com Programmer","date":"2014-05-01 17:00:28","author":"Jimmy Alford","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/weebly-guy0-2-150x150.jpg"},{"id":23375,"url":"http:\/\/blog.teamtreehouse.com\/illustrator-ben-obrien-inspiration","title":"Noted Illustrator Ben O’Brien Talks About Finding Inspiration, Taking Chances","date":"2014-04-29 18:13:58","author":"Gillian Carson","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/04\/obrien3-150x150.jpg"},{"id":23373,"url":"http:\/\/blog.teamtreehouse.com\/gulp-sketch-3-bud-treehouse-show-episode-88","title":"Gulp | Sketch 3 | Bud | The Treehouse Show Episode 88","date":"2014-04-29 15:29:20","author":"Jason Seifer","thumbnail":null},{"id":23361,"url":"http:\/\/blog.teamtreehouse.com\/flexbox-next-generation-css-layout-arrived","title":"Flexbox: The Next Generation of CSS Layout Has Arrived","date":"2014-04-29 11:53:40","author":"Nick Pettit","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/04\/Screen-Shot-2014-04-28-at-1.00.03-AM-150x150.png"},{"id":23364,"url":"http:\/\/blog.teamtreehouse.com\/help-wanted-women-color-needed-technology-web-jobs","title":"Help Wanted: Women of Color Needed in Technology, Web Jobs","date":"2014-04-28 12:28:56","author":"Anayat Durrani","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/04\/poorn
This is where teh error is being caught:
public void updateList() {
if (mBlogData == null) {
// TODO: Handle Error
}
else {
try {
Log.d(TAG, mBlogData.toString(2));
}
catch (JSONException e) {
Log.e(TAG, "Exception Caught", e);
}
}
}
I am not sure what is causing this error so any suggestions are welcome. I can provide more code if needed. Thank You.
Just wanted to add to eMad's answer which helped me solve the same problem you are having. I hope this helps anybody who is to come after me because this darn bug killed 2 hours of my day (or night, I'm nocturnal). Well, with out further (ado? adieu?), here you go : P.S. the below code will go in your private class GetBlogPostsTask AsynnTask...
protected JSONObject doInBackground(Object... arg0) {
int responseCode = -1;
JSONObject jsonResponse = null;
try {
//set API URL
URL blogFeedUrl = new URL("http://blog.teamtreehouse.com/api/get_recent_summary/? count=" + NUMBER_OF_POSTS);
//open URL connection
URLConnection connection = blogFeedUrl.openConnection();
//create BufferedReader to read the InputStream return from the connection
BufferedReader in = new BufferedReader(
new InputStreamReader ( connection.getInputStream() )
);
//initiate strings to hold response data
String inputLine;
String responseData = "";
//read the InputStream with the BufferedReader line by line and add each line to responseData
while ( ( inputLine = in.readLine() ) != null ){
responseData += inputLine;
}
//check to make sure the responseData is not empty
if( responseData!= "" ){
/*initiate the jsonResponse as a JSONObject based on the string values added
to responseData by the BufferedReader */
jsonResponse = new JSONObject(responseData);
}
/*return the jsonResponse JSONObject to the postExecute() method
to update the UI of the context */
return jsonResponse;
}
catch (MalformedURLException e) {
Log.e(TAG, "Exception caught: ", e);
}
catch (IOException e) {
Log.e(TAG, "Exception caught: ", e);
}
catch (Exception e) {
Log.e(TAG, "Exception caught: ", e);
}
return jsonResponse;
}
#Override
protected void onPostExecute(JSONObject result) {
/* set the class' member JSONObject mBlogData to the result
to be used by the handleBlogResponse() method to update the UI */
mBlogData = result;
/*call the handleBlogResponse() method to update the UI with the result of this AsyncTask
which will be a JSONObject in best case scenario or a null object in worst case */
handleBlogResponse();
}
A friend of mine brought me a code that was generating the same output as yours. I think this is the solution that you're looking for. Given code is
// inside the class which connects to URL (Probably MainList)
InputStream inputStream = connection.getInputStream();
Reader reader = new InputStreamReader(inputStream);
int contentLength = connection.getContentLength();
char[] charArray = new char[contentLength];
reader.read(charArray);
String responseData = new String(charArray);
jsonResponse = new JSONObject(responseData);
But don't know why using above code, you either not get the full string or get the ContentLenght right but the last few characters aren't received properly. Use following code instead which reads complete response:
URLConnection yc = blogFeedUrl.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
yc.getInputStream()));
String inputLine;
responseData = "";
while ((inputLine = in.readLine()) != null) // read till you can receive any data
responseData += inputLine;
in.close();

Categories

Resources