- Add the
worker.js
code to a new Cloudflare Worker - Set up a worker for your domain than responds to
/tunnel/*
and point it to your new worker - Add the Sentry script to your html but replace
https://browser.sentry-cdn.com/
with./tunnel/
- Eg.
<script src="./tunnel/6.9.0/bundle.min.js"></script>
- Eg.
init
Sentry with thetunnel
option set to/tunnel/
- Eg.
Sentry.init({ dsn: "__DSN__", tunnel: "/tunnel/" })
- Eg.
- Rejoice at how everything now works with ad blockers
-
-
Save timfish/a69dd7457b8d6d97c0a8018675be6c23 to your computer and use it in GitHub Desktop.
const SLUG = '/tunnel/'; | |
addEventListener('fetch', event => { | |
event.respondWith(handleRequest(event.request)) | |
}) | |
async function handleRequest(request) { | |
const url = new URL(request.url) | |
// Handle requests for Sentry CDN JavaScript | |
if (request.method === 'GET' && url.pathname.startsWith(SLUG) && (url.pathname.endsWith('.js') || url.pathname.endsWith('.js.map'))) { | |
const path = url.pathname.slice(SLUG.length); | |
// Fetch and pass the same response, including headers | |
return fetch(`https://browser.sentry-cdn.com/${path}`); | |
} | |
if (request.method === 'POST' && url.pathname === SLUG) { | |
let { readable, writable } = new TransformStream() | |
request.body.pipeTo(writable); | |
// We tee the stream so we can pull the header out of one stream | |
// and pass the other straight as the fetch POST body | |
const [header, body] = readable.tee(); | |
let decoder = new TextDecoder() | |
let chunk = ''; | |
const headerReader = header.getReader(); | |
while (true) { | |
const { done, value } = await headerReader.read(); | |
if (done) { | |
break; | |
} | |
chunk += decoder.decode(value); | |
const index = chunk.indexOf('\n'); | |
if (index >= 0) { | |
// Get the first line | |
const firstLine = chunk.slice(0, index); | |
const event = JSON.parse(firstLine); | |
const dsn = new URL(event.dsn); | |
// Pass through the user IP address | |
const headers = request.headers | |
headers.set('X-Forwarded-For', request.headers.get('CF-Connecting-IP')) // enhance the original headers | |
// Post to the Sentry endpoint! | |
return fetch(`https://${dsn.host}/api${dsn.pathname}/envelope/`, { | |
method: 'POST', | |
body, | |
headers, | |
}) | |
} | |
} | |
} | |
// If the above routes don't match, return 404 | |
return new Response(null, { status: 404 }); | |
} |
Nice! What changes do I need to make to this gist to support X-Forwaded-For
?
I was thinking of putting into a repo with a "Deploy to Cloudflare" button which automates the setup
@timfish I think you could replace line 47 with
const headers = request.headers
headers.set('X-Forwarded-For', request.headers.get('CF-Connecting-IP')) // enhance the original headers
// Post to the Sentry endpoint!
return fetch(`https://${dsn.host}/api${dsn.pathname}/envelope/`, {
method: 'POST',
body,
headers,
})
Updated, thanks!
The request.body.pipeTo(writable);
code seemed invalid to me as it is an asynchronous function, but after adding await
, the solution stopped working for me in one of my projects, for no apparent reason.
After replacing the code:
let { readable, writable } = new TransformStream()
request.body.pipeTo(writable);
// We tee the stream so we can pull the header out of one stream
// and pass the other straight as the fetch POST body
const [header, body] = readable.tee();
as follows:
// We tee the stream so we can pull the header out of one stream
// and pass the other straight as the fetch POST body
const [header, body] = request.body.tee();
everything was back to normal.
My full code only supports POST
because I'm just tunneling the request from Sentry.
export async function onRequestPost({request}) {
const [header, body] = request.body.tee();
let decoder = new TextDecoder();
let chunk = '';
const headerReader = header.getReader();
while (true) {
const {done, value} = await headerReader.read();
if (done) break;
chunk += decoder.decode(value);
const index = chunk.indexOf('\n');
if (index >= 0) {
const line = chunk.slice(0, index);
const dsn = new URL(JSON.parse(line).dsn);
const headers = request.headers;
headers.set('X-Forwarded-For', request.headers.get('CF-Connecting-IP'));
return fetch(`https://${dsn.host}/api${dsn.pathname}/envelope/`, {
method: 'POST', body, headers,
});
}
}
return new Response(null, {status: 404});
}
Humm, I gotta ask if anyone has made this with Nginx directly? 🤔
Hey, just wondering if the Cloudflare Worker proxy still works?
When I tried it I get the error Can't modify immutable headers
on the X-Forwarded-For
line.
Any thoughts?
@alan0xd7, try:
const newRequest = new Request(request);
newRequest.headers.set('X-Custom-Header', '...');
or:
const newHeaders = new Headers(request.headers);
newHeaders.set('X-Custom-Header', '...');
Thanks! This works:
const newHeaders = new Headers(request.headers);
const clientIp = request.headers.get('CF-Connecting-IP');
newHeaders.set('X-Forwarded-For', clientIp);
It's apparently a bug in Sentry: getsentry/relay#2450