Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default {
return daResp({ status: 400 });
}
console.error('Error computing context', e);
return daResp({ status: 500 });
return daResp({ status: 500, error: e.message });
}

const { users, authorized, key } = daCtx;
Expand Down
10 changes: 8 additions & 2 deletions src/storage/object/get.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ export default async function getObject(
etag: e.ETag || conditionalHeaders?.ifNoneMatch,
};
}
return { body: '', status, contentLength: 0 };
const error = status >= 500 ? e.message : undefined;
return {
body: '', status, contentLength: 0, ...(error ? { error } : {}),
};
}
}
// HEAD request path - uses presigned URL with fetch
Expand Down Expand Up @@ -141,6 +144,9 @@ export default async function getObject(
if (status === 304 || status === 412) {
return { body: '', status, contentLength: 0 };
}
return { body: '', status, contentLength: 0 };
const error = status >= 500 ? e.message : undefined;
return {
body: '', status, contentLength: 0, ...(error ? { error } : {}),
};
}
}
4 changes: 2 additions & 2 deletions src/storage/object/move.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,15 @@ export default async function moveObject(env, daCtx, details) {
// eslint-disable-next-line no-console
console.error('Move partial failure', r.reason);
});
return { body: JSON.stringify({ error: 'partial_failure', failed: failed.length }), status: 500 };
return { body: JSON.stringify({ error: 'partial_failure', failed: failed.length }), status: 500, error: failed[0]?.reason?.message };
}
results.push(...settled.map((r) => r.value));

ContinuationToken = NextContinuationToken;
} catch (e) {
// eslint-disable-next-line no-console
console.error('Move failed', e);
return { body: JSON.stringify({ error: 'move_failed' }), status: 500 };
return { body: JSON.stringify({ error: 'move_failed' }), status: 500, error: e.message };
}
} while (ContinuationToken);

Expand Down
2 changes: 1 addition & 1 deletion src/storage/version/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,6 @@ export async function writeAuditEntry(env, ctx, repo, fileId, entry, attempt = 0
} catch (e) {
// eslint-disable-next-line no-console
console.error('writeAuditEntry failed', e);
return { status: 500 };
return { status: 500, error: e.message };
}
}
8 changes: 4 additions & 4 deletions src/storage/version/put.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export async function putVersion(config, {
// Cancel the body stream if it wasn't consumed (e.g. R2 rejected via 100-continue on 412).
// Without this, Cloudflare Workers logs "non-retryable streaming request" warnings.
if (Body?.cancel) Body.cancel();
return { status };
return { status, ...(status >= 500 ? { error: e.message } : {}) };
}
}

Expand Down Expand Up @@ -189,7 +189,7 @@ export async function putObjectWithVersion(

// eslint-disable-next-line no-console
if (status >= 500) console.error('Failed to put object (in object with version)', e);
return { status, metadata: { id: ID } };
return { status, metadata: { id: ID }, ...(status >= 500 ? { error: e.message } : {}) };
}
}

Expand Down Expand Up @@ -319,7 +319,7 @@ export async function putObjectWithVersion(

// eslint-disable-next-line no-console
if (status >= 500) console.error('Failed to version (in object with version)', e);
return { status, metadata: { id: ID } };
return { status, metadata: { id: ID }, ...(status >= 500 ? { error: e.message } : {}) };
}
}

Expand All @@ -335,7 +335,7 @@ export async function postObjectVersionWithLabel(label, env, daCtx) {
}, true);

if (resp.status !== 200) return { status: resp.status };
if (!resp.versionCreated) return { status: 500 };
if (!resp.versionCreated) return { status: 500, error: 'Version was not created' };
return { status: 201 };
}

Expand Down
7 changes: 6 additions & 1 deletion src/utils/daResp.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ export default function daResp({
metadata,
etag,
continuationToken,
error,
}, ctx = null) {
const headers = new Headers();
headers.append('Access-Control-Allow-Origin', '*');
headers.append('Access-Control-Allow-Methods', 'HEAD, GET, PUT, POST, DELETE');
headers.append('Access-Control-Allow-Headers', '*');
headers.append('Access-Control-Expose-Headers', 'X-da-actions, X-da-child-actions, X-da-acltrace, X-da-id, da-continuation-token, ETag');
headers.append('Access-Control-Expose-Headers', 'X-da-actions, X-da-child-actions, X-da-acltrace, X-da-id, da-continuation-token, ETag, x-error');
headers.append('Content-Type', normalizeCharset(contentType));
if (contentLength) {
headers.append('Content-Length', contentLength);
Expand All @@ -55,6 +56,10 @@ export default function daResp({
headers.append('da-continuation-token', continuationToken);
}

if (status >= 500 && error) {
headers.append('x-error', error);
}

if (ctx?.aclCtx && status < 500) {
headers.append('X-da-actions', `/${ctx.key}=${[...ctx.aclCtx.actionSet]}`);

Expand Down
2 changes: 2 additions & 0 deletions test/storage/object/move.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ describe('Move', () => {
const resp = await moveObject({}, ctx, { source: 'somewhere', destination: 'somedest' });

assert.strictEqual(resp.status, 500);
assert.strictEqual(resp.error, 'R2 throttled');
const body = JSON.parse(resp.body);
assert.strictEqual(body.error, 'move_failed');
});
Expand Down Expand Up @@ -161,6 +162,7 @@ describe('Move', () => {

// a.html (from initialKeys) throws, b.html succeeds — one failure, one success
assert.strictEqual(resp.status, 500);
assert.strictEqual(resp.error, 'R2 throttled');
const body = JSON.parse(resp.body);
assert.strictEqual(body.error, 'partial_failure');
assert.strictEqual(body.failed, 1);
Expand Down
2 changes: 2 additions & 0 deletions test/storage/version/audit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ describe('Version Audit', () => {
});

assert.strictEqual(result.status, 500);
assert.strictEqual(result.error, 'server error');
});

it('appends three entries when edit then version then edit (version breaks time window)', async () => {
Expand Down Expand Up @@ -851,6 +852,7 @@ describe('Version Audit', () => {
});

assert.strictEqual(result.status, 500, 'persistent 412 must surface as 500 after one retry');
assert.strictEqual(result.error, 'precondition failed');
});
});
});
6 changes: 6 additions & 0 deletions test/storage/version/put.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ describe('Version Put', () => {
const mockCtx = { users: [{ email: 'blah@acme.com' }] };
const resp = await putObjectWithVersion(mockEnv, mockCtx, mockUpdate, true);
assert.equal(500, resp.status);
assert.strictEqual(resp.error, 'testing 123');
});

it('Put Object With Version store content', async () => {
Expand Down Expand Up @@ -788,9 +789,11 @@ describe('Version Put', () => {
s3Client = s3client2;
const resp2 = await putVersion({}, { Body: 'hello' });
assert.equal(500, resp2.status);
assert.strictEqual(resp2.error, 'Test error2');
s3Client = s3client3;
const resp3 = await putVersion({}, { Body: 'hello' });
assert.equal(500, resp3.status);
assert.strictEqual(resp3.error, 'Test error3');
});

it('Test putVersion preserves ContentType', async () => {
Expand Down Expand Up @@ -2298,6 +2301,7 @@ describe('Version Put', () => {

const resp = await postObjectVersion(req, env, ctx);
assert.equal(500, resp.status);
assert.strictEqual(resp.error, 'Version was not created');
});

it('postObjectVersion returns 201 when version is successfully created', async () => {
Expand Down Expand Up @@ -2965,6 +2969,7 @@ describe('Version Put', () => {

// No label means shouldCreateVersionObject is false → versionCreated stays false → 500
assert.strictEqual(resp.status, 500);
assert.strictEqual(resp.error, 'Version was not created');
});
});

Expand Down Expand Up @@ -3066,6 +3071,7 @@ describe('Version Put', () => {
const resp = await postObjectVersionWithLabel('My Label', {}, daCtx);

assert.strictEqual(resp.status, 500, 'must return 500 when version was not created');
assert.strictEqual(resp.error, 'Version was not created');
});
});
});
13 changes: 10 additions & 3 deletions test/utils/daResp.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('DA Resp', () => {
assert.strictEqual('*', resp.headers.get('Access-Control-Allow-Origin'));
assert.strictEqual('HEAD, GET, PUT, POST, DELETE', resp.headers.get('Access-Control-Allow-Methods'));
assert.strictEqual('*', resp.headers.get('Access-Control-Allow-Headers'));
assert.strictEqual('X-da-actions, X-da-child-actions, X-da-acltrace, X-da-id, da-continuation-token, ETag', resp.headers.get('Access-Control-Expose-Headers'));
assert.strictEqual('X-da-actions, X-da-child-actions, X-da-acltrace, X-da-id, da-continuation-token, ETag, x-error', resp.headers.get('Access-Control-Expose-Headers'));
assert.strictEqual('text/plain; charset=utf-8', resp.headers.get('Content-Type'));
assert.strictEqual('777', resp.headers.get('Content-Length'));
assert.strictEqual('/foo/bar.html=read,write', resp.headers.get('X-da-actions'));
Expand All @@ -49,7 +49,7 @@ describe('DA Resp', () => {
assert.strictEqual('*', resp.headers.get('Access-Control-Allow-Origin'));
assert.strictEqual('HEAD, GET, PUT, POST, DELETE', resp.headers.get('Access-Control-Allow-Methods'));
assert.strictEqual('*', resp.headers.get('Access-Control-Allow-Headers'));
assert.strictEqual('X-da-actions, X-da-child-actions, X-da-acltrace, X-da-id, da-continuation-token, ETag', resp.headers.get('Access-Control-Expose-Headers'));
assert.strictEqual('X-da-actions, X-da-child-actions, X-da-acltrace, X-da-id, da-continuation-token, ETag, x-error', resp.headers.get('Access-Control-Expose-Headers'));
assert.strictEqual('application/json', resp.headers.get('Content-Type'));
assert(!resp.headers.get('Content-Length'));
assert.strictEqual('/foo/blah.html=read', resp.headers.get('X-da-actions'));
Expand All @@ -69,6 +69,13 @@ describe('DA Resp', () => {
assert(resp.headers.get('X-da-child-actions') === null);
assert(resp.headers.get('X-da-acltrace') === null);
assert(resp.headers.get('X-da-id') === null);
assert(resp.headers.get('x-error') === null);
});

it('test 500 with error message', () => {
const resp = daResp({ status: 500, error: 'Something went wrong' });
assert.strictEqual(500, resp.status);
assert.strictEqual('Something went wrong', resp.headers.get('x-error'));
});

it('normalizes text/html to include charset=utf-8', () => {
Expand Down Expand Up @@ -136,7 +143,7 @@ describe('DA Resp', () => {
const ctx = { key: 'foo/bar.html', aclCtx };
const resp = daResp({ status: 200, body: 'foobar' }, ctx);
assert.strictEqual(200, resp.status);
assert.strictEqual('X-da-actions, X-da-child-actions, X-da-acltrace, X-da-id, da-continuation-token, ETag', resp.headers.get('Access-Control-Expose-Headers'));
assert.strictEqual('X-da-actions, X-da-child-actions, X-da-acltrace, X-da-id, da-continuation-token, ETag, x-error', resp.headers.get('Access-Control-Expose-Headers'));
assert.strictEqual('/haha/hoho/**=read,write', resp.headers.get('X-da-child-actions'));
});
});
Loading