parent
8d24804e50
commit
72a85a825d
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
1
main.go
1
main.go
|
@ -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
31
s3.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue