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

grpc / grpc-java / #19711

24 Feb 2025 02:58PM UTC coverage: 88.545% (-0.08%) from 88.622%
#19711

push

github

web-flow
netty: Per-rpc authority verification against peer cert subject names (#11724)

Per-rpc verification of authority specified via call options or set by the LB API against peer cert's subject names.

34437 of 38892 relevant lines covered (88.55%)

0.89 hits per line

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

71.7
/../netty/src/main/java/io/grpc/netty/GrpcHttp2OutboundHeaders.java
1
/*
2
 * Copyright 2016 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.netty;
18

19
import io.netty.handler.codec.http2.Http2Headers;
20
import io.netty.util.AsciiString;
21
import java.util.Iterator;
22
import java.util.Map;
23
import java.util.NoSuchElementException;
24

25
/**
26
 * A custom implementation of Http2Headers that only includes methods used by gRPC.
27
 */
28
final class GrpcHttp2OutboundHeaders extends AbstractHttp2Headers {
29

30
  private final AsciiString[] normalHeaders;
31
  private final AsciiString[] preHeaders;
32
  private static final AsciiString[] EMPTY = new AsciiString[]{};
1✔
33

34
  static GrpcHttp2OutboundHeaders clientRequestHeaders(byte[][] serializedMetadata,
35
      AsciiString authority, AsciiString path, AsciiString method, AsciiString scheme,
36
      AsciiString userAgent) {
37
    AsciiString[] preHeaders = new AsciiString[] {
1✔
38
        Http2Headers.PseudoHeaderName.AUTHORITY.value(), authority,
1✔
39
        Http2Headers.PseudoHeaderName.PATH.value(), path,
1✔
40
        Http2Headers.PseudoHeaderName.METHOD.value(), method,
1✔
41
        Http2Headers.PseudoHeaderName.SCHEME.value(), scheme,
1✔
42
        Utils.CONTENT_TYPE_HEADER, Utils.CONTENT_TYPE_GRPC,
43
        Utils.TE_HEADER, Utils.TE_TRAILERS,
44
        Utils.USER_AGENT, userAgent,
45
    };
46
    return new GrpcHttp2OutboundHeaders(preHeaders, serializedMetadata);
1✔
47
  }
48

49
  static GrpcHttp2OutboundHeaders serverResponseHeaders(byte[][] serializedMetadata) {
50
    AsciiString[] preHeaders = new AsciiString[] {
1✔
51
        Http2Headers.PseudoHeaderName.STATUS.value(), Utils.STATUS_OK,
1✔
52
        Utils.CONTENT_TYPE_HEADER, Utils.CONTENT_TYPE_GRPC,
53
    };
54
    return new GrpcHttp2OutboundHeaders(preHeaders, serializedMetadata);
1✔
55
  }
56

57
  static GrpcHttp2OutboundHeaders serverResponseTrailers(byte[][] serializedMetadata) {
58
    return new GrpcHttp2OutboundHeaders(EMPTY, serializedMetadata);
1✔
59
  }
60

61
  private GrpcHttp2OutboundHeaders(AsciiString[] preHeaders, byte[][] serializedMetadata) {
1✔
62
    normalHeaders = new AsciiString[serializedMetadata.length];
1✔
63
    for (int i = 0; i < normalHeaders.length; i++) {
1✔
64
      normalHeaders[i] = new AsciiString(serializedMetadata[i], false);
1✔
65
    }
66
    this.preHeaders = preHeaders;
1✔
67
  }
1✔
68

69
  @Override
70
  public CharSequence authority() {
71
    for (int i = 0; i < preHeaders.length / 2; i++) {
1✔
72
      if (preHeaders[i * 2].equals(Http2Headers.PseudoHeaderName.AUTHORITY.value())) {
1✔
73
        return preHeaders[i * 2 + 1];
1✔
74
      }
75
    }
76
    return null;
×
77
  }
78

79
  @Override
80
  @SuppressWarnings("ReferenceEquality") // STATUS.value() never changes.
81
  public CharSequence status() {
82
    // preHeaders is never null.  It has status as the first element or not at all.
83
    if (preHeaders.length >= 2 && preHeaders[0] == Http2Headers.PseudoHeaderName.STATUS.value()) {
1✔
84
      return preHeaders[1];
1✔
85
    }
86
    return null;
1✔
87
  }
88

89
  @Override
90
  public Iterator<Map.Entry<CharSequence, CharSequence>> iterator() {
91
    return new Itr();
1✔
92
  }
93

94
  @Override
95
  public int size() {
96
    return (normalHeaders.length + preHeaders.length) / 2;
1✔
97
  }
98

99
  private class Itr implements Map.Entry<CharSequence, CharSequence>,
1✔
100
      Iterator<Map.Entry<CharSequence, CharSequence>> {
101
    private int idx;
102
    private AsciiString[] current = preHeaders.length != 0 ? preHeaders : normalHeaders;
1✔
103
    private AsciiString key;
104
    private AsciiString value;
105

106
    @Override
107
    public boolean hasNext() {
108
      return idx < current.length;
1✔
109
    }
110

111
    /**
112
     * This function is ordered specifically to get ideal performance on OpenJDK.  If you decide to
113
     * change it, even in ways that don't seem possible to affect performance, please benchmark
114
     * speeds before and after.
115
     */
116
    @Override
117
    public Map.Entry<CharSequence, CharSequence> next() {
118
      if (hasNext()) {
1✔
119
        key = current[idx];
1✔
120
        value = current[idx + 1];
1✔
121
        idx += 2;
1✔
122
        if (idx >= current.length && current == preHeaders) {
1✔
123
          current = normalHeaders;
1✔
124
          idx = 0;
1✔
125
        }
126
        return this;
1✔
127
      } else {
128
        throw new NoSuchElementException();
×
129
      }
130
    }
131

132
    @Override
133
    public CharSequence getKey() {
134
      return key;
1✔
135
    }
136

137
    @Override
138
    public CharSequence getValue() {
139
      return value;
1✔
140
    }
141

142
    @Override
143
    public CharSequence setValue(CharSequence value) {
144
      throw new UnsupportedOperationException();
×
145
    }
146

147
    @Override
148
    public void remove() {
149
      throw new UnsupportedOperationException();
×
150
    }
151
  }
152

153
  @Override
154
  public String toString() {
155
    StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append('[');
×
156
    String separator = "";
×
157
    for (Map.Entry<CharSequence, CharSequence> e : this) {
×
158
      CharSequence name = e.getKey();
×
159
      CharSequence value = e.getValue();
×
160
      builder.append(separator);
×
161
      builder.append(name).append(": ").append(value);
×
162
      separator = ", ";
×
163
    }
×
164
    builder.append(']');
×
165
    return builder.toString();
×
166
  }
167
}
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