I am sending a request to a website's webpage's url using OkHttpClient and storing the cookie it gives by the following method which I got from stackoverflow only.
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(this));
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.build();
Request request = new Request.Builder()
.url("www.example.com/homePage")
.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0")
.build();
It is necessary to store the cookie otherwise the website redirects the request to a timeout page.
Then, I see the html of the page to check whether I reached the correct URL.
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
textView.setText("Failed to get response");
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
//String myResponse contains the html of the webpage
final String myResponse = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(myResponse);
}
});
}
}
});
Now, I make another Request variable in a similar fashion to the URL "www.example.com/loginPage" and try to see the html but it redirects me to the timeout page because the request is made without sending the cookie which I got from the homePage.
So, in short, how can I get a cookie from "www.example.com/cookieProviderPage" and store it and then use that cookie for all further requests to all pages of that website. Pages of that website have different urls like "www.example.com/cookieRequiredPage1", "www.example.com/cookieRequiredPage2" etc.
P.S. - I have checked many stackoverflow questions related to cookies but I am unable to implement the them specifically to my case.
Cookies added with Command
new OkHttpClient.Builder()
.cookieJar(cookieJar)
are loaded depending on the CookieJar.loadForRequest method. You must check, how your implementation of the interface CookieJar implemented the loadForRequest method. If cookies are just loaded for exact the same url the cookies originally come from, you have the error.
If the cookies come from "www.example.com/cookieProviderPage" and you want to supply the cookies for the request "www.example.com/loginPage", your CookieJar implementation may only supply the cookies to requests with the url "www.example.com/cookieProviderPage".
This is for example the case, if Cookie.matches is used to the get the cookies for the request. Cookie.matches compares domain name and path of the url.
Related
I am trying to retrieve some JSON data using OkHttp in Android Studio from the URL: www.duolingo.com/vocabulary/overview
Before I can get the data using this URL, it requires me to Login into the Duolingo server first (which makes sense since I want it to return data from my profile) so I make a POST request with my credentials using OkHttp. This is my code to achieve that:
OkHttpClient client = new OkHttpClient();
String postUrl = "https://www.duolingo.com/2017-06-30/login?fields=";
String getUrl = "https://www.duolingo.com/vocabulary/overview";
String credentials = "{\"identifier\": \"something#email.com\", \"password\": \"Password\"}";
RequestBody body = RequestBody.create(credentials, MediaType.parse("application/json; charset=utf-8"));
Request request = new Request.Builder()
.url(postUrl)
.post(body)
.build();
client.newCall(request).enqueue(new Callback()
{
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e)
{
Log.i("TAG", "ERROR - " + e.getMessage());
}
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException
{
if (response.isSuccessful())
{
Log.i("LOG", "LOGGED IN");
}
else
{
Log.i("LOG", "FAILED - " + response.toString());
}
}
});
The Response is successful and I get a 200 Response Code.
Now since I have Logged In, I want to make a GET Request to the URL mentioned above to get the JSON Data. Problem is I do not know how to make a GET Request in succession to the POST Request I just made. OkHttp treats the 2 consecutive requests as separate while I want them to be treated as the same session.
Someone told me Cookies can help but I am totally oblivious to that and how they work. All help is appreciated!
This question basically wants to know how to use stored cookies for subsequent request. The long text below is just for example. Basic question is how to use the same cookie for all requests on a particular website.
Basically I am trying to reach the login page of a website within the android app. The website works the following way.
There are 3 urls to consider.
1 -> "http://www.example.com/timeoutPage"
2 -> "http://www.example.com/mainPage"
3 -> "http://www.example.com/loginPage"
The two main points to consider are
(1) If we directly go to the 3rd url (loginPage), it redirects to the 1st url(timeoutPage). The timeoutPage has a button to go to the mainPage.
(2) If we go to the 2nd url (mainPage), it gives us a cookie. Now, after getting the cookie, when we visit the 3rd url (loginPage), we are able to access it. The loginPage has a captcha so it's essential to visit it(loginPage) in order to login.
Without the cookie, which is given at visiting 2nd url(mainPage), we cannot directly access 3rd url(loginPage).
so what i am doing is to make a ClearableCookieJar and attach it to OkHttpClient.
OkHttpClient client;
ClearableCookieJar cookieJar;
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(this));
client = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.build();
Request request = new Request.Builder()
.url("http://www.example.com/mainPage")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
textView.setText("Failed to get response");
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
final String myResponse = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(myResponse);
}
});
}
}
});
Everthing is fine till here as i am able to print the html of mainPage in my textview.
Problem starts here when i make another request for the loginPage.
request = new Request.Builder()
.url("http://www.example.com/loginPage")
.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
textView.setText("Failed to get response");
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
final String myResponse2 = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(myResponse2);
}
});
}
}
});
Here i again make a request to the loginPage but i reach the timeoutPage. How should i make the request for the loginPage url so that my request sends the cookie which i stored in the cookieJar while making a request to mainPage. One way i thought of was
request = new Request.Builder()
.url("http://www.example.com/loginPage")
.addHeader("Cookie", cookieStringGivenAtMainPage)
.build();
But i don't know how to access that cookieStringGivenAtMainPage. How should i reach that loginPage?
I print the html of the response to see if i reached the correct page.
It seems the answer you want to know is the singleton pattern.
Please refer to below sample code. I got it from kakao developer site about 3 years ago.
public class NetworkManager {
private static NetworkManager instance;
private OkHttpClient client;
/**
* By using Singleton Pattern we can share cookie, client values.
**/
private NetworkManager() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
Context context = GlobalApplication.getGlobalApplicationContext();
ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context));
builder.cookieJar(cookieJar);
builder.followRedirects(true);
builder.addInterceptor(new RedirectInterceptor());
File cacheDir = new File(context.getCacheDir(), "network");
if (!cacheDir.exists()) {
cacheDir.mkdir();
}
Cache cache = new Cache(cacheDir, 10 * 1024 * 1024);
builder.cache(cache);
builder.connectTimeout(30, TimeUnit.SECONDS);
builder.readTimeout(10, TimeUnit.SECONDS);
builder.writeTimeout(10, TimeUnit.SECONDS);
client = builder.build();
}
public static NetworkManager getInstance() {
if (instance == null) {
instance = new NetworkManager();
}
return instance;
}
public OkHttpClient getClient() {
return client;
}
}
In addition below is sample usage.
OkHttpClient client = NetworkManager.getInstance().getClient();
RequestBody formBody = new FormBody.Builder()
.add("userId", getTargetUserId())
.build();
Request request = new Request.Builder()
.url("www.test.com/insert.php")
.post(formBody)
.build();
client.newCall(request).enqueue(callback);
Glide 4.10.0
When i try to load image into imageview with glide with custom cookie headers it throws 403 error at httpurlfetcher.java class while trying to read inputstream, but when i send the same request with okhttpclient i get proper response with response code 200, and even in browser i am able to view image.
In logs, i get file not found exception
java.io.FileNotFoundException: https://d2q89b5pewg0ry.cloudfront.net/images/hikup.jpg
But when i debug i get 403 in httpurlfetcher.java class
1.) Glide -> image is not loaded into imageview
List<String> cookies = Session.getInstance().getCookies(); GlideUrl glideUrl = new GlideUrl("https://d2q89b5pewg0ry.cloudfront.net/images/hikup.jpg", new LazyHeaders.Builder() .addHeader("Cookie", cookies.get(0)) .addHeader("Cookie", cookies.get(1)) .addHeader("Cookie", cookies.get(2)) .build()); Glide.with(this).load(glideUrl).error(android.R.color.white).into(profilePic);
2.) OkHttpClient -> here i get response
OkHttpClient client = new OkHttpClient(); final Request request = new Request.Builder() .addHeader("Cookie", cookies.get(0)) .addHeader("Cookie", cookies.get(1)) .addHeader("Cookie", cookies.get(2)) .url("https://d2q89b5pewg0ry.cloudfront.net/images/hikup.jpg") .build(); client.newCall(request).enqueue(new Callback() { #Override public void onFailure(Call call, IOException e) { runOnUiThread(() -> { Toast.makeText(ProfileActivity.this,e.toString(),Toast.LENGTH_LONG).show(); }); } #Override public void onResponse(Call call, final okhttp3.Response response) { runOnUiThread(() -> { Toast.makeText(ProfileActivity.this, response.toString(), Toast.LENGTH_LONG).show(); }); } });
When i debug loadDataWithRedirects method in httpurlfetcher.java class
urlConnection = connectionFactory.build(url);
// here i put a breakpoint and evaluate urlConnection.getResponseCode(), i get 403 how am i getting responsecode even before connection? headers are added in next line?
for (Map.Entry<String, String> headerEntry : headers.entrySet()) { urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue()); } urlConnection.setConnectTimeout(timeout); urlConnection.setReadTimeout(timeout); urlConnection.setUseCaches(false); urlConnection.setDoInput(true); // Stop the urlConnection instance of HttpUrlConnection from following redirects so that // redirects will be handled by recursive calls to this method, loadDataWithRedirects. urlConnection.setInstanceFollowRedirects(false); // Connect explicitly to avoid errors in decoders if connection fails. urlConnection.connect(); // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352. stream = urlConnection.getInputStream();
Issue has been resolved, i used okhttp integration library with interceptor to set headers. Issue was with lazy headers, when same key exists, in my case "Cookie", all the headers with that key get combined, whereas AWS Cloudfront needs 3 separate Cookie headers.
I am working on an Android app in which a log in post request is made to a webservice. The request returns a cookie which expires in 20 minutes.
Using okhttp3 and this PersistentCookieStore library, I got the cookie to be stored and subsequently added it as request header to access authentication-required get requests (e.g. personal information that are non-public).
The code goes this way,
CookieJar myCookieJar = new PersistentCookieJar(new SetCookieCache(),
new SharedPrefsCookiePersistor(this));
OkHttpClient client = new OkHttpClient.Builder().cookieJar(HttpRequests.cookieJar).build();
I then call a method like this inside an (after I have gone through another log in Async task to get the cookie) Async task to perform a get request that requires authentication,
public static String PostReq(String url, String json) {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.addHeader("Cookie", "key=value")
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
catch(Exception e){
}
}
The .addHeader("Cookie", "key=value") adds the cookie to the header to tell the webservice that I am authenticated.
Here comes my difficulty. Since the cookie expires after 20 minutes, I would like to be able to access the cookie itself to check for the expiration time and possibly redirect the user to the log in activity by calling the method,
myCookie.expiresAt()
and comparing it to
System.currentTimeMillis()
I tried to look at the PersistentCookieStore codes and found that it uses a SharedPreference with the key "CookiePersistence". I looked inside this file while my emulator was running the app and found it to be empty however.
How would I be able to access this cookie that I have obtained? Much thanks for any advice to be given.
OK, this is old, but I was facing the same problem, and here is how I fixed it.
Hold a reference to your SetCookieCache used to instantiate your CookieJar:
SetCookieCache cookieCache = new SetCookieCache();
CookieJar myCookieJar = new PersistentCookieJar(
cookieCache,
new SharedPrefsCookiePersistor(this)
);
Then use this to find your cookie and check it:
for (Cookie cookie : cookieCache) {
if (cookie.name().equals("cookie_name") && cookie.persistent()) {
//cookie is still good
break;
}
}
Or use cookie.expiresAt() to do your thing.
Thanks for your time. Im programming an Android App for School and need a Authentification Form for the Moodle Login (Server ends with /index.php).
My Goal: Get the "Set-Cookie" Header in the Response with the active Cookie in it. This is given, if the Server Status returnes "303(See Other)".
My Question: What should I post to the Login Server, to get the Status "303" (and therefore also the right Cookie) ?
I dont know, if the ".add" Method is the right or wrong or if I should send more or less to the Server.
class MoodleLogin{
public static void FirstRequest(String url) throws Exception {
final OkHttpClient client = new OkHttpClient();
//FORM BODY
RequestBody formBody = new FormBody.Builder()
.add("username", USERNAME) // Username
.addEncoded("password", PASSWORT) //Passwort
.add("token", "6f65e84f626ec97d9eeee7ec45c88303") //Security Key for Moodle mobile web service (I dont know if I need that)
.build();
// A normal Request
Request request = new Request.Builder()
.url(url)
.post(formBody)
.build();
// Asynchronous Call via Callback with onFailure and onResponse
client.newCall(request).enqueue(new okhttp3.Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.i("Internet", "request failed: " + e.toString());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) { // Server Status is not 200 - THAT IS WHAT I WANT
Log.d("Server Status", response.message().toString());
throw new IOException("Unexpected code ");
} else { // Server Status is 200(OK)
Log.d("Server Status", response.message().toString());
}
response.body().close();
}
}); // End of "onResponse"
}
This peace of Code only returns the Server Status "200" (what is wrong in my case).
Do anyone know, what I must change to get the Status "303" ? I tested it with hurl.it (A Website for HTTP Requests) and it works only if I post the "username" and "password" like normal Parameters.
Im grateful for every answer and tip !
I answered it myself. So here is the right code:
Connection.Response res = Jsoup
.connect("your Moodle-Login Page")
.data("username", username, "password", password)
.method(Connection.Method.POST)
.execute();
String Login_cookies = res.cookies().toString();
String cookie = Login_cookies.substring(1, 50);
System.out.println("COOKIES: "+cookie);