vcl_recv
The built-invcl_recv subroutine is executed when a client request is received by Fastly or as a result of arestart.
Typically, the recv state is used for tasks such as:
- normalizing client input
- routing:dynamically allocating a backend to the request
- applying authentication or evaluating access rights (e.g., API keys, paywalls, session tokens,URL tokens)
- triggering synthetic responses for known paths (e.g., to implementredirects for old URLs)
- requiring TLS
- Denying requests based ongeolocation orACLs
- Enabling serve stale behavior
- Setting limits or defaults
- EnablingImage Optimization
- Validating initial request to remove 'trusted' headers that should only be added by edge logic
- Changing backend after a
restart, as part of thepre-flight pattern,A/B testing ororigin failover. - InvokingWebSockets passthrough
The default return path fromvcl_recv forGET requests islookup, which will trigger thevcl_hash subroutine, perform a cache key calculation and look up the resulting address in the cache, ultimately triggering thevcl_hit,vcl_miss orvcl_pass subroutines as appropriate. It's also possible toreturn(pass), which will still perform a cache key calculation, but will always transition fromvcl_hash tovcl_pass. Returningupgrade will terminate the VCL execution and Fastly will maintain the connection as a persistentWebSockets tunnel.
Changes made to thereq object invcl_recv will affect the calculation of the cache key, if the changed properties are included inobj.hash byvcl_hash.
The exception statementsrestart anderror may both be used inrecv.
Method specific behavior
At the end ofvcl_recv, the default behavior is dependent on the method of the inbound request:
GET,HEAD, andPURGErequests will trigger alookup, while all other methods will cause apass. This behavior is in theboilerplate VCL and is overridable by using custom VCL in your service.- If the return state is
lookup, methods other thanGETandPOSTwill be converted toGETon the backend request (bereq) and any request body will be dropped. This behavior is part of the Fastly platform and is not overridable.
HINT: With the default boilerplate VCL, the rules above will result in the conversion of aHEAD request into aGET to your origin server, allowing Fastly to populate the resource into our cache, but the response to the client will correctly exclude the content body, since the client requested only the HEAD.
State transitions
| vcl_recv |
To see this subroutine in the context of the full VCL flow, seeour guide about Fastly VCL.
Example
The code exampleUse microservices to divide up a domain is a good example of thevcl_recv subroutine in use:
Tokens available in this subroutine
The following limited-scope VCL functions and variables are available for use in this subroutine (those inbold are availableonly in this subroutine, those available in *all* subroutines are not listed):
- fastly_info.h2.is_push
- req.enable_range_on_pass
- req.hash_always_miss
- req.enable_segmented_caching
- req.hash_ignore_busy
- req.is_purge
- esi.allow_inside_cdata
- req.esi_level
- req.esi
- client.socket.congestion_algorithm
- client.socket.cwnd
- client.socket.nexthop
- client.socket.pace
- client.socket.ploss
- client.socket.tcp_info
- client.socket.tcpi_advmss
- client.socket.tcpi_bytes_acked
- client.socket.tcpi_bytes_received
- client.socket.tcpi_data_segs_in
- client.socket.tcpi_data_segs_out
- client.socket.tcpi_delta_retrans
- client.socket.tcpi_delivery_rate
- client.socket.tcpi_last_data_sent
- client.socket.tcpi_max_pacing_rate
- client.socket.tcpi_min_rtt
- client.socket.tcpi_notsent_bytes
- client.socket.tcpi_pmtu
- client.socket.tcpi_pacing_rate
- client.socket.tcpi_rcv_mss
- client.socket.tcpi_rcv_rtt
- client.socket.tcpi_rcv_space
- client.socket.tcpi_rcv_ssthresh
- client.socket.tcpi_reordering
- client.socket.tcpi_rtt
- client.socket.tcpi_rttvar
- client.socket.tcpi_segs_in
- client.socket.tcpi_segs_out
- client.socket.tcpi_snd_cwnd
- client.socket.tcpi_snd_mss
- client.socket.tcpi_snd_ssthresh
- client.socket.tcpi_total_retrans
- fastly_info.h2.stream_id
- quic.cc.cwnd
- quic.cc.ssthresh
- quic.num_bytes.received
- quic.num_bytes.sent
- quic.num_packets.ack_received
- quic.num_packets.decryption_failed
- quic.num_packets.late_acked
- quic.num_packets.lost
- quic.num_packets.sent
- quic.num_packets.received
- quic.rtt.latest
- quic.rtt.minimum
- quic.rtt.smoothed
- quic.rtt.variance
- req.is_ipv6
- tls.client.certificate.dn
- tls.client.certificate.is_cert_bad
- tls.client.certificate.is_cert_expired
- tls.client.certificate.is_cert_missing
- tls.client.certificate.is_cert_unknown
- tls.client.certificate.is_unknown_ca
- tls.client.certificate.is_verified
- tls.client.certificate.issuer_dn
- tls.client.certificate.not_after
- tls.client.certificate.not_before
- tls.client.certificate.raw_certificate_b64
- tls.client.certificate.serial_number
- tls.client.cipher
- tls.client.ciphers_list_sha
- tls.client.ciphers_list_txt
- tls.client.ciphers_list
- tls.client.ciphers_sha
- tls.client.handshake_sent_bytes
- tls.client.iana_chosen_cipher_id
- tls.client.ja3_md5
- tls.client.ja4
- tls.client.servername
- tls.client.protocol
- tls.client.tlsexts_list_sha
- tls.client.tlsexts_list
- tls.client.tlsexts_list_txt
- tls.client.tlsexts_sha
- transport.bw_estimate
- transport.type
- fastly.ddos_detected
- segmented_caching.block_size