Skip to content
File

Blob: fuzzilli/r2-mock.js

javascript92 lines
1function shouldChaos() {
2 return Math.random() < 0.13; // 13% chaos for R2
3}
4 
5function getChaoticR2Response() {
6 const chaos = Math.random();
7 if (chaos < 0.2) {
8 // Access denied
9 return new Response(
10 '<?xml version="1.0" encoding="UTF-8"?><Error><Code>AccessDenied</Code><Message>Access Denied</Message></Error>',
11 { status: 403, headers: { 'Content-Type': 'application/xml' } }
12 );
13 } else if (chaos < 0.4) {
14 // Object not found
15 return new Response(
16 '<?xml version="1.0" encoding="UTF-8"?><Error><Code>NoSuchKey</Code></Error>',
17 { status: 404, headers: { 'Content-Type': 'application/xml' } }
18 );
19 } else if (chaos < 0.6) {
20 // Bandwidth limit exceeded
21 return new Response('Rate limit exceeded', { status: 429 });
22 } else if (chaos < 0.8) {
23 // Corrupted metadata
24 return new Response('corrupted object content', {
25 headers: {
26 'Content-Type': 'text/plain',
27 'CF-R2-Metadata-Size': 'not-a-number', // Invalid metadata
28 ETag: 'invalid-etag-format',
29 },
30 });
31 } else {
32 // Wrong content type but valid data
33 return new Response(JSON.stringify({ not: 'xml', but: 'json' }), {
34 headers: { 'Content-Type': 'application/xml' }, // Lying about content type
35 });
36 }
37}
38 
39export default {
40 async fetch(request, env, ctx) {
41 // Random chaos injection
42 if (shouldChaos()) {
43 return getChaoticR2Response();
44 }
45 
46 const { pathname } = new URL(request.url);
47 const method = request.method;
48 
49 if (method === 'GET' && pathname !== '/') {
50 // GET object
51 return new Response('test-object-content', {
52 headers: {
53 'Content-Type': 'text/plain',
54 'CF-R2-Metadata-Size': '18',
55 },
56 });
57 } else if (method === 'PUT') {
58 // PUT object
59 return new Response(
60 JSON.stringify({
61 etag: 'mock-etag-' + Math.random().toString(36).substr(2, 9),
62 }),
63 {
64 headers: { 'Content-Type': 'application/json' },
65 }
66 );
67 } else if (method === 'GET' && pathname === '/') {
68 // LIST objects (sometimes return inconsistent results)
69 const objects = [{ key: 'test-object', metadata: { size: 18 } }];
70 if (Math.random() < 0.1) {
71 // Sometimes add random objects to list
72 objects.push({
73 key: 'mystery-object',
74 metadata: { size: Math.floor(Math.random() * 1000) },
75 });
76 }
77 
78 return new Response(
79 JSON.stringify({
80 keys: objects,
81 is_truncated: Math.random() < 0.05, // Sometimes claim truncation
82 }),
83 {
84 headers: { 'Content-Type': 'application/json' },
85 }
86 );
87 }
88 
89 return new Response('R2 mock ready', { status: 200 });
90 },
91};