17

So, i have this code to make a POST request with volley:

public class MainActivity extends AppCompatActivity {

 Button btnSearch;
 ProgressDialog loadingDialog;
 ListView lvResult;
 String session_id;
 RequestQueue queue;
 MyCookieManager myCookieManager;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  btnSearch = (Button) findViewById(R.id.btnSearch);
  lvResult = (ListView) findViewById(R.id.lvResult);
  loadingDialog = new ProgressDialog(MainActivity.this);
  loadingDialog.setMessage("Wait.\nLoading...");
  loadingDialog.setCancelable(false);
  myCookieManager = new MyCookieManager();

  requestCookie(); //FIRST CALL TO GET SESSION ID

  btnSearch.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
    showLoading();
    requestWithSomeHttpHeaders(); //CALL TO MAKE THE REQUEST WITH VALID SESSION ID
   }
  });

 }

 public void requestCookie() {
  queue = Volley.newRequestQueue(this);
  String url = "http://myurl.com/json/";

  StringRequest postRequest = new StringRequest(Request.Method.POST, url,
   new Response.Listener < String > () {
    @Override
    public void onResponse(String response) {
     //
     String x = myCookieManager.getCookieValue();
    }
   },
   new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
     Log.d("ERROR", "Error => " + error.toString());
     hideLoading();
    }
   }
  ) {
   @Override
   public byte[] getBody() throws AuthFailureError {
    String httpPostBody = "param1=XPTO&param2=XPTO";
    return httpPostBody.getBytes();
   }

   @Override
   public Map < String, String > getHeaders() throws AuthFailureError {
    Map <String, String> params = new HashMap < String, String > ();
    params.put("User-Agent", "Mozilla/5.0");
    params.put("Accept", "application/json, text/javascript, */*; q=0.01");
    params.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    //params.put("Set-Cookie", session_id);// + " _ga=GA1.3.1300076726.1496455105; _gid=GA1.3.1624400465.1496455105; _gat=1; _gali=AguardeButton");
    //"PHPSESSID=ra0nbm0l22gsnl6s4jo0qkqci1");
    return params;
   }

   protected Response <String> parseNetworkResponse(NetworkResponse response) {
    try {
     String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
     String header_response = String.valueOf(response.headers.values());
     int index1 = header_response.indexOf("PHPSESSID=");
     int index2 = header_response.indexOf("; path");
     //Log.e(Utils.tag, "error is : " + index1 + "::" + index2);
     session_id = header_response.substring(index1, index2);

     return Response.success(jsonString, HttpHeaderParser.parseCacheHeaders(response));
    } catch (UnsupportedEncodingException e) {
     return Response.error(new ParseError(e));
    }
   }
  };

  queue.add(postRequest);
 }

 public void requestWithSomeHttpHeaders() {
  queue = Volley.newRequestQueue(this);
  String url = "http://myurl.com/json/";

  StringRequest postRequest = new StringRequest(Request.Method.POST, url,
   new Response.Listener <String> () {
    @Override
    public void onResponse(String response) {
     Log.d("Response", response);
     String x = myCookieManager.getCookieValue();
     String status = "";

     try {
      JSONObject resultObject = new JSONObject(response);
      Log.d("JSON RESULT =>", resultObject.toString());
     } catch (JSONException e) {
      Toast.makeText(MainActivity.this, "Request Error", Toast.LENGTH_SHORT).show();
      e.printStackTrace();
     }

     hideLoading();
    }
   },
   new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
     Log.d("ERROR", "Error => " + error.toString());
     hideLoading();
    }
   }
  ) {
   @Override
   public byte[] getBody() throws AuthFailureError {
    String httpPostBody = "param1=XPTO&param2=XPTO";
    return httpPostBody.getBytes();
   }

   @Override
   public Map <String, String> getHeaders() throws AuthFailureError {
    Map <String, String> params = new HashMap <String, String> ();
    params.put("User-Agent", "Mozilla/5.0");
    params.put("Accept", "application/json, text/javascript, */*; q=0.01");
    params.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    params.put("Cookie", /*myCookieManager.getCookieValue()*/ session_id + "; _ga=GA1.3.1300076726.1496455105; _gid=GA1.3.1624400465.1496455105; _gat=1; _gali=AguardeButton");
    return params;
   }
  };

  queue.add(postRequest);
 }

 private void showLoading() {
  runOnUiThread(new Runnable() {
   @Override
   public void run() {
    if (!loadingDialog.isShowing())
     loadingDialog.show();
   }
  });
 }

 private void hideLoading() {
  runOnUiThread(new Runnable() {
   @Override
   public void run() {
    if (loadingDialog.isShowing())
     loadingDialog.dismiss();
   }
  });
 }
}

If I send a valid cookie ID this return a valid JSON object else a empty object.

I tried (unsuccessfully) to set default cookie handles like

CookieManager manager = new CookieManager(); CookieHandler.setDefault(manager);

but I get a empty object.

How to put a valid cookie session ID to post request?

PiLHA
  • 2,326
  • 1
  • 24
  • 32
  • Refer this link https://developer.android.com/training/volley/request-custom.html – Rohit Parmar Jun 05 '17 at 10:24
  • @RohitParmar I already tried to implement parseNetworkResponse to receive a valid session when starting the app and then using it in the request, it did not work. Thanks. – PiLHA Jun 05 '17 at 11:51
  • You must take a look on your code. If CookieManager does not work must be an error in your android version or implementation. Anyway.. if nothing works you can try to capture the "Set-Cookie" header every time you do a request and the server responds, store it ( in memory and preferences for example) and resent it every time – Oscar Romero Jun 07 '17 at 21:16
  • @OscarRomero As I said in the comment above, I tried to make a request when starting the app to get the session ID and save it, but even so when making a new request using the ID does not work. If I make the request in the browser, get the ID and then put in the code its works. – PiLHA Jun 07 '17 at 22:04
  • Have you tried something [with this](https://developer.android.com/reference/java/net/CookieStore.html) ? – Shark Jun 07 '17 at 23:12
  • @Shark Yes, I even used the implementation of this answer https://stackoverflow.com/a/23365081/1706450 I dont understand why this does not work :/ – PiLHA Jun 08 '17 at 00:06
  • Try below way. https://stackoverflow.com/questions/16680701/using-cookies-with-android-volley-library#answer-16743595 – Amit Thakkar Jun 08 '17 at 04:33
  • Which class is instancing the `CookieStore` ? Your `Application` class, or one of your `Activity` classes? Should try keeping it in your `Application` class if the ID should not be persistable, but should be kept through the lifespan of the application. Should keep it in the `Application` class even if you wanna persist it, makes it easier to do so before app closing. – Shark Jun 08 '17 at 11:52
  • @Shark My current flow is: in `onCreate` I call the method (that is described in the question) and I use the override of `parseNetworkResponse` to get the `PHPSESSID` in the response, I get it and store it in a string, its OK. Then (in the event of a button) I make that same request by placing the PHPSESSID parameter for that string. Note: This class I posted in the previous answer gives me the same response parameters (PHPSESSID) as the parseNetworkResponse implementation but both invalid. – PiLHA Jun 08 '17 at 12:12
  • I updated the question with valid request data – PiLHA Jun 08 '17 at 12:14
  • Cookies work by URL (website) and only for that website. Are you sure you don't mean authentication token or something like that. – danny117 Jun 08 '17 at 17:36
  • @danny117 Yep. I provide a working code (with real params) in question body. Can you test? – PiLHA Jun 08 '17 at 17:42

3 Answers3

4

So the problem was getting a valid cookie. My mistake was to get it from the POST request itself. I kept the same working principle, getting the cookie when I started the application but using GET instead of POST and calling the root of the URL instead of the address where I get the JSON.

My solution looked like this:

public void requestCookie() {
  queue = Volley.newRequestQueue(this);
  String url = "http://myurl.com/";

  StringRequest getRequest = new StringRequest(Request.Method.GET, url,
   new Response.Listener <String> () {
    @Override
    public void onResponse(String response) {
     String x = myCookieManager.getCookieValue();
    }
   },
   new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
     Log.d("ERROR", "Error => " + error.toString());
     hideLoading();
    }
   }
  ) {   
   protected Response <String> parseNetworkResponse(NetworkResponse response) {
    try {
     String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
     String header_response = String.valueOf(response.headers.values());
     int index1 = header_response.indexOf("PHPSESSID=");
     int index2 = header_response.indexOf("; path");
     //Log.e(Utils.tag, "error is : " + index1 + "::" + index2);
     session_id = header_response.substring(index1, index2);

     return Response.success(jsonString, HttpHeaderParser.parseCacheHeaders(response));
    } catch (UnsupportedEncodingException e) {
     return Response.error(new ParseError(e));
    }
   }
  };

  queue.add(getRequest);
 }
PiLHA
  • 2,326
  • 1
  • 24
  • 32
1

Using cookies with Android volley library

Request class:

public class StringRequest extends com.android.volley.toolbox.StringRequest {

    private final Map<String, String> _params;

    /**
     * @param method
     * @param url
     * @param params
     *            A {@link HashMap} to post with the request. Null is allowed
     *            and indicates no parameters will be posted along with request.
     * @param listener
     * @param errorListener
     */
    public StringRequest(int method, String url, Map<String, String> params, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, listener, errorListener);

        _params = params;
    }

    @Override
    protected Map<String, String> getParams() {
        return _params;
    }

    /* (non-Javadoc)
     * @see com.android.volley.toolbox.StringRequest#parseNetworkResponse(com.android.volley.NetworkResponse)
     */
    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        // since we don't know which of the two underlying network vehicles
        // will Volley use, we have to handle and store session cookies manually
        MyApp.get().checkSessionCookie(response.headers);

        return super.parseNetworkResponse(response);
    }

    /* (non-Javadoc)
     * @see com.android.volley.Request#getHeaders()
     */
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = super.getHeaders();

        if (headers == null
                || headers.equals(Collections.emptyMap())) {
            headers = new HashMap<String, String>();
        }

        MyApp.get().addSessionCookie(headers);

        return headers;
    }
}

MyApp:

public class MyApp extends Application {
    private static final String SET_COOKIE_KEY = "Set-Cookie";
    private static final String COOKIE_KEY = "Cookie";
    private static final String SESSION_COOKIE = "sessionid";

    private static MyApp _instance;
  private RequestQueue _requestQueue;
  private SharedPreferences _preferences;

    public static MyApp get() {
        return _instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        _instance = this;
            _preferences = PreferenceManager.getDefaultSharedPreferences(this);
        _requestQueue = Volley.newRequestQueue(this);
    }

    public RequestQueue getRequestQueue() {
        return _requestQueue;
    }


    /**
     * Checks the response headers for session cookie and saves it
     * if it finds it.
     * @param headers Response Headers.
     */
    public final void checkSessionCookie(Map<String, String> headers) {
        if (headers.containsKey(SET_COOKIE_KEY)
                && headers.get(SET_COOKIE_KEY).startsWith(SESSION_COOKIE)) {
                String cookie = headers.get(SET_COOKIE_KEY);
                if (cookie.length() > 0) {
                    String[] splitCookie = cookie.split(";");
                    String[] splitSessionId = splitCookie[0].split("=");
                    cookie = splitSessionId[1];
                    Editor prefEditor = _preferences.edit();
                    prefEditor.putString(SESSION_COOKIE, cookie);
                    prefEditor.commit();
                }
            }
    }

    /**
     * Adds session cookie to headers if exists.
     * @param headers
     */
    public final void addSessionCookie(Map<String, String> headers) {
        String sessionId = _preferences.getString(SESSION_COOKIE, "");
        if (sessionId.length() > 0) {
            StringBuilder builder = new StringBuilder();
            builder.append(SESSION_COOKIE);
            builder.append("=");
            builder.append(sessionId);
            if (headers.containsKey(COOKIE_KEY)) {
                builder.append("; ");
                builder.append(headers.get(COOKIE_KEY));
            }
            headers.put(COOKIE_KEY, builder.toString());
        }
    }

}
A Maharaja
  • 1,227
  • 1
  • 11
  • 20
0

You getting cookie (Session id) in Login response, Save cookie in sharedpreference or other db, and use that to send in request.

for getting cookie from login request

 CustomStringRequest stringRequest = new CustomStringRequest(Request.Method.POST, SIGN_IN_URL,
                    new Response.Listener<CustomStringRequest.ResponseM>() {
                        @Override
                        public void onResponse(CustomStringRequest.ResponseM result) {

                            CookieManager cookieManage = new CookieManager();
                            CookieHandler.setDefault(cookieManage);

                            progressDialog.hide();
                            try {
                                //From here you will get headers
                                String sessionId = result.headers.get("Set-Cookie");
                                String responseString = result.response;

                                Log.e("session", sessionId);
                                Log.e("responseString", responseString);

                                JSONObject object = new JSONObject(responseString);

CustomStringRequest class

public class CustomStringRequest extends Request<CustomStringRequest.ResponseM> {


    private Response.Listener<CustomStringRequest.ResponseM> mListener;

    public CustomStringRequest(int method, String url, Response.Listener<CustomStringRequest.ResponseM> responseListener, Response.ErrorListener listener) {
        super(method, url, listener);
        this.mListener = responseListener;
    }


    @Override
    protected void deliverResponse(ResponseM response) {
        this.mListener.onResponse(response);
    }

    @Override
    protected Response<ResponseM> parseNetworkResponse(NetworkResponse response) {
        String parsed;
        try {
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException e) {
            parsed = new String(response.data);
        }

        ResponseM responseM = new ResponseM();
        responseM.headers = response.headers;
        responseM.response = parsed;

        return Response.success(responseM, HttpHeaderParser.parseCacheHeaders(response));
    }


    public static class ResponseM {
        public Map<String, String> headers;
        public String response;
    }

}

set cookie when add request to server..

                @Override
                public Map<String, String> getHeaders() throws AuthFailureError {
                    Map<String, String> headers = new HashMap<String, String>();

                    String session=sharedPreferences.getString("sessionId","");
                    headers.put("Cookie",session);
                    return headers;
                }
Gundu Bandgar
  • 2,593
  • 1
  • 17
  • 21
  • Did you test your answer? Did it work? Previously, as said in the comments, I had tried to make a request when starting the application to capture the cookie session and use it on another request but it did not work. I will try using shared preferences but I think the end result should not be differentiated. – PiLHA Jul 10 '17 at 13:21
  • This code is in my Project, it's working 100 %, please update your question code how you implemented, then i will post all code with changes.. – Gundu Bandgar Jul 11 '17 at 05:13
  • Can you tell how do you get ID from browser and add into code.. I think problem is in your server side, web services..., just give how you get id from browser, i will try again.. now getting response = "" – Gundu Bandgar Jul 12 '17 at 05:19