private void processPart(InterfaceHttpData part) throws RestServiceException {
    if (part.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
      FileUpload fileUpload = (FileUpload) part;
      if (fileUpload.getName().equals(RestUtils.MultipartPost.BLOB_PART)) {
        // this is actual data.
        if (hasBlob) {
          nettyMetrics.repeatedPartsError.inc();
          throw new RestServiceException("Request has more than one " + RestUtils.MultipartPost.BLOB_PART,
              RestServiceErrorCode.BadRequest);
        } else {
          hasBlob = true;
          if (getSize() != -1 && fileUpload.length() != getSize()) {
            nettyMetrics.multipartRequestSizeMismatchError.inc();
            throw new RestServiceException(
                "Request size [" + fileUpload.length() + "] does not match Content-Length [" + getSize() + "]",
                RestServiceErrorCode.BadRequest);
          } else {
            contentLock.lock();
            try {
              if (isOpen()) {
                requestContents.add(new DefaultHttpContent(ReferenceCountUtil.retain(fileUpload.content())));
                blobBytesReceived.set(fileUpload.content().capacity());
              } else {
                nettyMetrics.multipartRequestAlreadyClosedError.inc();
                throw new RestServiceException("Request is closed", RestServiceErrorCode.RequestChannelClosed);
              }
            } finally {
              contentLock.unlock();
            }
          }
        }
      } else {
        // this is any kind of data. (For ambry, this will be user metadata).
        // TODO: find a configurable way of rejecting unexpected file parts.
        String name = fileUpload.getName();
        if (allArgs.containsKey(name)) {
          nettyMetrics.repeatedPartsError.inc();
          throw new RestServiceException("Request already has a component named " + name,
              RestServiceErrorCode.BadRequest);
        } else {
          ByteBuffer buffer = ByteBuffer.allocate(fileUpload.content().readableBytes());
          // TODO: Possible optimization - Upgrade ByteBufferReadableStreamChannel to take a list of ByteBuffer. This
          // TODO: will avoid the copy.
          fileUpload.content().readBytes(buffer);
          buffer.flip();
          allArgs.put(name, buffer);
        }
      }
    } else {
      nettyMetrics.unsupportedPartError.inc();
      throw new RestServiceException("Unexpected HTTP data", RestServiceErrorCode.BadRequest);
    }
  }
Processes a single decoded part in a multipart request. Exposes the data in the part either through the channel
itself (if it is the blob part) or via {@link #getArgs()}.
@param part the {@link InterfaceHttpData} that needs to be processed.
@throws RestServiceException if the request channel is closed, if there is more than one part of the same name, if
                             the size obtained from the headers does not match the actual size of the blob part or
                             if {@code part} is not of the expected type ({@link FileUpload}).
ambry-rest/src/main/java/com/github/ambry/rest/NettyMultipartRequest.java