1
0
Fork 0

Prevent overwriting files

Closes #3
upload-progress
Ambrose Chua 2021-07-03 20:25:08 +08:00
parent 8d24804e50
commit 72a85a825d
6 changed files with 77 additions and 1 deletions

View File

@ -71,6 +71,12 @@ func handleCreateMultipartUpload(w http.ResponseWriter, req *http.Request) {
// Derive the object key
key := formatKey(cred.Prefix, r.Filename)
// Ensure that the file does not exist
err = headObject(key, cred)
if !errors.Is(err, errNotFound) {
errorResponse(w, req, fmt.Errorf("%w: the provided key exists", errConflict))
}
result, err := initiateMultipartUpload(key, cred)
if err != nil {
errorResponse(w, req, err)
@ -104,7 +110,7 @@ func handleGetUploadedParts(w http.ResponseWriter, req *http.Request) {
return
}
parts := make(getUploadedPartsRes, 0, 0)
parts := make(getUploadedPartsRes, 0)
var nextPartNumberMarker uint32
for {
page, err := listParts(key, uploadID, cred, nextPartNumberMarker)

View File

@ -148,3 +148,9 @@ func handleCreateForm(w http.ResponseWriter, req *http.Request) {
w.Write([]byte(id))
}
/* help template */
func handleHelp(w http.ResponseWriter, req *http.Request) {
executeTemplate(w, "help.tmpl", nil)
}

View File

@ -10,6 +10,7 @@ var errBadRequest = errors.New("bad request")
var errInternalServerError = errors.New("internal server error")
var errUnauthorized = errors.New("unauthorized")
var errForbidden = errors.New("forbidden")
var errConflict = errors.New("conflict")
func errorResponseStatus(w http.ResponseWriter, req *http.Request, err error) {
errorStatus := http.StatusInternalServerError
@ -24,6 +25,8 @@ func errorResponseStatus(w http.ResponseWriter, req *http.Request, err error) {
errorStatus = http.StatusUnauthorized
} else if errors.Is(err, errForbidden) {
errorStatus = http.StatusForbidden
} else if errors.Is(err, errConflict) {
errorStatus = http.StatusConflict
}
w.WriteHeader(errorStatus)
@ -50,6 +53,8 @@ func responseToError(resp *http.Response) error {
return errUnauthorized
} else if resp.StatusCode == http.StatusForbidden {
return errForbidden
} else if resp.StatusCode == http.StatusConflict {
return errConflict
}
return nil
}

View File

@ -28,6 +28,7 @@ func main() {
router.Methods(http.MethodGet).Path("/").HandlerFunc(handleCreate)
router.Methods(http.MethodPost).Path("/").HandlerFunc(handleCreateForm)
router.Methods(http.MethodGet).Path("/help").HandlerFunc(handleHelp)
uploadRouter := router.PathPrefix("/{id}").Subrouter()
uploadTemplateRouter := uploadRouter.Path("").Subrouter()

31
s3.go
View File

@ -307,3 +307,34 @@ func abortMultipartUpload(
return nil
}
/* headObject */
func headObject(
key string,
cred credential,
) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
unsignedReq, err := http.NewRequestWithContext(ctx, http.MethodHead, cred.Endpoint+"/"+key, nil)
if err != nil {
log.Printf("failure creating request: %v", err)
return err
}
signedReq := sign(unsignedReq, cred)
resp, err := httpClientS3.Do(signedReq)
if err != nil {
log.Printf("failure connecting to endpoint: %v", err)
return err
}
defer resp.Body.Close()
err = endpointReturnedError(resp)
if err != nil {
log.Printf("endpoint responded negatively: %v", err)
return err
}
return nil
}

View File

@ -14,6 +14,7 @@ uploadAreas.forEach(uploadArea => {
const logClearBtn = uploadArea.querySelector('.log-clear')
const dropArea = uploadArea.querySelector('.drop-area');
const statusArea = uploadArea.querySelector('.status-area');
const noticeArea = uploadArea.querySelector('.notice-area');
/* Components */
@ -25,6 +26,20 @@ uploadAreas.forEach(uploadArea => {
log.clear();
});
/* Error */
function showError(error='') {
let message = error.message || error.toString();
if (message !== '') {
noticeArea.classList.remove('hidden');
noticeArea.innerText = message;
} else {
noticeArea.classList.add('hidden');
noticeArea.innerText = message;
}
window.scrollTo({ top: 0 });
}
/* Uppy */
const uppy = new Uppy({
@ -42,7 +57,19 @@ uploadAreas.forEach(uploadArea => {
companionUrl: window.location.pathname,
});
uppy.on('upload-error', (f, error, res) => {
window.e = { f, error, res };
if (error.message.contains('status: 409')) {
showError('A file with the same name already exists. Rename your file and try again');
return;
}
showError(error);
});
uppy.on('upload-retry', (id) => {
showError();
});
uppy.on('upload-success', (f, res) => {
showError();
log.add({
name: f.name,
size: f.size,