Varnish: How to change language of the site based on a cookie? - cookies

I have my site almost working. It works perfect with one language, but I have a cookie that sets the language. I hashed it also.
The problem is that I cant change the value of my cookie, I cant get an idea about how to do that.
My site receives a variable called "lg=1" where "1" is the language code.
I dont get the idea about how to pass that to my site, to get the "english" version and save the new cookie (with lg=1 value) again, so next time the user access without the lg=1 variable, he visits our english site, based on cookie value.
Can someody help me?
Thanky you

If you want to be able to set a cookie based on get-parameter you have two options
Set the cookie with javascript. Here is a SO answer for setting Cookie with JS
Configure Varnish to always pass requests containing "lg=" to your application so that you can set the cookie there.
sub vcl_recv {
if (req.url ~ ".*lg=") {
return (pass);
}
#Your other code in vcl_recv.....
}

You will probably need to edit your VCL file, by default something like /etc/varnish/default.vcl
When you receive a language parameter, you can set a cookie via Varnish.
Then use the value of the cookie to override the request url to the backend.
It should be something like that :
sub vcl_recv {
// Use the value of the cookie to override the request url.
if (req.http.Cookie ~ "lg") {
set req.url = req.url + "?" + req.http.Cookie;
}
// Go to VCL_error to redirect and remove the parametter.
if (req.url ~ "(?i)lg=1") {
error 802 "Remember to use the english version";
}
}
sub vcl_error {
/* Removes lg parameter and remember the english choice */
if (obj.status == 802) {
set obj.http.Set-Cookie = "lg=1; domain=." + req.http.host + "; path=/";
set obj.http.Location = req.http.X-Forwarded-Proto + "://" + req.http.host + regsub(req.url, "\?lg=1", "");
set obj.status = 302;
return(deliver);
}
}
I would prefer to use a different subdomain for each language, like that you can just redirect the user to the subdomain when you receive a parameter. By doing that you would not need to override the request.url each time.

I will use below approach to achieve:
Check lg cookie is exist or not. If not exist then set it using back-end server or varnish server.
I preferred to set language cookie using varnish instead of back-end server to avoid excessive request/load on back-end server.
Default language selection must be English i.e. "1"
Set the hash based on user language selection.It will help to maintain different cache based on language also retrieve the data from cache.
Please refer below code:
I have used IPD cookie.
backend default {
#applicable code goes here
}
sub identify_cookie{
#Call cookie based detection method in vcl_recv
if (req.http.cookie ~ "IPD=") {
set req.http.Language = regsub(req.http.cookie, "(.*?)(IPD=)([^;]*)(.*)$", "\3");
}
}
C{
#used to set persistent(9+ years) cookie from varnish server.
const char* persistent_cookie(char *cookie_name){
time_t rawtime;
struct tm *info;
char c_time_string[80];
rawtime = time(NULL) * 1.2; /*Added 9 years*/;
info = localtime(&rawtime);
strftime(c_time_string,80,"%a, %d-%b-%Y %H:%M:%S %Z", info);
char * new_str ;
if((new_str = malloc(strlen(cookie_name)+strlen(c_time_string)+1)) != NULL){
new_str[0] = '\0'; // ensures the memory is an empty string
strcat(new_str,cookie_name);
strcat(new_str,c_time_string);
} else {
syslog(LOG_INFO,"Persistent cookie malloc failed!\n");
}
return new_str;
}
}C
sub vcl_recv {
call identify_cookie; #Used to get identify cookie and get its value
if(!req.http.Cookie ~ "IPD"){
C{
VRT_SetHdr(sp, HDR_REQ, "\006X-IPD:",persistent_cookie("IPD=1; domain=yourdomain.com; path=/; Expires="),vrt_magic_string_end);
}C
}
}
sub vcl_fetch {
set beresp.http.Set-Cookie = req.http.X-IPD; #used for debug purpose only.Check cookie in response header
}
sub vcl_backend_response {
#applicable code goes here
}
sub vcl_deliver {
#applicable code goes here
set resp.http.X-Cookie = "Cookies Set ("req.http.X-IPD")"; #used for debug purpose only.Check cookie in response header
}
sub vcl_error {
#applicable code goes here
}
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
}
if(!req.http.Language){
req.http.Language = 1 #default english language
}
hash_data(req.http.Language); # make different hash for different language to avoid cache clashing
return(hash);
}
sub vcl_pipe {
#applicable code goes here
}
sub vcl_pass {
#applicable code goes here
}
Note: Please ensure to change cookie name only.Regular expression supports to retrive cookie value from multiple cookies without considering its order

Related

Adding a cookie to DocumentRequest

Using AngleSharp v 0.9.9, I'm loading a page with OpenAsync which sets a bunch of cookies, something like:
var configuration = Configuration.Default.WithHttpClientRequester().WithCookies();
var currentContext = BrowsingContext.New(configuration);
// ....
var doc = context.OpenAsync(url, token);
This works fine and I can see the cookies have been set. For example, I can do this:
var cookieProvider = currentContext.Configuration.Services.OfType<ICookieProvider>().First() as MemoryCookieProvider;
And examine it in the debugger and see the cookies in there (for domain=.share.state.nm.us)
Then I need to submit a post:
var request = new DocumentRequest(postUrl);
request.Method = HttpMethod.Post;
request.Headers["Content-Type"] = "application/x-www-form-urlencoded";
request.Headers["User-Agent"] = userAgent;
//...
Which eventually gets submitted:
var download = loader.DownloadAsync(request);
And I can see (using Fiddler) that it's submitting the cookies from the cookieProvider.
However, I need to add a cookie (and possible change the value in another) and no matter what I try, it doesn't seem to include it. For example, I do this:
cookieProvider.Container.Add(new System.Net.Cookie()
{
Domain = ".share.state.nm.us",
Name = "psback",
Value = "somevalue",
Path = "/"
});
And again I can examine the cookieProvider in the debugger and see the cookie I set. But when I actually submit the request and look in fiddler, the new cookie isn't included.
This seems like it should be really simple, what is the correct way to set a new cookie and have it included in subsequent requests?
I think there are two potential ways to solve this.
either use document.Cookie for setting a new cookie (would require an active document that already is at the desired domain) or
Use a Filter for getting / manipulating the request before its send. This let's you really just change the used cookie container before actually submitting.
The Filter is set in the DefaultLoader configuration. See https://github.com/AngleSharp/AngleSharp/blob/master/src/AngleSharp/ConfigurationExtensions.cs#L152.

Liferay : unable to read full value from cookies in Controller

I want read value from cookie using Java code.
Example:
I have store value in cookie . like email=abc#xyz.com
When I am trying to fetch email value from cookie using below code I am only get "abc". But I want full value "abc#xyz.com"
I am using below code
Cookie[] cookies = renderRequest.getCookies();
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
System.out.print("Name : " + cookie.getName( ) + ", ");
System.out.println("Value: " + cookie.getValue( ));
}
I'm not sure if the RenderRequest gives you the same cookies as the HttpServletRequest: After all, it's a portlet-request. If you have set the value yourself, and you're not getting the same value back, you probably made a mistake encoding the value when you set it.
Also, as you're obviously in a render request handler, that might be the request of someone who is logged in anyway, and there's no need to set a specific cookie: You can just get the value for the currently signed in user (unless you're looking for somebody else's mail address - however that gets stored in the cookie)

varnish split url and change url

Is there a way to split url on varnish or change url structure with it.
I know regsub or regsuball support that but they are not enough in my case.
I would like to change a url and redirect it to another domain.
For example:
http://aaa.test.com/sport/99244-article-hyun-jun-suku-kapa.html?
to redirect below address
http://m.test.com/article-hyun-jun-suku-kapa-sport-99244/
I added some lines in vcl file to do that
set req.http.xrul=regsuball(req.url,".html",""); "clear .html"
set req.http.xrul=regsub(req.http.xrul,"(\d+)","\1"); find numbers --article ID =99244
I can rid of the article ID with
set req.http.xrul=regsub(req.http.xrul,"(\d+)","");
but cannot get just only article ID
set req.http.xrul=regsub(req.http.xrul,"(\d+)","\1"); or any other method
Does varnish support split the url with "-" pattern thus I could redesign the url? Or can we get only articleID with regsub?
Is this what you want to achieve?
set req.http.X-Redirect-URL = regsuball(req.url,"^/([^/]*)/([0-9]+)-([^/]+)\.html$","http://m.test.com/\3-\1-\2");
This is working code tailored to example you provided, just one level of section placement.
If you want to support more levels of sections, you only have to adjust regexp a bit and replace / to - in second step:
set req.http.X-Redirect-URL = "http://m.test.com/" + regsuball(regsuball(req.url, "^/(.*)/([0-9]+)-([^/]+)\.html$", "\3-\1-\2"), "/", "-");
Maybe you need one more refinement. What if URL doesn't match you pattern? X-Redirect-URL will be the very same value as req.url is. You definitely don't want redirect loop, so I suggest to add mark character to the begin of X-Redirect-URL and then test for it.
Let's say:
set req.http.X-Redirect-URL = regsuball(regsuball(req.url, "^/(.*)/([0-9]+)-([^/]+)\.html$", "#\3-\1-\2"), "/", "-");
if(req.http.X-Redirect-URL ~ "^#") {
set req.http.X-Redirect-URL = regsuball(req.http.X-Redirect-URL, "#", "http://m.test.com/");
return(synth(391));
} else {
unset req.http.X-Redirect-URL;
}
and for all cases, you need in vcl_synth:
if (resp.status == 391) {
set resp.status = 301;
set resp.http.Location = req.http.X-Redirect-URL;
return (deliver);
}
Hope this helps.

Add cookie for Xdebug in Paw

I debug my API using Xdebug and PHPStorm's debugging features. For this to work, the client needs a cookie named XDEBUG_SESSION.
When using Postman, I used to use a Chrome extension to add this cookie, and Postman's cookie interception feature to get this to work in Postman (since it's a sandboxed app).
However, I cannot create cookies in Paw. So, as a workaround, I modified the API response cookie to have the key as XDEBUG_SESSION and value as PHPSTORM, and debugging worked fine. However, this is not ideal as I would also like to set the expiry date to something far in the future (which I can't in Paw).
So, my questions are:
Is there a way to add custom cookies in Paw?
If not, is there a way to to edit the expiry date for an existing cookie (considering that name, value, domain and path are editable)?
Are there any other alternatives to achieve my objective?
I just managed to achieve this exact thing to debug my APIs with Paw (2.1.1).
You just have to Add a Header with the name Cookie and a value of Cookies picked from the dropdown that will appear. You then have to insert a Cookie named XDEBUG_SESSION with a value of PHPSTORM inside the Cookies value of the header just created.
To be more clear, you can see it in the screenshot below:
I messed around with it to see if I could create an extension. I wasn't able to, and the below does not work but thought I'd share in case anyone knows the missing pieces.
First off, there is no extension category (generator, dynamic value, importer) that this functionality falls into. I tried to make use of the dynamic value category but was unsuccessful:
CookieInjector = function(key, value) {
this.key = "XDEBUG_SESSION";
this.value = "PHPSTORM";
this.evaluate = function () {
var f = function (x,y) {
document.cookie=this.key+"="+this.value;
return true;
}
return f(this.key, this.value);
}
// Title function: takes no params, should return the string to display as
// the Dynamic Value title
this.title = function() {
return "Cookie"
}
// Text function: takes no params, should return the string to display as
// the Dynamic Value text
this.text = function() {
return this.key+"="+this.value;
}
}
// Extension Identifier (as a reverse domain name)
CookieInjector.identifier = "com.luckymarmot.PawExtensions.CookieInjector";
// Extension Name
CookieInjector.title = "Inject Cookie Into Cookie Jar";
// Dynamic Value Inputs
CookieInjector.inputs = [
DynamicValueInput("key", "Key", "String"),
DynamicValueInput("value", "Value", "String")
]
// Register this new Extension
registerDynamicValueClass(CookieInjector);
The main thing stopping this from working is I'm not sure how the request is built in PAW and not sure how to attach the cookie. I've looked through the documentation here: https://luckymarmot.com/paw/doc/Extensions/Reference/Reference, and can't find what I need.

jmeter - counting cookie values

I'm playing around with jmeter to validate a bug fix.
Server logic sets the cookie "mygroup" it can be either "groupa" or "groupb". I want to be able fire a series of requests and be able to see there is a proper balanced distribution between the values of this cookie. Ie make 100 requests and 50 times the cookie will be set to "groupa" and "groupb".
I'm a bit stuck on this. I currently have the following. I can see the cookies being set in the results tree but I'd like to be able to display the a table with the version and the number of requests of each.
Thread Group
HTTP Cookie Manager
HTTP Request
View Results Tree
Within the results tree I can see Set-Cookie: mygroup="groupa" and also sometimes mygroup="groupb" how do I tabulize this ??
You can have cookies values exported as JMeter variables by setting:
CookieManager.save.cookies=true
in user.properties.
Add a Cookie Manager to your Test Plan.
In this case you will have the var COOKIE_mygroup set by JMeter.
You can then count it like this using a JSR223 Sampler + Groovy (add groovy-all-version.jar in jmeter/lib folder:
String value = vars.get("COOKIE_mygroup");
Integer counterB = vars.getObject("counterB");
Integer counterA = vars.getObject("counterA");
if(counterA == null) {
counterA = new Integer(0);
vars.putObject("counterA", counterA);
}
if(counterB == null) {
counterB = new Integer(0);
vars.putObject("counterB", counterB);
}
if(value.equals("groupa")) {
counterA = counterA+1;
vars.putObject("counterA", counterA);
} else {
counterB = counterB+1;
vars.putObject("counterB", counterB);
}
Asyou have only one thread, at end of loop you can then compare the 2 values or just display the value:
add a debug sampler
add a view tree result
Run test plan, in view result tree click on debug sampler , select response tab and you should have your values