Volley parseNetworkResponse is not called if last response body is null - android

Problem:
Once I execute DELETE request using Volley, the very next request always goes to onErrorResponse block (bypassing parseNetworkResponse). After that all requests work fine until again I execute DELETE request. The very next request doesn't work. If I try the same request again, it will work.
Description:
I'm using JsonObjectRequest to fire all APIs. As for DELETE request, response body is null. Thus, JsonObjectRequest can't handle it and results into Parse error. So, I implemented parseNetworkResponse to explicitly check for null body. Now, DELETE request works.
Here is my code,
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
//Allow null
if (jsonString == null || jsonString.length() == 0) {
jsonString = "{'status':'success'}";
}
return Response.success(new JSONObject(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
Above snippet allowed JsonObjectRequest to handle null body. Now, DELETE request is working fine.
But as soon as I fire DELETE request, the very next request stops
working. It directly goes to onErrorResponse and
parseNetworkResponse is not being called.
Example:
Fired multiple POST, GET combinations. All good.
Fired DELETE request. Successfully completed
Fired one POST or GET request. Directly goes to onErrorResponse (bypassing parseNetworkResponse).
Again tried the same request, it worked.
Everything works properly until again I fire DELETE request. Once I fire DELETE request, then the very next request only doesn't work.
It throws below error,
com.android.volley.NoConnectionError: java.net.ProtocolException: Unexpected status line: <link rel='stylesheet' type='text/css' property='stylesheet' href='//MY_DOMAIN_NAME/_debugbar/assets/stylesheets?v=1484813989'><script type='text/javascript' src='//MY_DOMAIN_NAME/_debugbar/assets/javascript?v=1483605979'></script><script type="text/javascript">jQuery.noConflict(true);</script>
I also tried to disable the cache for all requests. I even tried appending random number as a parameter to make sure url is always unique. Still it didn't work.
Edit:
Also further debugging shows that, parseNetworkError is called. Apache log on backend suggests that sometimes that faulty request reaches to the server and server returned correct response though it doesn't go to parseNetworkResponse and shows error.
Majority of the times, request doesn't even reach to the server at all.
It sounds very weird bug. Any help will be greatly appreciated. Let me know if you need more information.

Related

OKHTTP request responds with no data

In my app I make a simple get request via okhttp (this is simplified a bit, but you get the gist)
Request request = new Request.Builder()
.url(url)
.get()
.build();
try {
Response response = getOkHttpClient().newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
return "";
}
}
catch (Exception e) {
Log.e(TAG, "Exception: ", e);
return "";
}
The url is a http url.
The api is my clients api and the call works fine outside their office network, unfortunately it does not work inside their office network.
Inside their network the response is 200 but there is no data attached to it (response.body().string() returns an empty string), however the request works just fine in the browser inside their network.
So what could the difference be between making the request inside their network from the app, versus inside their network in the browser? Could I spoof a browser user agent and that would fix it?
We do not know what was causing this, apparently their IT department made some sort of unrelated change to the network and now it works.

Android: OkHttp request format and authorising apis

I am using the Dirble Api and I am trying to test it to even get some results back but I think I might be doing it the wrong way. This is how I have been trying:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://api.dirble.com/v2/songs?token={MY_PROVIDED_ACCESS_TOKEN}")
.build();
try {
Response response = client.newCall(request).execute();
System.out.println("Test " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
But I keep getting the error:
{"error":"Unauthorized. Invalid or expired token."}
I assumed that this meant the tokens they provided me are just not functioning. So I generated a new one and same result.
This is there guidelines:
https://dirble.com/api-doc#introduction
I cant see anything I am doing wrong but since I am a novice in http requests, I would like to check there is nothing wrong with how I am doing it before I contact them to say the my access codes aren't working.

Volley Cache returns null when receiving 304

I am trying to get Volley to work using its Cache. When I receive a 304 getCacheEntry().data is null even though "cache-control" is set. Here is what I am doing:
Volley gets instantiated likes this
// Instantiate the cache
Cache cache = new DiskBasedCache(c.getCacheDir(), 10 * 1024 * 1024); // 10 MB cap
// Set up the network to use HttpURLConnection as the HTTP client.
Network network = new BasicNetwork(new HurlStack());
// Instantiate the RequestQueue with the cache and network.
mRequestQueue = new RequestQueue(cache, network);
// Start the queue
mRequestQueue.start();
After sending a GET request I get the response 200 with "cache-control" set to "max-age=180, public". So far so good right?
If a GET request gets made twice or more I set "If-Modified-Since" with the last timestamp the request was made to the request header.
The second time I request a specific API endpoint the sever will respond with a 304. getCacheEntry().data returns null though. If I check the cache entries in Volleys RequestQueue I cannot find an entry for my specific request.
What am I doing wrong? For some reason I have one request that is always cached when fired once. It's even one that returns a lot of data. But all other requests aren't cached. Following code snippet parses the response and checks for 304.
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response, String charset) {
try {
String json = "";
if (!response.notModified) {
json = new String(response.data, charset);
} else {
//if not modified -> strangely getCacheEntry().data always null
json = new String(getCacheEntry().data, charset);
}
return Response.success(
gson.fromJson(json, clazz),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
I really appreciate any comments on this.
IMHO, your cache entry is always null (not only when getting 304 resp code), because of the following:
Cache cache = new DiskBasedCache(c.getCacheDir(), 10 * 1024 * 1024); // 10 MB cap
Please check your c.getCacheDir() to see if you want to use External Storage to store cache data, then you should set WRITE_EXTERNAL_STORAGE permission inside AndroidManifest.xml file.
Hope this helps!

Android post authorization

I am trying to do a http post to my server to check if the login credentials are valid with help of this tutorial. I need to make a request to my server but i have to add Authorization, i get the string with the function getB64Auth from this answer. the function logs the right variable, (the same as i use with postman). But for some reason my program stops running if i run my code. I already tried adding the code from the comments but it didn't help.
What am i doing wrong?
private String getB64Auth (String login, String pass) {
String source=login+":"+pass;
String ret="Basic "+Base64.encodeToString(source.getBytes(),Base64.URL_SAFE| Base64.NO_WRAP);
Log.d("authy", ret);
return ret;
}
/** Called when the user clicks the Login button */
public void login(View view) {
// Getting username and password
EditText userText = (EditText) findViewById(R.id.inputLoginUsername);
EditText passText = (EditText) findViewById(R.id.inputLoginPassword);
String usernameInput = userText.getText().toString();
String passwordInput = passText.getText().toString();
String authorizationString = getB64Auth(usernameInput,passwordInput );
// Do something in response to button
// 1. Create an object of HttpClient
HttpClient httpClient = new DefaultHttpClient();
// 2. Create an object of HttpPost
// I have my real server name down here
HttpPost httpPost = new HttpPost("https://myservername.com/login");
// 3. Add POST parameters
httpPost.setHeader("Authorization", authorizationString);
// 5. Finally making an HTTP POST request
try {
HttpResponse response = httpClient.execute(httpPost);
Log.d("win", "win1");
// write response to log
Log.d("Http Post Response:", response.toString());
} catch (ClientProtocolException e) {
Log.d("fail", "Fail 3");
// Log exception
e.printStackTrace();
} catch (IOException e) {
Log.d("fail", "Fail 4");
// Log exception
e.printStackTrace();
}
}
When i run my code the app stops working, i can find the log authy but i cant find any fail succes logs.
The things i have changed in the example are step 3.
ive added my authorization there.
and removed step 4 cause i dont need it.
Working postman example, with the same request i want to make in android.
You can see I get a response, and only set Authorization on my request.
I cant find any decent post/authorization tutorials so i hope i'm looking at the right direction.
It's an android 4.* project
Just a few suggestions about such issues:
Check permissions (INTERNET is the one you would need)
Applications like Charles / Fiddler let you sniff the Http traffic from the device so you could investigate what is being sent
If the application is crashing - check the LogCat messages (for example it could contain a message explaining which permission is missing)
Regarding this message:
The application may be doing too much work on its main thread.
This usually means that you are doing some heavy operations in the main thread - for example parsing the Json from the Http response. Generally you'd like to do all these operations in a background thread and use the main one to update the UI only.

Make a synchronous Retrofit call from inside an OkHttp Interceptor

I am trying to automatically refresh an auth token if it is expired. I am using the new Interceptor class that was introduced in OkHttp 2.2. In the intercept method I am trying the original request with chain.proceed(request), checking the response code, and if the token is expired I am making a call to a separate Retrofit service, synchronously, to obtain a new token.
The strange thing is, no code past the synchronous call seems to run. If I try debugging with a breakpoint on the synchronous call's line, then do a step-over, I am stopped in Dispatcher.java at :
if (!executedCalls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
Any idea as to what I might be doing wrong here? I could probably just craft a new request by hand, but I am just kind of curious why a Retrofit call doesn't seem to work here.
My Interceptor:
public class ReAuthInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// try the request
Response response = chain.proceed(request);
// if we receive a "401 - Not Authorized" then refresh the auth token and try again
if (response.code() == 401) {
// get a new auth token and store it
UserToken userToken = MobileClient.getOkraService().login(AuthUtil.getUserToken(MSWorksApplication.getContext()));
AuthUtil.authenticate(MSWorksApplication.getContext(), userToken);
Log.d("TEST", "TEST TEST TEST");
// use the original request with the new auth token
Request newRequest = request.newBuilder().header("Authorization", AuthUtil.getAuthToken(MSWorksApplication.getContext())).build();
return chain.proceed(newRequest);
}
else {
// the auth token is still good
return response;
}
}
}
I had this problem - if you're getting an HTTP response code that would cause Retrofit to call failure() instead of success() an exception will be thrown.
If you wrap
UserToken userToken = MobileClient.getOkraService().login(AuthUtil.getUserToken(MSWorksApplication.getContext()));
in a try/catch(RetrofitError e) you'll be able to execute code after a failure, however I've found this to be quite cumbersome and am still in the process of finding a nicer solution.

Categories

Resources