OkHttp CookieJar saveFromResponse method - retrofit2

I created a simple project which using CookieJar. Now I am trying to understand when saveFromResponse method works. But I see in my logs that loadForRequest works fine, but I doesn't see saveFromResponse logs. Why? At what time of process this method works? Can we use only intercept method if we works with cookies or may be we have a special situation for using CookieJar?
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new ReceivedCookiesInterceptor())
.cookieJar(new CookieJar() {
private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();
#Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
Log.d(TAG,"saveFromResponse");
cookieStore.put(url, cookies);
}
#Override
public List<Cookie> loadForRequest(HttpUrl url) {
Log.d(TAG,"loadForRequest");
List<Cookie> cookies = cookieStore.get(url);
return cookies != null ? cookies : new ArrayList<Cookie>();
}
})
.build();
Request request = new Request.Builder()
.url("http://www.publicobject.com/helloworld.txt")
.build();
Response response = client.newCall(request).execute();
response.body().close();

I know it's a bit late, but I was struggling with the exact same issue and then I realised that saveFromResponse is only called on new cookies. This means that all the cookies you set on loadForRequest are not received in saveFromResponse.
That's the behaviour I could infer, but I'm not sure if it is the one that it should be, as this way you can't get cookie value updates from remote server.
Did you experienced the behaviour that only on the first request after OkHttpClient creation the cookies are received and not on the rest of the requests?
Please, someone with more knowledge that can shed some light?

Related

Dotnet Core 2.0.3 Migration | Encoding unable to translate bytes [8B]

Im not sure if this should just go direct to the github but I thought id check here first if anyone has encountered this issue before.
I recently have upgraded one of my apps to use dot net 2.0.3 From 1.1.4.
Everything works fine locally but when I deploy to my app service in azure I get the following exception.
System.Text.DecoderFallbackException: Unable to translate bytes [8B] at index 1 from specified code page to Unicode.
The code that calls it is a httpclient that talks between the apps.
public async Task<T1> Get<T1>(string url, Dictionary<string, string> urlParameters = null) where T1 : DefaultResponse, new()
{
var authToken = _contextAccessor.HttpContext.Request.Cookies["authToken"];
using (var client = new HttpClient().AcceptJson().Acceptgzip().AddAuthToken(authToken))
{
var apiResponse = await client.GetAsync(CreateRequest(url, urlParameters));
T1 output;
if (apiResponse.IsSuccessStatusCode)
{
output = await apiResponse.Content.ReadAsAsync<T1>();
//output.Succeeded = true;
}
else
{
output = new T1();
var errorData = GlobalNonSuccessResponseHandler.Handle(apiResponse);
output.Succeeded = false;
output.Messages.Add(errorData);
}
return output;
}
}
public static HttpClient AcceptJson(this HttpClient client)
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
public static HttpClient Acceptgzip(this HttpClient client)
{
// Commenting this out fixes the issue.
//client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("gzip"));
client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("deflate"));
return client;
}
public static HttpClient AddAuthToken(this HttpClient client, string authToken)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
return client;
}
Im a bit stumped as to whats going on.
So I have 2 apps which we call client and server from now on.
Client uses the above code to talk to the server.
Locally this is fine on azure not so, this all worked fine before upgrading.
So I setup the client locally to talk to the server on azure I was able to replicate the issue.
I had a look at the response in fiddler and it is able to correctly decode it.
If anyone has any idea where I should look and has seen it before any info would be great :D.
UPDATE 1
So after some more digging I decided to remove gzip and then everything started working.
client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("gzip"));
Can anyone explain this?
8B can be a second byte of multi-byte UTF8 character. The DecoderFallbackException tells that you’re interpreting the data as some other encoding. Probably Latin-1 which doesn’t have 8B character.
In fiddler, you should look at the content-type HTTP header in the response. If it says application/json or application/json; charset=utf-8, it’s probably a bug in .NET, because even without charset=utf-8 RFC 4627 says the default encoding is already UTF-8.
If it says something else, I would try changing the server so it sends the correct content-type header in the response.

Using Azure B2C with an MVC app gets into infinite loop resulting with Bad Request - Request Too Long Http 400 error

So I've built and published a new website that uses Azure B2C as the authentication mechanism.
What I found was that the login and sign would work fine for a while. But after a period of time, say couple of hours after visiting the site post deployment, I would find that on login or signup, after successful authentication, instead of being redirected back to the return url set up in the b2c configuration, my browser would get caught between an infinite loop between the post authentication landing page that is protected with an authorise attribute and the Azure B2C Login page, before finally finishing with Http 400 error message with the message - Bad Request - Request too long.
I did some googling around this and there are number of posts that suggest that the problem is with the cookie, and that deleting the cookie should resolve the issue. This is not the case. The only thing I have found to fix this is restarting the application on the webserver, or waiting say 24 hours for some kind of cache or application pool to reset. Anyone has any ideas what's going on here?
Ok, I think I may have found the answer.
Looks like there is an issue with Microsoft.Owin library and the way it sets cookies. Writing directly to System.Web solves this problem according to this article.
There are three suggested solutions:
Ensure session is established prior to authentication: The conflict between System.Web and Katana cookies is per request, so it may be possible for the application to establish the session on some request prior to the authentication flow. This should be easy to do when the user first arrives, but it may be harder to guarantee later when the session or auth cookies expire and/or need to be refreshed.
Disable the SessionStateModule: If the application is not relying on session information, but the session module is still setting a cookie that causes the above conflict, then you may consider disabling the session state module.
Reconfigure the CookieAuthenticationMiddleware to write directly to System.Web's cookie collection.
I will opt for the third option, which is to overwrite the default Cookie AuthenticationMiddleware, as they have suggested below.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
// ...
CookieManager = new SystemWebCookieManager()
});
public class SystemWebCookieManager : ICookieManager
{
public string GetRequestCookie(IOwinContext context, string key)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
var cookie = webContext.Request.Cookies[key];
return cookie == null ? null : cookie.Value;
}
public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (options == null)
{
throw new ArgumentNullException("options");
}
var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
bool expiresHasValue = options.Expires.HasValue;
var cookie = new HttpCookie(key, value);
if (domainHasValue)
{
cookie.Domain = options.Domain;
}
if (pathHasValue)
{
cookie.Path = options.Path;
}
if (expiresHasValue)
{
cookie.Expires = options.Expires.Value;
}
if (options.Secure)
{
cookie.Secure = true;
}
if (options.HttpOnly)
{
cookie.HttpOnly = true;
}
webContext.Response.AppendCookie(cookie);
}
public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (options == null)
{
throw new ArgumentNullException("options");
}
AppendResponseCookie(
context,
key,
string.Empty,
new CookieOptions
{
Path = options.Path,
Domain = options.Domain,
Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
});
}
}
I will give that a crack, and post my results back here.

Can't send volley post request from android phone

I'm using Volley to send an http post request with parameters from my android app to my local server running in http://192.168.1.4:3000/battery_signal_report
I'm pretty sure the server is running properly (I checked it with Postman successfully).
also, I successfully sent the request through Android Studio's Emulator using ip 10.0.2.2
Trying to make it work, i used various request implementations including JsonObjectRequest, StringRequest and the custom request described here: Volley JsonObjectRequest Post request not working
Also, I've read somewhere that Volley post requests have some problems with the request header, so i tried to override it in different ways.
Nothing works. onErrorResponse is called every time with an empty VolleyError input.
I've fairly new to android development, so any insights would be much appreciated.
Thanks in advance.
For anyone else coming across this, you need to forget about the header override and setup your own getBodyContentType() and getBody() methods. Follow this pattern:
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, successListener, errorListener) {
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";//set here instead
}
#Override
public byte[] getBody() {
try {
Map<String, String> params = yourObject.getMappedParams();
JSONObject json = new JSONObject(params);
String requestBody = json.toString();
return requestBody == null ? null : requestBody.getBytes("utf-8");
} catch (UnsupportedEncodingException uee) {
return null;
}
}
};

Set Cookie for UIWebView requests

I want to embed an UIWebView into my MonoTouch application for an area that is not yet implemented natively.
In order to authenticate with the website I want to set a cookie containing a key for the current session.
I tried creating a NSDictionary with the properties for the Cookie and then create a new NSHttpCookie and add it to the NSHttpCookieStorage.SharedStorage.
Sadly the cookie seems to be empty and not used for the request.
An example of how to build be cookie with properties and a comment on whether or not this is the simplest way to do this would be greatly appreciated.
Following Anuj's bug report I felt bad about how many lines of code were required to create the cookies. So the next MonoTouch versions will have new constructors for NSHttpCookie, similar to System.Net.Cookie that will allow you do to something like:
// this ctor requires all mandatory parameters
// so you don't have to guess them while coding
var cookie = new NSHttpCookie ("iherd", "ulikecookies", "/", "yodawg.com");
You'll even be able to create a NSHttpCookie from a .NET System.Net.Cookie.
Note: Never hesitate to fill a bug report when an API proves to be way more complicated than it should be :-)
Whenever I need to send cookies and params up to the server I use something like RestSharp or Hammock and then pass the response.Content value into UIWebView's loadHtmlString method:
//setup cookies and params here
var response = client.Execute(req);
_webView = new UIWebView();
_webView.LoadHtmlString(response.Content, new NSUrl(baseUrl));
The NSDictionary API is fairly trivial too:
var props = new NSMutableDictionary ();
props.Add (NSHttpCookie.KeyOriginURL, new
NSString("http://yodawg.com"));
props.Add (NSHttpCookie.KeyName, new NSString("iherd"));
props.Add (NSHttpCookie.KeyValue, new NSString("ulikecookies"));
props.Add (NSHttpCookie.KeyPath, new NSString("/"));
AFAIK every application has its own cookie storage so try to use this code before rendering the page in the UIWebView
NSHttpCookie cookie = new NSHttpCookie()
{
Domain = "yourdomain.com",
Name = "YourName",
Value = "YourValue" //and any other info you need to set
};
NSHttpCookieStorage cookiejar = NSHttpCookieStorage.SharedStorage;
cookiejar.SetCookie(cookie);
I'm not in a MAC right now so im not able to test it hope this helps
okay sorry, i wasn't able to test it before posting, anyways I won't get home until tonight so give this a spin
var objects = new object[] { "http://yoururl.com", "CookieName", "CookieValue", "/" };
var keys = new object[] { "NSHTTPCookieOriginURL", "NSHTTPCookieName", "NSHTTPCookieValue", "NSHTTPCookiePath" };
NSDictionary properties = (NSDictionary) NSDictionary.FromObjectsAndKeys(objects, keys);
NSHttpCookie cookie = NSHttpCookie.CookieFromProperties(properties);
NSHttpCookieStorage.SharedStorage.SetCookie(cookie);
As you stated above, in the case that doesn't work might be a bug on monotouch binding so you can bind it manually by doing this
var objects = new object[] { "http://yoururl.com", "CookieName", "CookieValue", "/" };
var keys = new object[] { "NSHTTPCookieOriginURL", "NSHTTPCookieName", "NSHTTPCookieValue", "NSHTTPCookiePath" };
NSDictionary properties = (NSDictionary) NSDictionary.FromObjectsAndKeys(objects, keys);
NSHttpCookie cookie = (NSHttpCookie) Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(new Class("NSHTTPCookie").Handle, new Selector("cookieWithProperties:").Handle, properties.Handle))
NSHttpCookieStorage.SharedStorage.SetCookie(cookie);
also don't forget to include using MonoTouch.ObjCRuntime; if manually binding it
if manually binding works please don't forget to post a bug report on https://bugzilla.xamarin.com/
Alex
I’ve wrote the NSMutableURLRequest+XSURLRequest catagory and XSCookie class to do this;-) http://blog.peakji.com/cocoansurlrequest-with-cookies/
This might give you a lead. Previously I used a similar strategy to make a
WebRequest to a site and collect cookies which were stored in the .Net/Mono CookieStore. Then when loading a url in the UIWebView I copied those cookies over to the NSHttpCookieStorage.
public NSHttpCookieStorage _cookieStorage;
/// <summary>
/// Convert the .NET cookie storage to the iOS NSHttpCookieStorage with Login Cookies
/// </summary>
void DotNetCookieStoreToNSHttpCookieStore()
{
foreach (Cookie c in _cookies.GetCookies(new Uri(UrlCollection["Login"], UriKind.Absolute))) {
Console.WriteLine (c);
_cookieStorage.SetCookie(new NSHttpCookie(c));
}
}

How can I get GWT RequestFactory to with in a Gadget?

How can I get GWT RequestFactory to with in a Gadget?
Getting GWT-RPC to work with Gadgets is explained here.
I'm looking for a analogous solution for RequestFactory.
I tried using the GadgetsRequestBuilder, so far I've managed to get the request to the server using:
requestFactory.initialize(eventBus, new DefaultRequestTransport() {
#Override
protected RequestBuilder createRequestBuilder() {
return new GadgetsRequestBuilder(RequestBuilder.POST,
getRequestUrl());
}
#Override
public String getRequestUrl() {
return "http://....com/gadgetRequest";
}
});
But I end up with the following error:
java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at java.lang.String.charAt(String.java:694)
at com.google.gwt.autobean.server.impl.JsonSplittable.create(JsonSplittable.java:35)
at com.google.gwt.autobean.shared.impl.StringQuoter.split(StringQuoter.java:35)
at com.google.gwt.autobean.shared.AutoBeanCodex.decode(AutoBeanCodex.java:520)
at com.google.gwt.requestfactory.server.SimpleRequestProcessor.process(SimpleRequestProcessor.java:121)
The general approach for sending a RequestFactory payload should be the same as RPC. You can see the payload that's being received by the server by running it with the JVM flag -Dgwt.rpc.dumpPayload=true. My guess here is that the server is receiving a request with a zero-length payload. What happens if you set up a simple test involving a GadgetsRequestBuilder sending a POST request to your server? Do you still get the same zero-length payload behavior?

Resources