HttpRequest Configuration

The HttpRequest configuration specifies the details of each HTTP interaction with options for capturing responses, using payloads, and applying headers.

Key Attributes

  • URL: The endpoint to which the request is sent.
  • HTTP Method: Defines the type of request (e.g., GET, POST, PUT).
  • Headers: Key-value pairs included in the request.
  • Payload: Data sent with the request (e.g., JSON body).
  • skipIf: Optional condition to skip this HTTP request only.
  • before: Optional list of expressions that run first (before the request's skipIf is checked and its URL/headers are built), so any variable they store — typically via $find(..., variable=x) — is ready for this same request to use.
  • after: Optional list of expressions that run after the request completes and its response is captured, so they can read the response and store data for later steps.
  • Retry: Optional retry policy with conditional retry/stop expressions and fixed or exponential delays.
  • Version: HTTP version (e.g., 1.1, 2.0).
  • Client Certificate Path: Path to a client certificate file for mutual TLS (mTLS) authentication. Supported formats: .pfx, .p12, .pem, .cer, .crt.
  • Client Certificate Password: Password for the certificate file (if password-protected).
httpRequest:
  url: https://api.example.com/resource
  httpMethod: POST
  headers:
    Content-Type: application/json
  payload:
    type: Raw
    raw: '{"key": "value"}'
  httpVersion: 2.0
  clientCertificatePath: .\mycert.pfx
  clientCertificatePassword: optional-password

Transport Options

  • supportH2C: Enable HTTP/2 cleartext when backend supports it.
  • downloadHtmlEmbeddedResources: Auto-download page sub-resources (images/css/js) for page-load realism.

Other Options

  • saveResponse: Saves the response to the disk. Do not use unless you really need it. This may have serious impact on the load test performance.

skipIf at HttpRequest Level

httpRequest.skipIf skips only the HTTP request block when its expression evaluates to true. This is useful when the iteration should still exist in the flow, but the outbound request should be conditionally suppressed.

iterations:
  - name: userDetails
    httpRequest:
      skipIf: ${users.Body[$length($users.Body)-1].id} = 10
      httpMethod: Get
      url: https://httpbin.org/

Typical use cases:

  • Avoid a follow-up request when a captured response already shows the terminal condition.
  • Skip calls based on a previous status code or response body value.
  • Combine capture, declarative methods, and arithmetic path expressions in one condition.

before at HttpRequest Level

httpRequest.before is a list of setup expressions that run first — before the request's skipIf is checked and before its URL, headers, and payload are built. Each expression runs in order and is used for its side effect: it stores a variable (typically via $find(..., variable=x)) and its return value is ignored.

Because before runs first, the variables it produces are immediately available to the same request. This is what lets a request look something up and then use it in its own skipIf, URL, or headers — which is otherwise impossible, since those are all computed at send time.

Order of evaluation for one request:

  1. run each before expression (e.g. store userId)
  2. evaluate skipIf (can now read ${userId})
  3. build the URL and headers (can now read ${userId})
  4. send the request
iterations:
  - name: getAlbums
    httpRequest:
      before:
        # 1) look up the id first and store it in `userId`
        - '$find(source=$users.Body, where=item.username == "Bret", select=item.id, match=first, variable=userId)'
      # 2) now the URL can use it
      url: 'https://jsonplaceholder.typicode.com/users/${userId}/albums'
      method: GET

before is also available at the iteration level (runs once when the iteration starts, before the iteration's skipIf). See the Before Expressions article.

after at HttpRequest Level

httpRequest.after is a list of expressions that run after the request has completed and its response has been captured. Each expression runs in order and is used for its side effect: it stores a variable (typically via $find(..., variable=x) or a declarative method with variable=) and its return value is ignored.

Because after runs after the response is received and captured, it can read the response and prepare data for the next iteration/request — the mirror image of before.

When it runs: after the request finishes (including its retries). It runs on both success and failure, but not when skipIf skipped the request, and not on cancellation.

iterations:
  - name: getUser
    httpRequest:
      capture:
        to: user
        as: Json
        makeGlobal: true
      url: https://jsonplaceholder.typicode.com/users/1
      method: GET
      after:
        # post-process the captured response and store a value for later
        - '$setvariable(variable=userCity, value=${user.Body.address.city})'

after is also available at the iteration level (runs once when the iteration completes). See the before & after Expressions article.

Retry

httpRequest.retry retries the same request when retry.if evaluates to true. This is useful for transient failures such as 5xx responses, rate limits, or temporary upstream errors.

httpRequest:
  capture:
    to: LastResponse
    as: Json
    makeGlobal: false
  url: https://httpbin.org/status/500
  method: GET
  retry:
    if: ${LastResponse.StatusCode} >= 500
    stopIf: ${LastResponse.StatusCode} = 400
    maxRetries: 5
    delayInMs: 1000
    strategy: Exponential
    maxDelayInMs: 11000

Retry fields

  • if: Optional boolean expression evaluated after each attempt. When it evaluates to true, LPS schedules another attempt while retries remain. When omitted, if defaults to true — the request retries unconditionally (still bounded by stopIf and maxRetries).
  • stopIf: Optional boolean expression evaluated before retry.if. If it evaluates to true, retries stop immediately.
  • maxRetries: Maximum number of retry attempts after the initial request. Use 0 to disable retry while keeping the block present.
  • delayInMs: Base delay between retries in milliseconds.
  • strategy: Delay strategy. Supported values are Fixed and Exponential.
  • maxDelayInMs: Optional cap for exponential backoff. Omit it when strategy: Fixed.

Retry behavior

  • retry.if and retry.stopIf use the same Flee expression support as skipIf.
  • retry.if is optional; when omitted it defaults to true, so the request retries unconditionally (subject to stopIf and maxRetries).
  • stopIf is checked first on each cycle. If it is true, no more retries are attempted.
  • With strategy: Fixed, every retry waits exactly delayInMs.
  • With strategy: Exponential, delay grows as delayInMs * 2^(attempt-1) and is capped by maxDelayInMs when provided.
  • Capturing the response is the typical way to drive retry decisions, for example ${LastResponse.StatusCode} >= 500.

Validation rules

  • maxRetries must be explicitly provided and be greater than or equal to 0.
  • delayInMs must be explicitly provided and be greater than 0.
  • strategy must be either Fixed or Exponential.
  • For Fixed, omit maxDelayInMs.
  • For Exponential, maxDelayInMs is optional, but when provided it must be greater than or equal to delayInMs.
  • retry.if is optional (defaults to true); retry.stopIf is optional too.
  • When both are provided, retry.if and retry.stopIf must not be the same expression.

Common patterns

Retry server errors with exponential backoff:

retry:
  if: ${LastResponse.StatusCode} >= 500
  maxRetries: 5
  delayInMs: 1000
  strategy: Exponential
  maxDelayInMs: 11000

Retry with a fixed delay:

retry:
  if: ${LastResponse.StatusCode} = 429
  maxRetries: 3
  delayInMs: 500
  strategy: Fixed

Response Capture

Capture responses to variables for later usage:

httpRequest:
  capture:
    to: VariableName
    as: Json|QJson|String|QString|Xml|QXml|Csv|QCsv|Int|Double|Boolean
    regex: "optional-regex"
    makeGlobal: false

to: VariableName stores a session variable with .StatusCode, .StatusReason, .Headers.<Name>[i], .Body (supports JSONPath via ${VariableName.Body.field}).

Capture Details

The capture: property stores the full HTTP response into a built-in response variable type. The variable exposes:

  • Body — the default value; typed by as: (e.g., Json, QJson, Xml, QXml, Csv, QCsv, String, QString).
  • StatusCode — numeric HTTP status code.
  • StatusReason — HTTP reason phrase.
  • Headers — header values; case-insensitive lookup; multiple values supported via index [i].

Scope: Captured variables are session-scoped by default. Set makeGlobal: true to publish globally.

name: WebFlow
rounds:
  - name: Auth
    iterations:
      - name: Login
        httpRequest:
          url: https://api.example.com/login
          method: POST
          payload:
            type: Json
            value: '{"user":"${U}","pass":"${P}"}'
          capture:
            to: LoginResponse
            as: Json
            makeGlobal: false

Access Patterns

  • Body (typed): ${LoginResponse.Body}; JSON: ${LoginResponse.Body.token}; XML: ${LoginResponse.Body.Root.Element}; CSV: ${LoginResponse.Body[0,2]}
  • Status/Reason: ${LoginResponse.StatusCode}, ${LoginResponse.StatusReason}
  • Headers: ${LoginResponse.Headers.Content-Type}, ${LoginResponse.Headers.Set-Cookie[0]}

Arithmetic Expressions in Captured Values

Captured JSON, XML, and CSV values support arithmetic expressions in index positions:

  • JSON: ${UsersResponse.Body[0+1].id}
  • JSON with method call: ${UsersResponse.Body[$length($UsersResponse.Body)-1].id}
  • XML: ${CatalogResponse.Body/items/item[1+1]/name}
  • CSV: ${CsvUsers.Body[0+1,1]}

Notes:

  • JSON and CSV indexes are zero-based.
  • XML uses XPath semantics, so repeated element positions are one-based.
  • Non-arithmetic selectors such as ['name'], [*], and XPath attribute predicates are preserved as-is.

Typical skipIf Usage

skipIf: ${LoginResponse.StatusCode} == 401
skipIf: ${LoginResponse.Body.token} == ""

Client Certificate Authentication (Mutual TLS)

Use clientCertificatePath and clientCertificatePassword to authenticate with servers that require client certificates.

Supported certificate formats:

  • .pfx / .p12 — PKCS#12 format (may require password)
  • .pem / .cer / .crt — Base64-encoded certificate

YAML Example (Basic)

httpRequest:
  url: https://secure-api.example.com/resource
  method: GET
  httpVersion: 2.0
  clientCertificatePath: ./certs/client.pfx
  clientCertificatePassword: mysecretpassword

YAML Example (Using Environment Variable)

Use the $read() method to securely read the password from an environment variable:

name: SecureAPITest
variables:
- name: certPassword
  value: $read(source: env, name: CERT_PASSWORD)
rounds:
- name: TestRound
  numberOfClients: 1
  iterations:
  - name: SecureRequest
    httpRequest:
      url: https://secure-api.example.com/resource
      method: GET
      clientCertificatePath: ./certs/client.pfx
      clientCertificatePassword: $certPassword
    mode: R
    requestCount: 1

CLI Example

lps --url https://secure-api.example.com/resource --clientcertificatepath ./certs/client.pfx --clientcertificatepassword mysecretpassword

CLI Options:

OptionAliasDescription
--clientcertificatepath-ccpPath to the client certificate file
--clientcertificatepassword-ccpwPassword for PFX/P12 certificate files

Notes:

  • Path can be absolute or relative to the working directory
  • Password supports variable placeholders (e.g., $certPassword)
  • Use $read(source: env, name: VAR_NAME) to read sensitive values from environment variables
  • Certificate is loaded per-request, enabling different certificates for different endpoints
  • For .pem, .cer, .crt files, password is typically not required

Label: HttpRequest retry features (retry.if, retry.stopIf, maxRetries, delayInMs, strategy, maxDelayInMs) are currently available in lps.3.0.5.2-Preview.