@Override
    public HttpResponseOutputStream<Node> write(final Path file, final TransferStatus status, final ConnectionCallback callback) throws BackgroundException {
        final DelayedHttpEntityCallable<Node> command = new DelayedHttpEntityCallable<Node>(file) {
            @Override
            public Node call(final HttpEntity entity) throws BackgroundException {
                try {
                    final HttpEntityEnclosingRequestBase request;
                    if(status.isExists()) {
                        request = new HttpPut(String.format("%s/api/v1/nodes/%s/revisions", session.getClient().getBasePath(), fileid.getFileId(file)));
                    }
                    else {
                        request = new HttpPost(String.format("%s/api/v1/deepBoxes/%s/boxes/%s/files/%s",
                                session.getClient().getBasePath(),
                                fileid.getDeepBoxNodeId(file),
                                fileid.getBoxNodeId(file),
                                fileid.getFileId(file.getParent())));
                    }
                    final Checksum checksum = status.getChecksum();
                    if(Checksum.NONE != checksum) {
                        switch(checksum.algorithm) {
                            case sha1:
                                request.addHeader(HttpHeaders.CONTENT_MD5, checksum.hash);
                        }
                    }
                    final MultipartEntityBuilder multipart = MultipartEntityBuilder.create();
                    multipart.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
                    multipart.setCharset(StandardCharsets.UTF_8);
                    final ByteArrayOutputStream out = new ByteArrayOutputStream();
                    entity.writeTo(out);
                    if(status.isExists()) {
                        multipart.addBinaryBody("file", out.toByteArray(),
                                null == status.getMime() ? ContentType.APPLICATION_OCTET_STREAM : ContentType.create(status.getMime()), file.getName());
                        request.setEntity(multipart.build());
                        return session.getClient().getClient().execute(request, new AbstractResponseHandler<Node>() {
                            @Override
                            public Node handleEntity(final HttpEntity entity) throws IOException {
                                final ObjectReader reader = new JSON().getContext(null).reader(Node.class);
                                return reader.readValue(entity.getContent());
                            }
                        });
                    }
                    else {
                        multipart.addBinaryBody("files", out.toByteArray(),
                                null == status.getMime() ? ContentType.APPLICATION_OCTET_STREAM : ContentType.create(status.getMime()), file.getName());
                        request.setEntity(multipart.build());
                        return session.getClient().getClient().execute(request, new AbstractResponseHandler<Node>() {
                            @Override
                            public Node handleEntity(final HttpEntity entity) throws IOException {
                                final ObjectReader reader = new JSON().getContext(null).readerForArrayOf(Node.class);
                                final Node[] node = reader.readValue(entity.getContent());
                                return node[0];
                            }
                        });
                    }
                }
                catch(HttpResponseException e) {
                    throw new DefaultHttpResponseExceptionMappingService().map("Upload {0} failed", e, file);
                }
                catch(IOException e) {
                    throw new DefaultIOExceptionMappingService().map("Upload {0} failed", e, file);
                }
            }

            @Override
            public long getContentLength() {
                return -1L;
            }
        };
        return this.write(file, status, command);
    }
@Test
    public void testReadWrite() throws Exception {
        final DeepboxIdProvider nodeid = new DeepboxIdProvider(session);
        final Path documents = new Path("/ORG 4 - DeepBox Desktop App/ORG3:Box1/Documents/", EnumSet.of(Path.Type.directory, Path.Type.volume));
        final Path room = new DeepboxDirectoryFeature(session, nodeid).mkdir(
                new Path(documents,
                        new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
        final long folderTimestamp = new DeepboxAttributesFinderFeature(session, nodeid).find(room).getModificationDate();
        final byte[] content = RandomUtils.nextBytes(32769);
        final Path test = new Path(room, String.format("%s", new AlphanumericRandomStringService().random()), EnumSet.of(Path.Type.file));
        {
            final TransferStatus status = new TransferStatus();
            status.setLength(content.length);
            final DeepboxWriteFeature writer = new DeepboxWriteFeature(session, nodeid);
            final HttpResponseOutputStream<Node> out = writer.write(test, status, new DisabledConnectionCallback());
            assertNotNull(out);
            new StreamCopier(status, status).transfer(new ByteArrayInputStream(content), out);
        }
        assertTrue(new DefaultFindFeature(session).find(test));
        assertEquals(folderTimestamp, new DeepboxAttributesFinderFeature(session, nodeid).find(room).getModificationDate());
        PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(test);
        final String versionId = attributes.getVersionId();
        assertNull(versionId);
        final String nodeId = attributes.getFileId();
        assertNotNull(nodeId);
        assertEquals(new DeepboxAttributesFinderFeature(session, nodeid).find(test), attributes);
        final byte[] compare = new byte[content.length];
        final InputStream stream = new DeepboxReadFeature(session, nodeid).read(test, new TransferStatus().withLength(content.length), new DisabledConnectionCallback());
        IOUtils.readFully(stream, compare);
        stream.close();
        assertArrayEquals(content, compare);
        // Overwrite
        {
            final byte[] change = RandomUtils.nextBytes(256);
            final TransferStatus status = new TransferStatus();
            status.setLength(change.length);
            final DeepboxWriteFeature writer = new DeepboxWriteFeature(session, nodeid);
            final HttpResponseOutputStream<Node> out = writer.write(test, status.exists(true), new DisabledConnectionCallback());
            assertNotNull(out);
            new StreamCopier(status, status).transfer(new ByteArrayInputStream(change), out);
            assertEquals(nodeId, new DeepboxAttributesFinderFeature(session, nodeid).find(test).getFileId());
        }
        test.attributes().setCustom(Collections.emptyMap());
        attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(test);
        assertNotNull(attributes.getFileId());
        assertEquals(nodeId, new DeepboxIdProvider(session).getFileId(test));
        new DeepboxDeleteFeature(session, nodeid).delete(Collections.singletonList(room), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }