Passing on referer value on 301 https redirects

https
workers
#1

Hi,

i have such setup:

  1. Domain A (https)
  2. -> 301 redirect handled in Domain A worker
  3. -> Domain B (https)
  4. -> 301 redirect handled in Domain B worker
  5. -> Domain C (https)

I want to achieve that on steps 3-4 I’d have “Referrer” request parameter with correct value (‘Domain A’ in my case) and make sure ‘Domain C’ would NOT be able to see neither Domain A nor Domain B as a Referer.

So visitor goes to domainA.com(step1) and triggers the first worker(step2). In it I have:
<…>
let response = await fetch(request)
let newHdrs = new Headers(response.headers)
let location = ‘domainB.com

newHdrs.set(‘Referrer-Policy’, ‘unsafe-url’)
newHdrs.set(‘Location’, location)
newHdrs.set(‘Referer’, ${host})

return new Response(undefined, {
status: 301,
statusText: ‘Found’,
headers: newHdrs
})
<…>

But in step 4’s -domainB’s worker - I cant find the ‘Referrer’ header with ‘domainA’ as it’s value.

My initial thougts are:
a) Maybe Page Rules (a) always use https; b) redirect from non-www to www;) come in play;
b) Maybe there is something in the way I set headers;
c) Maybe there is incorrect Referrer-policy header value used;
d) Something else?

Many thanks for ideas how to pass referrer along with 301 redirect from worker.

Thanks!

#2

Added some more details on the same question reposted on StackOverflow: https://stackoverflow.com/questions/55882899/how-not-to-loose-referer-value-on-301-https-redirects-in-cloudflare-workers .

1 Like
#3

Answered on SoF

#4

Thanks, commented on your response in SoF!

#5

This is a bit confusing. You are first saying you’d like the referrer to contain domain A, only to negate this in the following sentence where you say C should never get A.

Would you like to set a custom referrer value or rather preserve an existing one, originally sent to A?

#6

HI Sandro, thanks for looking into this. My initial goal is domainA -> sends “domainA” as referer -> domainB -> sends no referer at all -> domainC (receives no referer).

But so far I’m stuck with first part - domainA -> sends “domainA” as referer -> domainB.

#7

I am afraid it still is somewhat unclear to me. What do you mean by domain A sends a referrer? The referrer is sent by the client, not the server. The server receives it.

Could you explain in plain, non-technical terms what it actually is you want to achieve at the end of the day? Non-technically please :slight_smile:

Also a few questions about your code

let response = await fetch(request)
let newHdrs = new Headers(response.headers)
let location = 'domainB.com'

newHdrs.set('Referrer-Policy', 'unsafe-url')
newHdrs.set('Location', location)
newHdrs.set('Referer', ${host})

return new Response(undefined, {
	status: 301,
	statusText: 'Found',
	headers: newHdrs
})
  • Why do you fetch the original request if you send a 301 anyhow?
  • location does contain a proper URL in your actual code, right? Because just a domain name wouldnt be valid.
  • Where does the host variable come from?
#8

Just to stress this. Referer is a request header, not a response header.

Could it be that you do not want to send a 301 back to the client, but actually proxy the request onward to B or C? In that case adding the referrer would make sense but you would need to include this in the new request object that you actually pass on to fetch.

#9

Hi Sandro, thanks a lot again for looking into it. To make things more clear, i’ve deployed the workers (code is simplified since initial post, but what you’ll see below is what’s exactly deployed as of now) to some random domains of mine:

a) https://369.lt (gets redirected with 301)
b) https://cerkasas.com returns “Testing referer: null”, but i am expecting “Testing referer: https://369.lt” to be returned.

Code for a) step, deployed on https://369.lt/* route:

addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
return new Response("Will redirect", {
status: 302,
statusText: 'Found',
headers: {
    Location: "https://cerkasas.com",
    "Referrer-Policy": "unsafe-url",
    "Referer": "https://369.lt",
}
})
}

Code for b) step, deployed on https://cerkasas.com/* route.

addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request))
    })

async function handleRequest(request) {
    let refr = request.headers.get('Referer')
    let resp = new Response(`Testing referer: ${refr}`)
    return resp
}

All page rules for both domains are disables.
Am really hoping things make much more sense now.
Thanks!

#10

Please address the question in my previous two replies. It seems the approach is somewhat wrong as far as I can tell.

#11

Could you explain in plain, non-technical terms what it actually is you want to achieve at the end of the day?

Sure!

a) User enters domainA.com and gets redirected to domainB.com;
b) domainB finds out which domain user was redirected from, and based on that does:
i) sends request to analytical software recording that ‘visit from domainA has happened’;
ii) is issueing another redirect to location(=domainC) x,y,z,d, etc. depending on the domainA value.

That ^ are the business requirements.

Could it be that you do not want to send a 301 back to the client, but actually proxy the request onward to B or C? In that case adding the referrer would make sense but you would need to include this in the new request object that you actually pass on to fetch .

I want the user to go domainA->301->domainB->301->domainC.

  • Why do you fetch the original request if you send a 301 anyhow?
  • location does contain a proper URL in your actual code, right? Because just a domain name wouldnt be valid.
  • Where does the host variable come from?

Goes those questions are not relevant anymore with the updated code examples.

In other words, how do I ensure that in “domainA->301 -> domainB->301->domainC” the bolded arrow, which represents request sent by client after receiving 301 redirect, contains “domainA” in any form of the request. I imagine I could achieve this by issueing ‘set-cookie’ readable by both domains with 301 response, but I was expecting to achieve this with Referers.

#12

Redirects do not necessarily contain a referrer. The redirect worker for A should send a redirect which contains an identifier in the query string and allows “B” to determine the source based on that identifier.

Also, you do and should not set any referrer values.

1 Like
#13

Many thanks for patience and clarifying things. I’ll use the query string approach as per your recommendation and will skip setting Referer myself. Thanks again, Sandro!