Repository: envoyproxy/envoy
File: source/extensions/filters/http/grpc_json_reverse_transcoder/filter_config.cc (C++)

Code before:
  max_request_body_size_ =
      transcoder_config.has_max_request_body_size()
          ? absl::make_optional(transcoder_config.max_request_body_size().value())
          : std::nullopt;
  max_response_body_size_ =
      transcoder_config.has_max_response_body_size()
          ? absl::make_optional(transcoder_config.max_response_body_size().value())
          : std::nullopt;
  api_version_header_ = transcoder_config.api_version_header().empty()
                            ? std::nullopt
                            : absl::make_optional(transcoder_config.api_version_header());

  const auto& print_options = transcoder_config.request_json_print_options();
  request_translate_options_.json_print_options.always_print_enums_as_ints =
      print_options.always_print_enums_as_ints();
  request_translate_options_.json_print_options.always_print_fields_with_no_presence =
      print_options.always_print_primitive_fields();
  // The inverse logic (`!`) is required here to maintain backward compatibility and avoid
  // changing the JSON output format for existing users.
  request_translate_options_.json_print_options.preserve_proto_field_names =
      !print_options.use_canonical_field_names();
}

const Protobuf::MethodDescriptor*
GrpcJsonReverseTranscoderConfig::GetMethodDescriptor(absl::string_view path) const {
  if (path.empty()) {
    return nullptr;
  }
  std::string grpc_method = absl::StrReplaceAll(path.substr(1), {{"/", "."}});
  return descriptor_pool_.FindMethodByName(grpc_method);
}

absl::StatusOr<std::string>
GrpcJsonReverseTranscoderConfig::ChangeBodyFieldName(absl::string_view message_name,
                                                     absl::string_view body_field) const {
  if (request_translate_options_.json_print_options.preserve_proto_field_names) {
    return std::string(body_field);
  }
  const auto* type_descriptor = descriptor_pool_.FindMessageTypeByName(message_name);
  if (type_descriptor == nullptr) {
    return absl::InvalidArgumentError(absl::StrCat("No message named: ", message_name));
  }
  const auto* field_descriptor = type_descriptor->FindFieldByName(body_field);
  if (field_descriptor == nullptr) {
    return absl::InvalidArgumentError(absl::StrCat("No field named: ", body_field));
  }
  return std::string(field_descriptor->json_name());
}

bool GrpcJsonReverseTranscoderConfig::IsRequestNestedHttpBody(
    const Protobuf::MethodDescriptor* method_descriptor,

Review comment (suggestion):
My reading of https://github.com/envoyproxy/envoy/blob/ac973c86c98a993c3861d17a118a18bac7ef3d8b/source/common/http/conn_manager_impl.cc#L1417-L1426 

is that in HTTP request `decodeHeaders()` processing, the `path` header will not be empty.
In that case, it may be better to have an assert here, but I will let the codeowners to decide.

Code after:
  max_request_body_size_ =
      transcoder_config.has_max_request_body_size()
          ? absl::make_optional(transcoder_config.max_request_body_size().value())
          : std::nullopt;
  max_response_body_size_ =
      transcoder_config.has_max_response_body_size()
          ? absl::make_optional(transcoder_config.max_response_body_size().value())
          : std::nullopt;
  api_version_header_ = transcoder_config.api_version_header().empty()
                            ? std::nullopt
                            : absl::make_optional(transcoder_config.api_version_header());

  const auto& print_options = transcoder_config.request_json_print_options();
  request_translate_options_.json_print_options.always_print_enums_as_ints =
      print_options.always_print_enums_as_ints();
  request_translate_options_.json_print_options.always_print_fields_with_no_presence =
      print_options.always_print_primitive_fields();
  // The inverse logic (`!`) is required here to maintain backward compatibility and avoid
  // changing the JSON output format for existing users.
  request_translate_options_.json_print_options.preserve_proto_field_names =
      !print_options.use_canonical_field_names();
}

const Protobuf::MethodDescriptor*
GrpcJsonReverseTranscoderConfig::GetMethodDescriptor(absl::string_view path) const {
  // HCM guarantees the `:path` header is non-empty here.
  ASSERT(!path.empty());
  std::string grpc_method = absl::StrReplaceAll(path.substr(1), {{"/", "."}});
  return descriptor_pool_.FindMethodByName(grpc_method);
}

absl::StatusOr<std::string>
GrpcJsonReverseTranscoderConfig::ChangeBodyFieldName(absl::string_view message_name,
                                                     absl::string_view body_field) const {
  if (request_translate_options_.json_print_options.preserve_proto_field_names) {
    return std::string(body_field);
  }
  const auto* type_descriptor = descriptor_pool_.FindMessageTypeByName(message_name);
  if (type_descriptor == nullptr) {
    return absl::InvalidArgumentError(absl::StrCat("No message named: ", message_name));
  }
  const auto* field_descriptor = type_descriptor->FindFieldByName(body_field);
  if (field_descriptor == nullptr) {
    return absl::InvalidArgumentError(absl::StrCat("No field named: ", body_field));
  }
  return std::string(field_descriptor->json_name());
}

bool GrpcJsonReverseTranscoderConfig::IsRequestNestedHttpBody(
    const Protobuf::MethodDescriptor* method_descriptor,
    const std::string& http_request_body_field) const {