• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #19715

06 Mar 2025 08:10AM UTC coverage: 88.479% (-0.04%) from 88.515%
#19715

push

github

web-flow
xds: xDS-based HTTP CONNECT configuration (#11861)

34489 of 38980 relevant lines covered (88.48%)

0.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.57
/../xds/src/main/java/io/grpc/xds/MetadataRegistry.java
1
/*
2
 * Copyright 2024 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.xds;
18

19
import com.google.common.annotations.VisibleForTesting;
20
import com.google.common.collect.ImmutableMap;
21
import com.google.protobuf.Any;
22
import com.google.protobuf.Struct;
23
import io.envoyproxy.envoy.config.core.v3.Metadata;
24
import io.grpc.xds.GcpAuthenticationFilter.AudienceMetadataParser;
25
import io.grpc.xds.XdsEndpointResource.AddressMetadataParser;
26
import io.grpc.xds.client.XdsResourceType.ResourceInvalidException;
27
import io.grpc.xds.internal.ProtobufJsonConverter;
28
import java.util.HashMap;
29
import java.util.Map;
30

31
/**
32
 * Registry for parsing cluster metadata values.
33
 *
34
 * <p>This class maintains a mapping of type URLs to {@link MetadataValueParser} instances,
35
 * allowing for the parsing of different metadata types.
36
 */
37
final class MetadataRegistry {
38
  private static final MetadataRegistry INSTANCE = new MetadataRegistry();
1✔
39

40
  private final Map<String, MetadataValueParser> supportedParsers = new HashMap<>();
1✔
41

42
  private MetadataRegistry() {
1✔
43
    registerParser(new AudienceMetadataParser());
1✔
44
    registerParser(new AddressMetadataParser());
1✔
45
  }
1✔
46

47
  static MetadataRegistry getInstance() {
48
    return INSTANCE;
1✔
49
  }
50

51
  MetadataValueParser findParser(String typeUrl) {
52
    return supportedParsers.get(typeUrl);
1✔
53
  }
54

55
  @VisibleForTesting
56
  void registerParser(MetadataValueParser parser) {
57
    supportedParsers.put(parser.getTypeUrl(), parser);
1✔
58
  }
1✔
59

60
  void removeParser(MetadataValueParser parser) {
61
    supportedParsers.remove(parser.getTypeUrl());
1✔
62
  }
1✔
63

64
  /**
65
   * Parses cluster metadata into a structured map.
66
   *
67
   * <p>Values in {@code typed_filter_metadata} take precedence over
68
   * {@code filter_metadata} when keys overlap, following Envoy API behavior. See
69
   * <a href="https://github.com/envoyproxy/envoy/blob/main/api/envoy/config/core/v3/base.proto#L217-L259">
70
   *   Envoy metadata documentation </a> for details.
71
   *
72
   * @param metadata the {@link Metadata} containing the fields to parse.
73
   * @return an immutable map of parsed metadata.
74
   * @throws ResourceInvalidException if parsing {@code typed_filter_metadata} fails.
75
   */
76
  public ImmutableMap<String, Object> parseMetadata(Metadata metadata)
77
      throws ResourceInvalidException {
78
    ImmutableMap.Builder<String, Object> parsedMetadata = ImmutableMap.builder();
1✔
79

80
    // Process typed_filter_metadata
81
    for (Map.Entry<String, Any> entry : metadata.getTypedFilterMetadataMap().entrySet()) {
1✔
82
      String key = entry.getKey();
1✔
83
      Any value = entry.getValue();
1✔
84
      MetadataValueParser parser = findParser(value.getTypeUrl());
1✔
85
      if (parser != null) {
1✔
86
        try {
87
          Object parsedValue = parser.parse(value);
1✔
88
          parsedMetadata.put(key, parsedValue);
1✔
89
        } catch (ResourceInvalidException e) {
×
90
          throw new ResourceInvalidException(
×
91
              String.format("Failed to parse metadata key: %s, type: %s. Error: %s",
×
92
                  key, value.getTypeUrl(), e.getMessage()), e);
×
93
        }
1✔
94
      }
95
    }
1✔
96
    // building once to reuse in the next loop
97
    ImmutableMap<String, Object> intermediateParsedMetadata = parsedMetadata.build();
1✔
98

99
    // Process filter_metadata for remaining keys
100
    for (Map.Entry<String, Struct> entry : metadata.getFilterMetadataMap().entrySet()) {
1✔
101
      String key = entry.getKey();
1✔
102
      if (!intermediateParsedMetadata.containsKey(key)) {
1✔
103
        Struct structValue = entry.getValue();
1✔
104
        Object jsonValue = ProtobufJsonConverter.convertToJson(structValue);
1✔
105
        parsedMetadata.put(key, jsonValue);
1✔
106
      }
107
    }
1✔
108

109
    return parsedMetadata.build();
1✔
110
  }
111

112
  interface MetadataValueParser {
113

114
    String getTypeUrl();
115

116
    /**
117
     * Parses the given {@link Any} object into a specific metadata value.
118
     *
119
     * @param any the {@link Any} object to parse.
120
     * @return the parsed metadata value.
121
     * @throws ResourceInvalidException if the parsing fails.
122
     */
123
    Object parse(Any any) throws ResourceInvalidException;
124
  }
125
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc