@Override
    public HttpResponseOutputStream<BaseB2Response> write(final Path file, final TransferStatus status, final ConnectionCallback callback) throws BackgroundException {
        // Submit store call to background thread
        final DelayedHttpEntityCallable<BaseB2Response> command = new DelayedHttpEntityCallable<BaseB2Response>(file) {
            /**
             * @return The SHA-1 returned by the server for the uploaded object
             */
            @Override
            public BaseB2Response call(final HttpEntity entity) throws BackgroundException {
                try {
                    final Checksum checksum = status.getChecksum();
                    if(status.isSegment()) {
                        final B2GetUploadPartUrlResponse uploadUrl = session.getClient().getUploadPartUrl(status.getParameters().get("fileId"));
                        return session.getClient().uploadLargeFilePart(uploadUrl, status.getPart(), entity, checksum.hash);
                    }
                    else {
                        if(null == urls.get()) {
                            final B2GetUploadUrlResponse uploadUrl = session.getClient().getUploadUrl(fileid.getVersionId(containerService.getContainer(file)));
                            if(log.isDebugEnabled()) {
                                log.debug(String.format("Obtained upload URL %s for file %s", uploadUrl, file));
                            }
                            urls.set(uploadUrl);
                            return this.upload(uploadUrl, entity, checksum);
                        }
                        else {
                            final B2GetUploadUrlResponse uploadUrl = urls.get();
                            if(log.isDebugEnabled()) {
                                log.debug(String.format("Use cached upload URL %s for file %s", uploadUrl, file));
                            }
                            try {
                                return this.upload(uploadUrl, entity, checksum);
                            }
                            catch(IOException | B2ApiException e) {
                                // Upload many files to the same upload_url until that URL gives an error
                                log.warn(String.format("Remove cached upload URL after failure %s", e));
                                urls.remove();
                                // Retry
                                return this.upload(uploadUrl, entity, checksum);
                            }
                        }
                    }
                }
                catch(B2ApiException e) {
                    throw new B2ExceptionMappingService(fileid).map("Upload {0} failed", e, file);
                }
                catch(IOException e) {
                    throw new DefaultIOExceptionMappingService().map("Upload {0} failed", e, file);
                }
            }

            private BaseB2Response upload(final B2GetUploadUrlResponse uploadUrl, final HttpEntity entity, final Checksum checksum) throws B2ApiException, IOException {
                final Map<String, String> fileinfo = new HashMap<>(status.getMetadata());
                if(null != status.getModified()) {
                    fileinfo.put(X_BZ_INFO_SRC_LAST_MODIFIED_MILLIS, String.valueOf(status.getModified()));
                }
                if(null != status.getCreated()) {
                    fileinfo.put(X_BZ_INFO_SRC_CREATION_DATE_MILLIS, String.valueOf(status.getCreated()));
                }
                final B2FileResponse response = session.getClient().uploadFile(uploadUrl,
                        containerService.getKey(file),
                        entity, checksum.algorithm == HashAlgorithm.sha1 ? checksum.hash : "do_not_verify",
                        status.getMime(), fileinfo);
                fileid.cache(file, response.getFileId());
                return response;
            }

            @Override
            public long getContentLength() {
                return status.getLength();
            }
        };
        return this.write(file, status, command);
    }
@Test
    public void testWriteChecksumFailure() throws Exception {
        final Path bucket = new Path("test-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
        final Path file = new Path(bucket, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file));
        final TransferStatus status = new TransferStatus();
        final byte[] content = RandomUtils.nextBytes(1);
        status.setLength(content.length);
        status.setChecksum(Checksum.parse("da39a3ee5e6b4b0d3255bfef95601890afd80709"));
        final HttpResponseOutputStream<BaseB2Response> out = new B2WriteFeature(session, new B2VersionIdProvider(session)).write(file, status, new DisabledConnectionCallback());
        IOUtils.write(content, out);
        try {
            out.close();
            fail();
        }
        catch(IOException e) {
            assertTrue(e.getCause() instanceof ChecksumException);
        }
    }