70bf21e064
Deploy (to testing) and Test Playground Preview Worker / Deploy Playground Preview Worker (testing) (push) Has been skipped
Deploy Workers Shared Staging / Deploy Workers Shared Staging (push) Failing after 0s
Prerelease / build (push) Has been skipped
Handle Changesets / Handle Changesets (push) Has been cancelled
Semgrep OSS scan / semgrep-oss (push) Has been cancelled
813 lines
24 KiB
TypeScript
813 lines
24 KiB
TypeScript
import { fetch } from "undici";
|
|
import { beforeAll, describe, it } from "vitest";
|
|
|
|
const REMOTE = "https://playground-testing.devprod.cloudflare.dev";
|
|
const PREVIEW_REMOTE =
|
|
"https://random-data.playground-testing.devprod.cloudflare.dev";
|
|
|
|
const TEST_WORKER_BOUNDARY = "----WebKitFormBoundaryqJEYLXuUiiZQHgvf";
|
|
const TEST_WORKER_CONTENT_TYPE = `multipart/form-data; boundary=${TEST_WORKER_BOUNDARY}`;
|
|
const TEST_WORKER = `--${TEST_WORKER_BOUNDARY}
|
|
Content-Disposition: form-data; name="index.js"; filename="index.js"
|
|
Content-Type: application/javascript+module
|
|
|
|
export default {
|
|
fetch(request) {
|
|
const url = new URL(request.url)
|
|
if(url.pathname === "/exchange") {
|
|
return Response.json({
|
|
token: "TEST_TOKEN",
|
|
prewarm: "TEST_PREWARM"
|
|
})
|
|
}
|
|
if(url.pathname === "/redirect") {
|
|
return Response.redirect("https://example.com", 302)
|
|
}
|
|
if(url.pathname === "/method") {
|
|
return new Response(request.method, {
|
|
headers: { "Test-Http-Method": request.method },
|
|
})
|
|
}
|
|
if(url.pathname === "/status") {
|
|
return new Response(407)
|
|
}
|
|
if(url.pathname === "/header") {
|
|
return new Response(request.headers.get("X-Custom-Header"))
|
|
}
|
|
if(url.pathname === "/cookies") {
|
|
const headers = new Headers();
|
|
|
|
headers.append("Set-Cookie", "foo=1");
|
|
headers.append("Set-Cookie", "bar=2");
|
|
|
|
return new Response(undefined, {
|
|
headers,
|
|
});
|
|
}
|
|
return Response.json({
|
|
url: request.url,
|
|
headers: [...request.headers.entries()]
|
|
})
|
|
}
|
|
}
|
|
|
|
--${TEST_WORKER_BOUNDARY}
|
|
Content-Disposition: form-data; name="metadata"; filename="blob"
|
|
Content-Type: application/json
|
|
|
|
{"compatibility_date":"2023-05-04","main_module":"index.js"}
|
|
--${TEST_WORKER_BOUNDARY}--`;
|
|
|
|
async function fetchUserToken() {
|
|
return fetch(REMOTE).then(
|
|
(r) => r.headers.getSetCookie()[0].split(";")[0].split("=")[1]
|
|
);
|
|
}
|
|
describe("Preview Worker", () => {
|
|
let defaultUserToken: string;
|
|
beforeAll(async () => {
|
|
defaultUserToken = await fetchUserToken();
|
|
|
|
await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=${defaultUserToken}`,
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: TEST_WORKER,
|
|
}).then((response) => response.json());
|
|
});
|
|
|
|
it("should be redirected with cookie", async ({ expect }) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=${defaultUserToken}&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "https://workers.cloudflare.com/",
|
|
},
|
|
}
|
|
);
|
|
expect(resp.headers.get("location")).toEqual("/hello?world");
|
|
expect(resp.headers.get("set-cookie") ?? "").toEqual(
|
|
`token=${defaultUserToken}; Domain=random-data.playground-testing.devprod.cloudflare.dev; Path=/; HttpOnly; Secure; SameSite=None; Partitioned`
|
|
);
|
|
});
|
|
it("shouldn't be redirected with no token", async ({ expect }) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "https://workers.cloudflare.com/",
|
|
},
|
|
}
|
|
);
|
|
expect(resp.status).toBe(400);
|
|
expect(await resp.text()).toMatchInlineSnapshot(
|
|
`"{"error":"TokenUpdateFailed","message":"Provide valid token","data":{}}"`
|
|
);
|
|
});
|
|
it("shouldn't be redirected with invalid token", async ({ expect }) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=TEST_TOKEN&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "https://workers.cloudflare.com/",
|
|
},
|
|
}
|
|
);
|
|
expect(resp.status).toBe(400);
|
|
expect(await resp.text()).toMatchInlineSnapshot(
|
|
`"{"error":"TokenUpdateFailed","message":"Provide valid token","data":{}}"`
|
|
);
|
|
});
|
|
|
|
it("should convert cookie to header", async ({ expect }) => {
|
|
const resp = await fetch(PREVIEW_REMOTE, {
|
|
method: "GET",
|
|
headers: {
|
|
cookie: `token=${defaultUserToken}`,
|
|
},
|
|
});
|
|
|
|
const json = (await resp.json()) as { headers: string[][]; url: string };
|
|
|
|
expect(json.url.slice(-13, -1)).toMatchInlineSnapshot('".workers.dev"');
|
|
});
|
|
it("should not follow redirects", async ({ expect }) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/redirect`, {
|
|
method: "GET",
|
|
headers: {
|
|
cookie: `token=${defaultUserToken}`,
|
|
},
|
|
redirect: "manual",
|
|
});
|
|
|
|
expect(resp.status).toMatchInlineSnapshot("302");
|
|
expect(resp.headers.get("Location")).toMatchInlineSnapshot(
|
|
'"https://example.com/"'
|
|
);
|
|
expect(await resp.text()).toMatchInlineSnapshot('""');
|
|
});
|
|
it("should return method", async ({ expect }) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/method`, {
|
|
method: "PUT",
|
|
headers: {
|
|
cookie: `token=${defaultUserToken}`,
|
|
},
|
|
redirect: "manual",
|
|
});
|
|
|
|
expect(await resp.text()).toMatchInlineSnapshot('"PUT"');
|
|
});
|
|
it("should return header", async ({ expect }) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/header`, {
|
|
method: "PUT",
|
|
headers: {
|
|
"X-Custom-Header": "custom",
|
|
cookie: `token=${defaultUserToken}`,
|
|
},
|
|
redirect: "manual",
|
|
});
|
|
|
|
expect(await resp.text()).toMatchInlineSnapshot('"custom"');
|
|
});
|
|
it("should return status", async ({ expect }) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/status`, {
|
|
method: "PUT",
|
|
headers: {
|
|
cookie: `token=${defaultUserToken}`,
|
|
},
|
|
redirect: "manual",
|
|
});
|
|
|
|
expect(await resp.text()).toMatchInlineSnapshot('"407"');
|
|
});
|
|
it("should reject no token", async ({ expect }) => {
|
|
const resp = await fetch(PREVIEW_REMOTE);
|
|
expect(resp.status).toBe(400);
|
|
expect(await resp.text()).toMatchInlineSnapshot(
|
|
`"{"error":"PreviewRequestFailed","message":"Valid token not found","data":{}}"`
|
|
);
|
|
});
|
|
it("should reject invalid cookie header", async ({ expect }) => {
|
|
const resp = await fetch(PREVIEW_REMOTE, {
|
|
headers: {
|
|
cookie: "token",
|
|
},
|
|
});
|
|
expect(resp.status).toBe(400);
|
|
expect(await resp.text()).toMatchInlineSnapshot(
|
|
`"{"error":"PreviewRequestFailed","message":"Valid token not found","data":{}}"`
|
|
);
|
|
});
|
|
it("should reject invalid token", async ({ expect }) => {
|
|
const resp = await fetch(PREVIEW_REMOTE, {
|
|
headers: {
|
|
cookie: `token=TEST_TOKEN`,
|
|
},
|
|
});
|
|
expect(resp.status).toBe(400);
|
|
expect(await resp.text()).toMatchInlineSnapshot(
|
|
`"{"error":"PreviewRequestFailed","message":"Valid token not found","data":{"tokenId":"TEST_TOKEN"}}"`
|
|
);
|
|
});
|
|
|
|
it("should return raw HTTP response", async ({ expect }) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/header`, {
|
|
headers: {
|
|
"X-CF-Token": defaultUserToken,
|
|
"CF-Raw-HTTP": "true",
|
|
"X-Custom-Header": "custom",
|
|
},
|
|
redirect: "manual",
|
|
});
|
|
expect(resp.headers.get("cf-ew-raw-content-length")).toMatchInlineSnapshot(
|
|
'"6"'
|
|
);
|
|
expect(await resp.text()).toMatchInlineSnapshot('"custom"');
|
|
});
|
|
it("should return method specified on the X-CF-Http-Method header", async ({
|
|
expect,
|
|
}) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/method`, {
|
|
method: "POST",
|
|
headers: {
|
|
"X-CF-Token": defaultUserToken,
|
|
"X-CF-Http-Method": "PUT",
|
|
"CF-Raw-HTTP": "true",
|
|
},
|
|
redirect: "manual",
|
|
});
|
|
|
|
expect(await resp.text()).toEqual("PUT");
|
|
});
|
|
it.for(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"])(
|
|
"should handle %s method specified on the X-CF-Http-Method header",
|
|
async (method, { expect }) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/method`, {
|
|
method: "POST",
|
|
headers: {
|
|
"X-CF-Token": defaultUserToken,
|
|
"X-CF-Http-Method": method,
|
|
"CF-Raw-HTTP": "true",
|
|
},
|
|
redirect: "manual",
|
|
});
|
|
|
|
// HEAD request does not return any body. So we will confirm by asserting the response header
|
|
expect(await resp.text()).toEqual(method === "HEAD" ? "" : method);
|
|
// Header from the client response will be prefixed with "cf-ew-raw-"
|
|
expect(resp.headers.get("cf-ew-raw-Test-Http-Method")).toEqual(method);
|
|
}
|
|
);
|
|
it("should fallback to the request method if the X-CF-Http-Method header is missing", async ({
|
|
expect,
|
|
}) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/method`, {
|
|
method: "PUT",
|
|
headers: {
|
|
"X-CF-Token": defaultUserToken,
|
|
"CF-Raw-HTTP": "true",
|
|
},
|
|
redirect: "manual",
|
|
});
|
|
|
|
expect(await resp.text()).toEqual("PUT");
|
|
});
|
|
it("should reject no token for raw HTTP response", async ({ expect }) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/header`, {
|
|
headers: {
|
|
"CF-Raw-HTTP": "true",
|
|
"X-Custom-Header": "custom",
|
|
},
|
|
redirect: "manual",
|
|
});
|
|
expect(resp.status).toBe(400);
|
|
expect(await resp.text()).toMatchInlineSnapshot(
|
|
`"{"error":"RawHttpFailed","message":"Provide valid token","data":{}}"`
|
|
);
|
|
});
|
|
it("should reject invalid token for raw HTTP response", async ({
|
|
expect,
|
|
}) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/header`, {
|
|
headers: {
|
|
"X-CF-Token": "TEST_TOKEN",
|
|
"CF-Raw-HTTP": "true",
|
|
"X-Custom-Header": "custom",
|
|
},
|
|
redirect: "manual",
|
|
});
|
|
expect(resp.status).toBe(400);
|
|
expect(await resp.text()).toMatchInlineSnapshot(
|
|
`"{"error":"RawHttpFailed","message":"Provide valid token","data":{}}"`
|
|
);
|
|
});
|
|
|
|
describe("Referer", () => {
|
|
it("should allow localhost", async ({ expect }) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=${defaultUserToken}&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "http://localhost:5173/some/path",
|
|
},
|
|
}
|
|
);
|
|
expect(resp.headers.get("location")).toMatchInlineSnapshot(
|
|
'"/hello?world"'
|
|
);
|
|
expect(resp.headers.get("set-cookie") ?? "").toEqual(
|
|
`token=${defaultUserToken}; Domain=random-data.playground-testing.devprod.cloudflare.dev; Path=/; HttpOnly; Secure; SameSite=None; Partitioned`
|
|
);
|
|
});
|
|
it("should allow workers.cloudflare.com", async ({ expect }) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=${defaultUserToken}&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "https://workers.cloudflare.com/some/path",
|
|
},
|
|
}
|
|
);
|
|
expect(resp.headers.get("location")).toMatchInlineSnapshot(
|
|
'"/hello?world"'
|
|
);
|
|
expect(resp.headers.get("set-cookie") ?? "").toEqual(
|
|
`token=${defaultUserToken}; Domain=random-data.playground-testing.devprod.cloudflare.dev; Path=/; HttpOnly; Secure; SameSite=None; Partitioned`
|
|
);
|
|
});
|
|
it("should allow workers-playground.pages.dev", async ({ expect }) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=${defaultUserToken}&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer:
|
|
"https://preview-id.workers-playground.pages.dev/some/path",
|
|
},
|
|
}
|
|
);
|
|
expect(resp.headers.get("location")).toMatchInlineSnapshot(
|
|
'"/hello?world"'
|
|
);
|
|
expect(resp.headers.get("set-cookie") ?? "").toEqual(
|
|
`token=${defaultUserToken}; Domain=random-data.playground-testing.devprod.cloudflare.dev; Path=/; HttpOnly; Secure; SameSite=None; Partitioned`
|
|
);
|
|
});
|
|
it("should allow workers-playground.workers.dev", async ({ expect }) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=${defaultUserToken}&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "https://workers-playground.workers.dev/some/path",
|
|
},
|
|
}
|
|
);
|
|
expect(resp.headers.get("location")).toMatchInlineSnapshot(
|
|
'"/hello?world"'
|
|
);
|
|
expect(resp.headers.get("set-cookie") ?? "").toEqual(
|
|
`token=${defaultUserToken}; Domain=random-data.playground-testing.devprod.cloudflare.dev; Path=/; HttpOnly; Secure; SameSite=None; Partitioned`
|
|
);
|
|
});
|
|
it("should reject unknown referer", async ({ expect }) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=${defaultUserToken}&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "https://example.com/some/path",
|
|
},
|
|
}
|
|
);
|
|
expect(await resp.json()).toEqual({
|
|
data: {},
|
|
error: "PreviewRequestForbidden",
|
|
message: "Preview request forbidden",
|
|
});
|
|
});
|
|
it("should reject unknown referer with pages.dev in path", async ({
|
|
expect,
|
|
}) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=${defaultUserToken}&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "https://example.com/workers-playground.pages.dev",
|
|
},
|
|
}
|
|
);
|
|
expect(await resp.json()).toEqual({
|
|
data: {},
|
|
error: "PreviewRequestForbidden",
|
|
message: "Preview request forbidden",
|
|
});
|
|
});
|
|
it("should reject unknown referer with workers.dev in path", async ({
|
|
expect,
|
|
}) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=${defaultUserToken}&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "https://example.com/workers-playground.workers.dev",
|
|
},
|
|
}
|
|
);
|
|
expect(await resp.json()).toEqual({
|
|
data: {},
|
|
error: "PreviewRequestForbidden",
|
|
message: "Preview request forbidden",
|
|
});
|
|
});
|
|
it("should reject spoofed pages.dev hostname", async ({ expect }) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=${defaultUserToken}&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "https://evil-workers-playground.pages.dev/some/path",
|
|
},
|
|
}
|
|
);
|
|
expect(await resp.json()).toEqual({
|
|
data: {},
|
|
error: "PreviewRequestForbidden",
|
|
message: "Preview request forbidden",
|
|
});
|
|
});
|
|
it("should reject spoofed workers.dev hostname", async ({ expect }) => {
|
|
const resp = await fetch(
|
|
`${PREVIEW_REMOTE}/.update-preview-token?token=${defaultUserToken}&suffix=${encodeURIComponent(
|
|
"/hello?world"
|
|
)}`,
|
|
{
|
|
method: "GET",
|
|
redirect: "manual",
|
|
// These are forbidden headers, but undici currently allows setting them
|
|
headers: {
|
|
"Sec-Fetch-Dest": "iframe",
|
|
Referer: "https://evil-workers-playground.workers.dev/some/path",
|
|
},
|
|
}
|
|
);
|
|
expect(await resp.json()).toEqual({
|
|
data: {},
|
|
error: "PreviewRequestForbidden",
|
|
message: "Preview request forbidden",
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Upload Worker", () => {
|
|
let defaultUserToken: string;
|
|
beforeAll(async () => {
|
|
defaultUserToken = await fetchUserToken();
|
|
});
|
|
it("should upload valid worker", async ({ expect }) => {
|
|
const w = await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=${defaultUserToken}`,
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: TEST_WORKER,
|
|
});
|
|
expect(w.status).toBe(200);
|
|
});
|
|
it("should upload valid worker and return tail url", async ({ expect }) => {
|
|
const w = await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=${defaultUserToken}`,
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: TEST_WORKER,
|
|
});
|
|
expect(await w.json()).toMatchObject({
|
|
tail: expect.stringContaining("tail.developers.workers.dev"),
|
|
});
|
|
});
|
|
it("should provide error message on invalid worker", async ({ expect }) => {
|
|
const w = await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=${defaultUserToken}`,
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: TEST_WORKER.replace("fetch(request)", "fetch(request"),
|
|
}).then((response) => response.json());
|
|
expect(w).toEqual({
|
|
data: {
|
|
error:
|
|
"Uncaught SyntaxError: Unexpected token '{'\n at index.js:2:15\n",
|
|
},
|
|
error: "PreviewError",
|
|
message:
|
|
"Uncaught SyntaxError: Unexpected token '{'\n at index.js:2:15\n",
|
|
});
|
|
});
|
|
it("should reject no token", async ({ expect }) => {
|
|
const w = await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: TEST_WORKER,
|
|
});
|
|
expect(w.status).toBe(401);
|
|
expect(await w.text()).toEqual(
|
|
`{"error":"UploadFailed","message":"Valid token not provided","data":{}}`
|
|
);
|
|
});
|
|
it("should reject invalid token", async ({ expect }) => {
|
|
const w = await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=TEST_TOKEN`,
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: TEST_WORKER,
|
|
});
|
|
expect(w.status).toBe(401);
|
|
expect(await w.text()).toEqual(
|
|
`{"error":"UploadFailed","message":"Valid token not provided","data":{}}`
|
|
);
|
|
});
|
|
it("should reject invalid form data", async ({ expect }) => {
|
|
const w = await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=${defaultUserToken}`,
|
|
"Content-Type": "text/plain",
|
|
},
|
|
body: "not a form",
|
|
});
|
|
expect(w.status).toBe(400);
|
|
expect(await w.text()).toEqual(
|
|
`{"error":"BadUpload","message":"Expected valid form data","data":{"error":"TypeError: Unrecognized Content-Type header value. FormData can only parse the following MIME types: multipart/form-data, application/x-www-form-urlencoded"}}`
|
|
);
|
|
});
|
|
it("should reject missing metadata", async ({ expect }) => {
|
|
const w = await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=${defaultUserToken}`,
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: `--${TEST_WORKER_BOUNDARY}
|
|
Content-Disposition: form-data; name="index.js"; filename="index.js"
|
|
Content-Type: application/javascript+module
|
|
|
|
export default {
|
|
fetch(request) { return new Response("body"); }
|
|
}
|
|
|
|
--${TEST_WORKER_BOUNDARY}--`,
|
|
});
|
|
expect(w.status).toBe(400);
|
|
expect(await w.text()).toEqual(
|
|
`{"error":"BadUpload","message":"Expected metadata file to be defined","data":{}}`
|
|
);
|
|
});
|
|
it("should reject invalid metadata json", async ({ expect }) => {
|
|
const w = await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=${defaultUserToken}`,
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: `--${TEST_WORKER_BOUNDARY}
|
|
Content-Disposition: form-data; name="metadata"; filename="blob"
|
|
Content-Type: application/json
|
|
|
|
{"compatibility_date":"2023-05-04",
|
|
--${TEST_WORKER_BOUNDARY}--`,
|
|
});
|
|
expect(w.status).toBe(400);
|
|
expect(await w.text()).toEqual(
|
|
`{"error":"BadUpload","message":"Expected metadata file to be valid","data":{}}`
|
|
);
|
|
});
|
|
it("should reject invalid metadata", async ({ expect }) => {
|
|
const w = await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=${defaultUserToken}`,
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: `--${TEST_WORKER_BOUNDARY}
|
|
Content-Disposition: form-data; name="metadata"; filename="blob"
|
|
Content-Type: application/json
|
|
|
|
{"compatibility_date":42,"main_module":"index.js"}
|
|
--${TEST_WORKER_BOUNDARY}--`,
|
|
});
|
|
expect(w.status).toBe(400);
|
|
expect(await w.text()).toEqual(
|
|
`{"error":"BadUpload","message":"Expected metadata file to be valid","data":{}}`
|
|
);
|
|
});
|
|
it("should reject service worker", async ({ expect }) => {
|
|
const w = await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=${defaultUserToken}`,
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: `--${TEST_WORKER_BOUNDARY}
|
|
Content-Disposition: form-data; name="index.js"; filename="index.js"
|
|
Content-Type: application/javascript
|
|
|
|
addEventListener("fetch", (event) => event.respondWith(new Response("body")));
|
|
--${TEST_WORKER_BOUNDARY}
|
|
Content-Disposition: form-data; name="metadata"; filename="blob"
|
|
Content-Type: application/json
|
|
|
|
{"compatibility_date":"2023-05-04","body_part":"index.js"}
|
|
--${TEST_WORKER_BOUNDARY}--`,
|
|
});
|
|
expect(w.status).toBe(400);
|
|
expect(await w.text()).toEqual(
|
|
`{"error":"ServiceWorkerNotSupported","message":"Service Workers are not supported in the Workers Playground","data":{}}`
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Raw HTTP preview", () => {
|
|
let defaultUserToken: string;
|
|
beforeAll(async () => {
|
|
defaultUserToken = await fetchUserToken();
|
|
|
|
await fetch(`${REMOTE}/api/worker`, {
|
|
method: "POST",
|
|
headers: {
|
|
cookie: `user=${defaultUserToken}`,
|
|
"Content-Type": TEST_WORKER_CONTENT_TYPE,
|
|
},
|
|
body: TEST_WORKER,
|
|
}).then((response) => response.json());
|
|
});
|
|
it("should allow arbitrary headers in cross-origin requests", async ({
|
|
expect,
|
|
}) => {
|
|
const resp = await fetch(PREVIEW_REMOTE, {
|
|
method: "OPTIONS",
|
|
headers: {
|
|
"Access-Control-Request-Headers": "foo",
|
|
origin: "https://cloudflare.dev",
|
|
"cf-raw-http": "true",
|
|
},
|
|
});
|
|
|
|
expect(resp.headers.get("Access-Control-Allow-Headers")).toBe("foo");
|
|
});
|
|
it("should allow arbitrary methods in cross-origin requests", async ({
|
|
expect,
|
|
}) => {
|
|
const resp = await fetch(PREVIEW_REMOTE, {
|
|
method: "OPTIONS",
|
|
headers: {
|
|
"Access-Control-Request-Method": "PUT",
|
|
origin: "https://cloudflare.dev",
|
|
"cf-raw-http": "true",
|
|
},
|
|
});
|
|
|
|
expect(resp.headers.get("Access-Control-Allow-Methods")).toBe("*");
|
|
});
|
|
|
|
it("should preserve multiple cookies", async ({ expect }) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}/cookies`, {
|
|
method: "GET",
|
|
headers: {
|
|
origin: "https://cloudflare.dev",
|
|
"cf-raw-http": "true",
|
|
"X-CF-Token": defaultUserToken,
|
|
},
|
|
});
|
|
|
|
expect(resp.headers.get("cf-ew-raw-set-cookie")).toEqual(`foo=1, bar=2`);
|
|
});
|
|
|
|
it("should pass headers to the user-worker", async ({ expect }) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}`, {
|
|
method: "GET",
|
|
headers: {
|
|
origin: "https://cloudflare.dev",
|
|
"cf-raw-http": "true",
|
|
"X-CF-Token": defaultUserToken,
|
|
"Some-Custom-Header": "custom",
|
|
Accept: "application/json",
|
|
},
|
|
});
|
|
|
|
const body = (await resp.json()) as Record<string, unknown>;
|
|
|
|
const headers = (body.headers as [string, string][]).filter(
|
|
(h) => h[0] === "some-custom-header" || h[0] === "accept"
|
|
);
|
|
|
|
// This contains some-custom-header & accept, as expected
|
|
expect(headers).toEqual([
|
|
["accept", "application/json"],
|
|
["some-custom-header", "custom"],
|
|
]);
|
|
});
|
|
|
|
it("should strip cf-ew-raw- prefix from headers which have it before hitting the user-worker", async ({
|
|
expect,
|
|
}) => {
|
|
const resp = await fetch(`${PREVIEW_REMOTE}`, {
|
|
method: "GET",
|
|
headers: {
|
|
origin: "https://cloudflare.dev",
|
|
"cf-raw-http": "true",
|
|
"X-CF-Token": defaultUserToken,
|
|
"Some-Custom-Header": "custom",
|
|
Accept: "application/json",
|
|
},
|
|
});
|
|
|
|
const body = (await resp.json()) as Record<string, unknown>;
|
|
|
|
const headers = (body.headers as [string, string][]).filter(
|
|
(h) =>
|
|
h[0] === "some-custom-header" ||
|
|
h[0] === "accept" ||
|
|
h[0].startsWith("cf-ew-raw-")
|
|
);
|
|
|
|
// This contains some-custom-header & accept, as expected, and does not contain cf-ew-raw-some-custom-header or cf-ew-raw-accept
|
|
expect(headers).toEqual([
|
|
["accept", "application/json"],
|
|
["some-custom-header", "custom"],
|
|
]);
|
|
});
|
|
});
|