From 3b39803b49ad27c5c0dc5c0b95a31f60c54074c0 Mon Sep 17 00:00:00 2001 From: Zac Gaetano Date: Mon, 6 Apr 2026 21:54:38 -0400 Subject: [PATCH] fix: extension upload uses server-signed content type + better error logging The presigned URL is signed with a specific Content-Type (determined by the server's MIME map). If the browser's file.type doesn't match (common for broadcast formats like MXF, R3D, BRAW), S3 rejects the PUT with a signature mismatch. Now the extension uses presigned.contentType from the server response instead of item.file.type. Also added console logging for upload requests and detailed error messages from S3 responses on failure. Co-Authored-By: Claude Sonnet 4.6 --- chrome-extension/popup.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/chrome-extension/popup.js b/chrome-extension/popup.js index 712b722..1ee352e 100644 --- a/chrome-extension/popup.js +++ b/chrome-extension/popup.js @@ -267,11 +267,15 @@ async function uploadHTTP(item, idx, prefix) { contentType: item.file.type || 'application/octet-stream' }); if (!presigned.success) throw new Error(presigned.error); + // Use the content type from the server response (matches what was signed) + // NOT item.file.type which may differ from what the server determined + const signedContentType = presigned.contentType || item.file.type || 'application/octet-stream'; + console.log(`[DW] Upload ${item.name} → ${presigned.url.substring(0, 60)}... (${signedContentType})`); await new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('PUT', presigned.url); - xhr.setRequestHeader('Content-Type', item.file.type || 'application/octet-stream'); + xhr.setRequestHeader('Content-Type', signedContentType); xhr.upload.onprogress = (e) => { if (e.lengthComputable) { const pct = Math.round((e.loaded / e.total) * 100); @@ -279,8 +283,14 @@ async function uploadHTTP(item, idx, prefix) { setFileStatus(idx, 'uploading', `${pct}%`); } }; - xhr.onload = () => xhr.status < 300 ? resolve() : reject(new Error(`S3 ${xhr.status}`)); - xhr.onerror = () => reject(new Error('Network error')); + xhr.onload = () => { + console.log(`[DW] S3 PUT ${item.name} → ${xhr.status}`); + xhr.status < 300 ? resolve() : reject(new Error(`S3 error ${xhr.status}: ${xhr.responseText?.substring(0, 200)}`)); + }; + xhr.onerror = () => { + console.error(`[DW] S3 PUT ${item.name} network error`); + reject(new Error('Network error — check console for details')); + }; xhr.send(item.file); }); document.getElementById(`fpb-${idx}`).style.width = '100%';