code: private <E extends Throwable> HttpRequestor.Response chunkedUploadCommon(String[] params, long chunkSize, DbxStreamWriter<E> writer)
          throws DbxException, E
      {
          String apiPath = "1/chunked_upload";
  
          ArrayList<HttpRequestor.Header> headers = new ArrayList<HttpRequestor.Header>();
          headers.add(new HttpRequestor.Header("Content-Type", "application/octet-stream"));
          headers.add(new HttpRequestor.Header("Content-Length", Long.toString(chunkSize)));
  
          HttpRequestor.Uploader uploader = DbxRequestUtil.startPut(requestConfig, accessToken, USER_AGENT_ID, host.getContent(), apiPath, params, headers);
          try {
              NoThrowOutputStream nt = new NoThrowOutputStream(uploader.getBody());
              try {
                  // Any exceptions thrown by writer.write (e.g. IOException) are "owned" by
                  // the caller so let them propagate.  We should only handle exceptions caused
                  // by our uploader OutputStream.
                  writer.write(nt);
              }
              catch (NoThrowOutputStream.HiddenException ex) {
                  if (ex.owner == nt) throw new NetworkIOException(ex.getCause());
                  throw ex;
              }
  
              long bytesWritten = nt.getBytesWritten();
              if (bytesWritten != chunkSize) {
                  throw new IllegalStateException("'chunkSize' is " + chunkSize + ", but 'writer' only wrote " + bytesWritten + " bytes");
              }
  
              try {
                  return uploader.finish();
              }
              catch (IOException ex) {
                  throw new NetworkIOException(ex);
              }
          }
          finally {
              uploader.close();
          }
      }
docs: Internal function called by both chunkedUploadFirst and chunkedUploadAppend.