public static GetBlobOptions buildGetBlobOptions(Map<String, Object> args, SubResource subResource,
      GetOption getOption, RestRequest restRequest, int blobSegmentIdx) throws RestServiceException {
    String rangeHeaderValue = getHeader(args, Headers.RANGE, false);
    if (subResource != null && !subResource.equals(SubResource.Segment) && rangeHeaderValue != null) {
      throw new RestServiceException("Ranges not supported for sub-resources that aren't Segment.",
          RestServiceErrorCode.InvalidArgs);
    }
    boolean resolveRangeOnEmptyBlob = getBooleanHeader(args, Headers.RESOLVE_RANGE_ON_EMPTY_BLOB, false);
    return new GetBlobOptionsBuilder().operationType(getBlobOptionsOperationType(subResource))
        .getOption(getOption)
        .blobSegment(blobSegmentIdx)
        .range(rangeHeaderValue != null ? RestUtils.buildByteRange(rangeHeaderValue) : null)
        .resolveRangeOnEmptyBlob(resolveRangeOnEmptyBlob)
        .restRequest(restRequest)
        .build();
  }
Build a {@link GetBlobOptions} object from an argument map for a certain sub-resource.
@param args the arguments associated with the request. This is typically a map of header names and query string
            arguments to values.
@param subResource the {@link SubResource} for the request, or {@code null} if no sub-resource is requested.
@param getOption the {@link GetOption} required.
@param restRequest the {@link RestRequest} that initiate this get operation, null if no rest request is available.
@param blobSegmentIdx index of blob segment one wishes to GET, {@link GetBlobOptions#NO_BLOB_SEGMENT_IDX_SPECIFIED}
                      if not used
@return a populated {@link GetBlobOptions} object.
@throws RestServiceException if the {@link GetBlobOptions} could not be constructed.
ambry-api/src/main/java/com/github/ambry/rest/RestUtils.java