• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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.okhttp;
18 
19 import com.google.common.base.Preconditions;
20 import io.grpc.InternalMetadata;
21 import io.grpc.Metadata;
22 import io.grpc.internal.GrpcUtil;
23 import io.grpc.internal.TransportFrameUtil;
24 import io.grpc.okhttp.internal.framed.Header;
25 import java.util.ArrayList;
26 import java.util.List;
27 import okio.ByteString;
28 
29 /**
30  * Constants for request/response headers.
31  */
32 class Headers {
33 
34   public static final Header HTTPS_SCHEME_HEADER = new Header(Header.TARGET_SCHEME, "https");
35   public static final Header HTTP_SCHEME_HEADER = new Header(Header.TARGET_SCHEME, "http");
36   public static final Header METHOD_HEADER = new Header(Header.TARGET_METHOD, GrpcUtil.HTTP_METHOD);
37   public static final Header METHOD_GET_HEADER = new Header(Header.TARGET_METHOD, "GET");
38   public static final Header CONTENT_TYPE_HEADER =
39       new Header(GrpcUtil.CONTENT_TYPE_KEY.name(), GrpcUtil.CONTENT_TYPE_GRPC);
40   public static final Header TE_HEADER = new Header("te", GrpcUtil.TE_TRAILERS);
41 
42   /**
43    * Serializes the given headers and creates a list of OkHttp {@link Header}s to be used when
44    * creating a stream. Since this serializes the headers, this method should be called in the
45    * application thread context.
46    */
createRequestHeaders( Metadata headers, String defaultPath, String authority, String userAgent, boolean useGet, boolean usePlaintext)47   public static List<Header> createRequestHeaders(
48       Metadata headers,
49       String defaultPath,
50       String authority,
51       String userAgent,
52       boolean useGet,
53       boolean usePlaintext) {
54     Preconditions.checkNotNull(headers, "headers");
55     Preconditions.checkNotNull(defaultPath, "defaultPath");
56     Preconditions.checkNotNull(authority, "authority");
57 
58     stripNonApplicationHeaders(headers);
59 
60     // 7 is the number of explicit add calls below.
61     List<Header> okhttpHeaders = new ArrayList<>(7 + InternalMetadata.headerCount(headers));
62 
63     // Set GRPC-specific headers.
64     if (usePlaintext) {
65       okhttpHeaders.add(HTTP_SCHEME_HEADER);
66     } else {
67       okhttpHeaders.add(HTTPS_SCHEME_HEADER);
68     }
69     if (useGet) {
70       okhttpHeaders.add(METHOD_GET_HEADER);
71     } else {
72       okhttpHeaders.add(METHOD_HEADER);
73     }
74 
75     okhttpHeaders.add(new Header(Header.TARGET_AUTHORITY, authority));
76     String path = defaultPath;
77     okhttpHeaders.add(new Header(Header.TARGET_PATH, path));
78 
79     okhttpHeaders.add(new Header(GrpcUtil.USER_AGENT_KEY.name(), userAgent));
80 
81     // All non-pseudo headers must come after pseudo headers.
82     okhttpHeaders.add(CONTENT_TYPE_HEADER);
83     okhttpHeaders.add(TE_HEADER);
84 
85     // Now add any application-provided headers.
86     return addMetadata(okhttpHeaders, headers);
87   }
88 
89   /**
90    * Serializes the given headers and creates a list of OkHttp {@link Header}s to be used when
91    * starting a response. Since this serializes the headers, this method should be called in the
92    * application thread context.
93    */
createResponseHeaders(Metadata headers)94   public static List<Header> createResponseHeaders(Metadata headers) {
95     stripNonApplicationHeaders(headers);
96 
97     // 2 is the number of explicit add calls below.
98     List<Header> okhttpHeaders = new ArrayList<>(2 + InternalMetadata.headerCount(headers));
99     okhttpHeaders.add(new Header(Header.RESPONSE_STATUS, "200"));
100     // All non-pseudo headers must come after pseudo headers.
101     okhttpHeaders.add(CONTENT_TYPE_HEADER);
102     return addMetadata(okhttpHeaders, headers);
103   }
104 
105   /**
106    * Serializes the given headers and creates a list of OkHttp {@link Header}s to be used when
107    * finishing a response. Since this serializes the headers, this method should be called in the
108    * application thread context.
109    */
createResponseTrailers(Metadata trailers, boolean headersSent)110   public static List<Header> createResponseTrailers(Metadata trailers, boolean headersSent) {
111     if (!headersSent) {
112       return createResponseHeaders(trailers);
113     }
114     stripNonApplicationHeaders(trailers);
115 
116     List<Header> okhttpTrailers = new ArrayList<>(InternalMetadata.headerCount(trailers));
117     return addMetadata(okhttpTrailers, trailers);
118   }
119 
120   /**
121    * Serializes the given headers and creates a list of OkHttp {@link Header}s to be used when
122    * failing with an HTTP response.
123    */
createHttpResponseHeaders( int httpCode, String contentType, Metadata headers)124   public static List<Header> createHttpResponseHeaders(
125       int httpCode, String contentType, Metadata headers) {
126     // 2 is the number of explicit add calls below.
127     List<Header> okhttpHeaders = new ArrayList<>(2 + InternalMetadata.headerCount(headers));
128     okhttpHeaders.add(new Header(Header.RESPONSE_STATUS, "" + httpCode));
129     // All non-pseudo headers must come after pseudo headers.
130     okhttpHeaders.add(new Header(GrpcUtil.CONTENT_TYPE_KEY.name(), contentType));
131     return addMetadata(okhttpHeaders, headers);
132   }
133 
addMetadata(List<Header> okhttpHeaders, Metadata toAdd)134   private static List<Header> addMetadata(List<Header> okhttpHeaders, Metadata toAdd) {
135     byte[][] serializedHeaders = TransportFrameUtil.toHttp2Headers(toAdd);
136     for (int i = 0; i < serializedHeaders.length; i += 2) {
137       ByteString key = ByteString.of(serializedHeaders[i]);
138       // Don't allow HTTP/2 pseudo headers to be added by the application.
139       if (key.size() == 0 || key.getByte(0) == ':') {
140         continue;
141       }
142       ByteString value = ByteString.of(serializedHeaders[i + 1]);
143       okhttpHeaders.add(new Header(key, value));
144     }
145     return okhttpHeaders;
146   }
147 
148   /** Strips all non-pseudo headers reserved by gRPC, to avoid duplicates and misinterpretation. */
stripNonApplicationHeaders(Metadata headers)149   private static void stripNonApplicationHeaders(Metadata headers) {
150     headers.discardAll(GrpcUtil.CONTENT_TYPE_KEY);
151     headers.discardAll(GrpcUtil.TE_HEADER);
152     headers.discardAll(GrpcUtil.USER_AGENT_KEY);
153   }
154 }
155