1

I am in a really bad situation.

I am using Volley on an Android application with Ruby on Rails JSON API.

Problem is there is a bug with Volley making it unable to correctly identify anything with staus 401. Basically, whenever there is a 401 status, the NetworkResponse is null and VolleyError is of type NoConnectionError.

I have searched a lot and the only way around it is to return 403 instead of 401 which can be identified correctly by Volley.

How can I change status codes on all responses to 403 if they are 401 in rails? I can't control all the actions and return 403 for example in devise premade actions.

Is there a way to finalize responses or something in rails?

Ayman Salah
  • 1,039
  • 14
  • 35
  • If you cannot control rails API status codes, try alternative solutions like extending the Request and overriding parseNetworkResponse as described in http://stackoverflow.com/questions/22948006/http-status-code-in-android-volley-when-error-networkresponse-is-null – random Aug 09 '16 at 05:17
  • I did that but when the response returns 401 the NetworkResponse is null. – Ayman Salah Aug 09 '16 at 11:14
  • You can add volley as a module and modify BasicNetwork.java to return correct response – random Aug 09 '16 at 11:16
  • @random Mind telling me how to do that? – Ayman Salah Aug 09 '16 at 11:47

3 Answers3

1

Since devise is using warden you can create a custom failureapp and set the http status which you want.

In lib/custom_failure.rb

class CustomFailure < Devise::FailureApp
  def respond
    self.status = 403 
    self.content_type = 'json'
    self.response_body = { error: "Invalid Email or password."}.to_json
  end 
end

In config/initializers/devise.rb

config.warden do |manager|
  manager.failure_app = CustomFailure
end 

In config/application.rb

config.autoload_paths << Rails.root.join('lib')
sssskkk
  • 126
  • 1
  • 5
1

401 status code might come with a blank response data and if you check this volley code line 63-75

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
            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));
        }
    }

if jsonString is blank it still tries to create a JSONObject from it new JSONObject(jsonString) which throws a JSONException

You may download volley source code, import it as module in your android studio project, add it dependency and make this correction:

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
//          Fix for an error on blank success response
//          return Response.success(new JSONObject(jsonString),
//                    HttpHeaderParser.parseCacheHeaders(response));
            if (!jsonString.trim().contentEquals("")) {
                return Response.success(new JSONObject(jsonString),
                        HttpHeaderParser.parseCacheHeaders(response));
            }
            else {
                return Response.success(new JSONObject(),
                        HttpHeaderParser.parseCacheHeaders(response));
            }
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }
}

To add Volley to your project - clone the Volley repository and set it as a library project

  1. Git clone the repository by typing the following at the command line:

    git clone https://android.googlesource.com/platform/frameworks/volley

  2. Import the downloaded source into your app project as an Android library module as described in Create an Android Library.

You may also try Prase 401 volley error message if you don't want a fix inside the imported library:

Community
  • 1
  • 1
random
  • 10,238
  • 8
  • 57
  • 101
0

I found a solution to my problem from the Ruby on Rails backend side that is generalized for the whole application which is required as a lot of controllers would also give 401 and not only devise.

I have used Rack middleware by doing the following:

app/middleware/unauthorized_to_forbidden.rb

class   UnauthorizedToForbidden
    def initialize(app)
        @app = app 
    end

    def call(env)
        status, headers, response = @app.call(env)
        if(status == 401)
            status = 403
        end
        [status, headers, response]
    end
end

config/application.rb

class Application < Rails::Application
    config.middleware.use "UnauthorizedToForbidden"
end

Now UnauthorizedToForbidden is at the bottom of the Rack stack and gets executed at the very end before the response is actually sent to the user. It basically changes the status code if it's 401 to 403.

Ayman Salah
  • 1,039
  • 14
  • 35