code: @InterfaceAudience.Private
      private boolean uploadMultipartRevision(final RevisionInternal revision) {
          Map<String, Object> body = revision.getProperties();
          Map<String, Object> attachments = (Map<String, Object>) body.get("_attachments");
  
          boolean attachmentsFollow = false;
          for (String attachmentKey : attachments.keySet()) {
              Map<String, Object> attachment = (Map<String, Object>) attachments.get(attachmentKey);
              if (attachment.containsKey("follows")) attachmentsFollow = true;
          }
          if (!attachmentsFollow) return false;
  
          Log.d(TAG, "Uploading multipart request.  Revision: %s", revision);
          addToChangesCount(1);
          final String path = String.format(Locale.ENGLISH, "%s?new_edits=false", encodeDocumentId(revision.getDocID()));
          CustomFuture future = sendAsyncMultipartRequest("PUT", path, body, attachments,
                  new RemoteRequestCompletion() {
                      @Override
                      public void onCompletion(RemoteRequest remoteRequest, Response httpResponse, Object result, Throwable e) {
                          try {
                              if (e != null) {
                                  if (e instanceof RemoteRequestResponseException) {
                                      // Server doesn't like multipart, eh? Fall back to JSON.
                                      if (((RemoteRequestResponseException) e).getCode() == 415) {
                                          //status 415 = "bad_content_type"
                                          dontSendMultipart = true;
                                          uploadJsonRevision(revision);
                                      }
                                  } else {
                                      Log.e(TAG, "Exception uploading multipart request", e);
                                      setError(e);
                                  }
                              } else {
                                  Log.v(TAG, "Uploaded multipart request.  Revision: %s", revision);
                                  removePending(revision);
                              }
                          } finally {
                              addToCompletedChangesCount(1);
                          }
                      }
                  });
          future.setQueue(pendingFutures);
          pendingFutures.add(future);
          return true;
      }
docs: in CBL_Pusher.m
  - (CBLMultipartWriter*)multipartWriterForRevision: (CBL_Revision*)rev