Cookies and headers are how your Gatling simulation talks to the server beyond just the request URL. They’re the tiny pieces of data that make your simulation act like a real browser, keeping track of sessions and passing along important context.
Let’s see Gatling manage these automatically. Imagine we’re simulating a user logging into a site and then performing an action.
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
class CookieHeaderSimulation extends Simulation {
val httpProtocol = http
.baseUrl("http://localhost:8080") // Replace with your target server
.doNotTrack
val scn = scenario("Cookie and Header Management")
.exec(http("Login Request")
.post("/login")
.formParam("username", "testuser")
.formParam("password", "password123")
.check(status.is(200))
.check(header("Set-Cookie").saveAs("sessionCookie"))) // Save the session cookie
.exec(http("Access Protected Page")
.get("/dashboard")
.header("X-Custom-Header", "MyValue") // Add a custom header
.cookie("sessionCookie") // Automatically use the saved session cookie
.check(status.is(200)))
setUp(
scn.inject(rampUsers(10) during (5.seconds))
).protocols(httpProtocol)
}
In this simulation, the Login Request POSTs credentials. The check(header("Set-Cookie").saveAs("sessionCookie")) is crucial: when the server responds with a Set-Cookie header (which is how it tells your browser to store a cookie, typically for session management), Gatling captures that entire header value and stores it in a session variable named sessionCookie.
The subsequent Access Protected Page GET request then uses .cookie("sessionCookie"). This tells Gatling to look up the sessionCookie variable and automatically send its value as a Cookie header in the outgoing request. It also adds a custom header X-Custom-Header with the value MyValue.
The httpProtocol itself has some built-in cookie management. doNotTrack is a good example: it automatically adds the DNT: 0 or DNT: 1 header to all requests, respecting the user’s tracking preferences. Gatling’s HTTP protocol is designed to handle the persistence of cookies received from the server and re-sending them on subsequent requests to the same domain, much like a real browser. This is all managed automatically unless you explicitly override it or tell Gatling to ignore certain cookies.
If you have a specific cookie you don’t want Gatling to send, you can explicitly remove it from the session before a request using exec(session => session.remove("cookieName")). Similarly, if a server sends back multiple Set-Cookie headers for different purposes, Gatling will store them all. You can then choose which ones to send back by referencing them by name, like cookie("cookieName").
The most surprising true thing about Gatling’s cookie and header management is that by default, it acts as a stateful client across all requests within a simulation, seamlessly handling session cookies without explicit configuration for each one. It’s not just blindly sending requests; it’s building a conversation.
The check(header("Set-Cookie").saveAs("sessionCookie")) is where the magic of stateful interaction begins. The saveAs function is key; it doesn’t just look at the header, it stores its value for future use. This means that any subsequent request that needs to include this cookie can simply reference it by the name provided in saveAs. Gatling’s HTTP protocol then automatically constructs the Cookie header using the stored value. This automatic re-sending of cookies is what enables simulations of logged-in users or interactions that rely on session state.
Consider the scenario where a server sends back multiple Set-Cookie headers. Gatling will store each of these individually. You can then selectively choose which cookies to include in subsequent requests. For instance, if a login response sets both a session ID cookie and a preference cookie, you could then perform an action that only requires the session ID by explicitly calling .cookie("sessionCookieName") and ignore the preference cookie. If you want to send all cookies Gatling has stored for that domain, you don’t need to specify them individually; Gatling will include them automatically.
When you define a custom header like .header("X-Custom-Header", "MyValue"), you’re directly injecting a specific piece of information into the request. This is useful for API keys, authentication tokens not managed by cookies, or custom request metadata that your application expects. Gatling uses header(name, value) for static header values and header(name).saveAs("variableName") to capture a header from a response.
The baseUrl in the httpProtocol is more than just a prefix; it also plays a role in cookie domain matching. Cookies are typically scoped to a domain, and Gatling uses the baseUrl to determine which cookies are relevant for a given request. If your baseUrl is http://api.example.com and a Set-Cookie header comes back with Domain=.example.com, Gatling will associate that cookie with requests to api.example.com.
The doNotTrack setting is a simple but important header. When enabled, Gatling adds DNT: 1 to requests. If disabled (or not set), it defaults to DNT: 0. This is a common header used by websites to respect user privacy preferences regarding online tracking.
The next concept you’ll likely encounter is handling more complex authentication flows, like OAuth, where headers and cookies are dynamically generated and exchanged.