How to prevent cookies generation

Hi, I’m facing face some issue with k6, In fact systematically 1/4 call are successful the others fall down in error, below the message
{"message":"Request CSRF Token does not match with the one provided by Session","messageType":"Error","title":""}

When I check header I see that some cookies are generated by k6 and I suspect that its the reason of my issue
Cookie: JSESSIONID=5189EA4A6102C182371EF2F8BFB0C8C1; ApplicationGatewayAffinityCORS=ae99db9211e67a2bca9455e3f5926c41; ApplicationGatewayAffinity=ae99db9211e67a2bca9455e3f5926c41

How can I prevent the generation of cookie with K6, I already try solutions presents here without success ? And if you think that the cookie is not the problem, I am interested in another solution.

I don’t think this is related to k6. This is a specific error thrown by your api. Please check with the api dev(s) to confirm in which exact case this error is thrown.

And if possible can you post your script here?

I did not say that it was related to k6, I agree with you on the error thrown by the api, the team in charge of these apis asks me to do not send the JSESSIONID, is it possible with k6? if yes how?
I already try to overloaded with const jar = http.cookieJar(); without success
as you asked below my script

import http from 'k6/http';
import { group, sleep, check } from 'k6';
import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.1/index.js';
import uuid from '../resources/uuid.js'
import { ordersOrTicketsLoader, discounts } from '../resources/test-data.js';
import { Rate } from "k6/metrics";

export const options = {
   vus: 1, // 1 user looping for 1 minute
   duration: '1m',
   thresholds: {
      http_req_failed: ['rate<0.01'],   
      http_req_duration: ['p(90) < 400', 'p(95) < 600'], 
      http_reqs: ['rate<600'] 
  },
 };

const USERNAME = '**********';
const PASSWORD = '*********';
const SLEEP_DURATION = 1;
export let errorRate = new Rate("errors");

export default () => {
   let jar = http.cookieJar();
  const credentials = `${USERNAME}:${PASSWORD}`;
  const baseUrl = `https://${credentials}@endpoint`;
  const urls = {
   discount: `${baseUrl}/discount`,
   orderOrTicketLoader: `${baseUrl}/OrderLoader?synchronizedProcessing=true`,
 };
   group('Discount', (_) => {
      discounts.forEach((discount) => {
      let res =  http.post(urls.discount, JSON.stringify(discount), {
            headers: { 'Content-Type': 'application/json' },
            tags: {
               'name': 'Discount',
            }
         });
         let success = check(res, {
            'status is 200': (r) => r.status == 200,
         });
         if (!success) {
            errorRate.add(1)
         }
         sleep(SLEEP_DURATION);  
      });
   });
   group('OrderOrTicketLoader', (_) => {
      for(const [key, otlO] of Object.entries(ordersOrTicketsLoader)){
         let otl = JSON.parse(JSON.stringify(otlO));
         jar.set(null,null, null);
         let res = http.post(urls.orderOrTicketLoader, JSON.stringify(otl), jar);
            check(res, {
               'status is 200': (r) => r.status == 200
         });
         sleep(SLEEP_DURATION);  
      }
   });
};


export function handleSummary(data) {
   return {
      'stdout': textSummary(data, { indent: ' ', enableColors: true }), // Show the text summary to stdout...
   }
}

Hi @franky, welcome to the forum :slight_smile:

The behavior in k6 is a bit confusing, but I’ll try to explain below. Also make sure to read the cookies documentation to get a sense of how things work.

  • http.cookieJar() (note lowercase c) returns the reference to the cookie jar specific to the current VU. This is where you can inspect and set cookies for the VU without having to specify cookies on each request.

  • http.CookieJar() (uppercase C) is a constructor to create new local jars you can use to set cookies on each request, which would override the VU specific jar.

  • k6 doesn’t “generate” any cookies. It just sets them on the VU specific jar as returned by the server and then uses it for any subsequent requests.

In order to override cookies, you need to pass the URL as the first argument. So to empty (note: not delete!) the JSESSIONID cookie you should do:

const jar = http.cookieJar();  // Get the VU specific jar
jar.set(urls.orderOrTicketLoader, 'JSESSIONID', null);
// Note that it's not required to pass the jar here
const res = http.post(urls.orderOrTicketLoader, JSON.stringify(otl));

This would send an empty string as JSESSIONID, but not remove it from the Cookie header. Depending on how your backend interprets this, this might be sufficient. Though I think this could be a k6 improvement, to delete the cookie from the header if it’s value is null, and I’ll discuss it with the team.

If you want to remove all cookies from the request, calling jar.set(urls.orderOrTicketLoader, null, null) on the per-VU cookie jar won’t work. This would instead send a blank cookie with a blank value, but not remove any of the other cookies.

If you want to do this, you’ll need to use a local cookie jar and pass it as a parameter on each request. For example this wouldn’t send a Cookie header at all:

const jar = new http.CookieJar();  // Create a new local empty jar
const res = http.post(urls.orderOrTicketLoader, JSON.stringify(otl), { jar });

I suggest running the test with --http-debug=full, or capturing the traffic with Wireshark if possible, to see the value of the Cookie header.

Hope this helps,

Ivan

Hi Imiric,

Thanks for you feedback , I tried below

And indeed I have a JSESSIONID to null but a second one appears as you can see on request header below, I have the feeling that it is not possible to have the JSESSIONID at null :frowning:

 Request:
> POST /orderOrTicketLoader
> Host: host.com
> User-Agent: k6/0.37.0 (https://k6.io/)
> Content-Length: 906
> Authorization: Basic xxxxxxxxxxxj0rU2g1NFo=
> Cookie: **JSESSIONID=; JSESSIONID=00221EF1B1F54A32D18DCB944CE9778A;** ApplicationGatewayAffinityCORS=ae99db9211e67a2bca9455e3f5926c41; ApplicationGatewayAffinity=ae99db9211e67a2bca9455e3f5926c41
> Accept-Encoding: gzip

Maybe you can try constructing a new http.CookieJar() from http.cookieJar() by copying each cookie expect JSESSIONID and attaching to the http request the newly constructed cookie.

1 Like

@franky That’s strange, it works in this example:

import http from 'k6/http';

export default function () {
  http.get('https://httpbin.test.k6.io/cookies/set?one=1&two=2');
  const jar = http.cookieJar();  // get the VU specific jar
  jar.set('https://httpbin.test.k6.io/cookies', 'one', null);
  const res = http.get('https://httpbin.test.k6.io/cookies');
  console.log(JSON.stringify(res.json().cookies));
}

The second request sends Cookie: one=; two=2.

Are you sure you’re not making another request after calling set() that resets it? :confused:

But like @rdt.one mentioned :bow:, you can create a new local jar (http.CookieJar()), get the cookies you need from the VU jar with jar.cookiesForURL() except JSESSIONID, and pass the local jar as a parameter to each request.

I created issue #2476 to add the functionality to delete cookies, so feel free to watch it for updates. Though this might take a while to fix since there are many other cookie related issues we want to address as well. :disappointed:

2 Likes