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 static io.grpc.internal.GrpcUtil.CONTENT_TYPE_KEY; 20 import static io.grpc.internal.GrpcUtil.USER_AGENT_KEY; 21 22 import com.google.common.base.Preconditions; 23 import io.grpc.InternalMetadata; 24 import io.grpc.Metadata; 25 import io.grpc.internal.GrpcUtil; 26 import io.grpc.internal.TransportFrameUtil; 27 import io.grpc.okhttp.internal.framed.Header; 28 import java.util.ArrayList; 29 import java.util.List; 30 import okio.ByteString; 31 32 /** 33 * Constants for request/response headers. 34 */ 35 class Headers { 36 37 public static final Header SCHEME_HEADER = new Header(Header.TARGET_SCHEME, "https"); 38 public static final Header METHOD_HEADER = new Header(Header.TARGET_METHOD, GrpcUtil.HTTP_METHOD); 39 public static final Header METHOD_GET_HEADER = new Header(Header.TARGET_METHOD, "GET"); 40 public static final Header CONTENT_TYPE_HEADER = 41 new Header(CONTENT_TYPE_KEY.name(), GrpcUtil.CONTENT_TYPE_GRPC); 42 public static final Header TE_HEADER = new Header("te", GrpcUtil.TE_TRAILERS); 43 44 /** 45 * Serializes the given headers and creates a list of OkHttp {@link Header}s to be used when 46 * creating a stream. Since this serializes the headers, this method should be called in the 47 * application thread context. 48 */ createRequestHeaders( Metadata headers, String defaultPath, String authority, String userAgent, boolean useGet)49 public static List<Header> createRequestHeaders( 50 Metadata headers, String defaultPath, String authority, String userAgent, boolean useGet) { 51 Preconditions.checkNotNull(headers, "headers"); 52 Preconditions.checkNotNull(defaultPath, "defaultPath"); 53 Preconditions.checkNotNull(authority, "authority"); 54 55 // Discard any application supplied duplicates of the reserved headers 56 headers.discardAll(GrpcUtil.CONTENT_TYPE_KEY); 57 headers.discardAll(GrpcUtil.TE_HEADER); 58 headers.discardAll(GrpcUtil.USER_AGENT_KEY); 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 okhttpHeaders.add(SCHEME_HEADER); 65 if (useGet) { 66 okhttpHeaders.add(METHOD_GET_HEADER); 67 } else { 68 okhttpHeaders.add(METHOD_HEADER); 69 } 70 71 okhttpHeaders.add(new Header(Header.TARGET_AUTHORITY, authority)); 72 String path = defaultPath; 73 okhttpHeaders.add(new Header(Header.TARGET_PATH, path)); 74 75 okhttpHeaders.add(new Header(GrpcUtil.USER_AGENT_KEY.name(), userAgent)); 76 77 // All non-pseudo headers must come after pseudo headers. 78 okhttpHeaders.add(CONTENT_TYPE_HEADER); 79 okhttpHeaders.add(TE_HEADER); 80 81 // Now add any application-provided headers. 82 byte[][] serializedHeaders = TransportFrameUtil.toHttp2Headers(headers); 83 for (int i = 0; i < serializedHeaders.length; i += 2) { 84 ByteString key = ByteString.of(serializedHeaders[i]); 85 String keyString = key.utf8(); 86 if (isApplicationHeader(keyString)) { 87 ByteString value = ByteString.of(serializedHeaders[i + 1]); 88 okhttpHeaders.add(new Header(key, value)); 89 } 90 } 91 92 return okhttpHeaders; 93 } 94 95 /** 96 * Returns {@code true} if the given header is an application-provided header. Otherwise, returns 97 * {@code false} if the header is reserved by GRPC. 98 */ isApplicationHeader(String key)99 private static boolean isApplicationHeader(String key) { 100 // Don't allow HTTP/2 pseudo headers or content-type to be added by the application. 101 return (!key.startsWith(":") 102 && !CONTENT_TYPE_KEY.name().equalsIgnoreCase(key)) 103 && !USER_AGENT_KEY.name().equalsIgnoreCase(key); 104 } 105 } 106