throw new ObjectTooLargeException("The '" +
CONTENT_LENGTH + "' of the incoming request " +
"is too large. Max upload size allowed is " +
uploadMaxSize_ + "-bytes.");
}
final HashedFileObject hfo = getHashedFileObject(repo, key);
return new ReentrantReadWriteEntityLock<HashedFileObject>(hfo) {
@Override
public HashedFileObject transaction() throws Exception {
final String eTag = hfo.getFirstHeader(ETAG);
// If we have an incoming If-Match, we need to compare
// that against the current HFO before we attempt to
// update. If the If-Match ETag does not match, fail.
if(ifMatch != null && eTag != null) {
// OK, we have an incoming If-Match ETag, use it.
// NOTE: HFO's will _always_ have an ETag attached
// to their meta-data. ETag's are always computed
// for HFO's upload. But new HFO's (one's the repo
// have never seen before) may not yet have an ETag.
if(!ifMatch.equals(eTag)) {
throw new ObjectConflictException("Failed " +
"to update HFO; incoming If-Match ETag " +
"does not match (hfo=" + hfo.getName() +
", etag=" + eTag + ", if-match=" +
ifMatch + ")");
}
}
final DiskObject object = getCanonicalObject(
repo, hfo,
// Create the File on disk if it does not
// already exist. Yay!
true);
// The file itself (should exist now).
final File objFile = object.getFile();
final File tempObjFile = object.getTempFile();
try(final InputStream is = request.getInputStream();
final OutputStream os = new FileOutputStream(tempObjFile);) {
// Compute the ETag (an MD5 hash of the file) while
// copying the file into place. The bytes of the
// input stream and piped into an MD5 digest _and_
// to the output stream -- ideally computing the
// hash and copying the file at the same time.
// Set the resulting ETag header (meta data).
hfo.setETag(getSHA1HashAndCopy(is, os,
// Only copy as much as the incoming
// Content-Length header sez is going
// to be sent. Anything more than this
// is caught gracefully and dropped.
contentLength));
// Move the uploaded file into place (moves
// the file from the temp location to the
// real destination inside of the repository
// on disk).
move(tempObjFile, objFile);
// Set the Last-Modified header (meta data).
hfo.setLastModified(objFile.lastModified());
// Set the Content-Length header (meta data).
hfo.setContentLength(objFile.length());
// Set the Content-Type header (meta data).
if(contentType != null) {
hfo.setContentType(contentType);
}
} catch (KolichChecksum.KolichChecksumException e) {
// Quietly delete the object on disk when
// it has exceeded the max upload size allowed
// by this Havalo instance.
throw new ObjectTooLargeException("The " +
"size of the incoming object is too " +
"large. Max upload size is " +
uploadMaxSize_ + "-bytes.", e);
} finally {
// Delete the file from the temp upload
// location. Note, this file may not exist
// if the upload was successful and the object
// was moved into place.. which is OK here.
deleteQuietly(tempObjFile);
}
// Append an ETag header to the response for the
// PUT'ed object.
response.setHeader(ETAG, hfo.getFirstHeader(ETAG));
return hfo;
}
@Override
public void success(final HashedFileObject e) throws Exception {
// On success only, ask the repo manager to