Skip to content

Instantly share code, notes, and snippets.

@flashlab
Last active March 7, 2024 01:50
Show Gist options
  • Save flashlab/bd35df266f49b4fd76caca746ff04640 to your computer and use it in GitHub Desktop.
Save flashlab/bd35df266f49b4fd76caca746ff04640 to your computer and use it in GitHub Desktop.
simple cf worker to proxy jellyfin plugin repository
export default {
async fetch(request, env, ctx) {
ctx.passThroughOnException();
const url = new URL(request.url);
const uri = url.pathname.slice(1);
if (request.method != "GET" || uri.length < 3 || uri.indexOf('.') == -1 || uri == "favicon.ico" || uri == "robots.txt") {
return new Response('', { status: 405 })
} else {
if (!uri.startsWith('http')) uri = 'https://' + uri;
if (uri.endsWith('/manifest.json')) {
return proxyJson(uri, request);
} else {
return proxyRequest(uri, request)
}
}
}
}
async function proxyRequest(url, request) {
let init = {
method: request.method,
headers: {}
};
// Only pass through a subset of headers
const proxyHeaders = ["Accept",
"Accept-Encoding",
"Accept-Language",
"Referer",
"User-Agent"];
for (let name of proxyHeaders) {
let value = request.headers.get(name);
if (value) {
init.headers[name] = value;
}
}
// Add an X-Forwarded-For with the client IP
const clientAddr = request.headers.get('cf-connecting-ip');
if (clientAddr) {
init.headers['X-Forwarded-For'] = clientAddr;
}
const response = await fetch(url, init);
if (response) {
const responseHeaders = ["Content-Type",
"Cache-Control",
"Expires",
"Accept-Ranges",
"Date",
"Last-Modified",
"ETag"];
// Only include a strict subset of response headers
let responseInit = {status: response.status,
statusText: response.statusText,
headers: {}};
for (let name of responseHeaders) {
let value = response.headers.get(name);
if (value) {
responseInit.headers[name] = value;
}
}
// Add some security headers to make sure there isn't scriptable content
// being proxied.
responseInit.headers['X-Content-Type-Options'] = "nosniff";
const newResponse = new Response(response.body, responseInit);
return newResponse;
}
return response;
}
async function proxyJson(url, request) {
let manifest = await fetchCSS(url, request)
if (manifest) {
const responseInit = {headers: {
"Content-Type": "text/json; charset=utf-8",
"Cache-Control": "private, max-age=86400, stale-while-revalidate=604800"
}};
const newResponse = new Response(manifest, responseInit);
return newResponse;
} else {
// Do a straight-through proxy as fallback
return proxyRequest(url, request);
}
}
async function fetchCSS(url, request) {
let jsonText = "";
let headers = {'Referer': request.url};
const clientAddr = request.headers.get('cf-connecting-ip');
if (clientAddr) {
headers['X-Forwarded-For'] = clientAddr;
}
headers['User-Agent'] = request.headers.get('user-agent') ?? "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)";
try {
const response = await fetch(url, {headers: headers});
if (response && response.status === 200) {
jsonText = await response.text();
jsonText = jsonText.replace(/(?<![\/:])(https?:)?\/\/([a-z]+\.)?github[a-z]*\.com\//mgi, 'https://mirror.ghproxy.com/$&');
}
} catch(e) {
// Ignore the exception
}
return jsonText;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment