blob: cb71846eb00818127a50b35bb5fcab8c82da2aa2 [file] [log] [blame]
/*
* Copyright 2014 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.okhttp;
import static io.grpc.internal.GrpcUtil.CONTENT_TYPE_KEY;
import static io.grpc.internal.GrpcUtil.USER_AGENT_KEY;
import com.google.common.base.Preconditions;
import io.grpc.InternalMetadata;
import io.grpc.Metadata;
import io.grpc.internal.GrpcUtil;
import io.grpc.internal.TransportFrameUtil;
import io.grpc.okhttp.internal.framed.Header;
import java.util.ArrayList;
import java.util.List;
import okio.ByteString;
/**
* Constants for request/response headers.
*/
class Headers {
public static final Header SCHEME_HEADER = new Header(Header.TARGET_SCHEME, "https");
public static final Header METHOD_HEADER = new Header(Header.TARGET_METHOD, GrpcUtil.HTTP_METHOD);
public static final Header METHOD_GET_HEADER = new Header(Header.TARGET_METHOD, "GET");
public static final Header CONTENT_TYPE_HEADER =
new Header(CONTENT_TYPE_KEY.name(), GrpcUtil.CONTENT_TYPE_GRPC);
public static final Header TE_HEADER = new Header("te", GrpcUtil.TE_TRAILERS);
/**
* Serializes the given headers and creates a list of OkHttp {@link Header}s to be used when
* creating a stream. Since this serializes the headers, this method should be called in the
* application thread context.
*/
public static List<Header> createRequestHeaders(
Metadata headers, String defaultPath, String authority, String userAgent, boolean useGet) {
Preconditions.checkNotNull(headers, "headers");
Preconditions.checkNotNull(defaultPath, "defaultPath");
Preconditions.checkNotNull(authority, "authority");
// Discard any application supplied duplicates of the reserved headers
headers.discardAll(GrpcUtil.CONTENT_TYPE_KEY);
headers.discardAll(GrpcUtil.TE_HEADER);
headers.discardAll(GrpcUtil.USER_AGENT_KEY);
// 7 is the number of explicit add calls below.
List<Header> okhttpHeaders = new ArrayList<>(7 + InternalMetadata.headerCount(headers));
// Set GRPC-specific headers.
okhttpHeaders.add(SCHEME_HEADER);
if (useGet) {
okhttpHeaders.add(METHOD_GET_HEADER);
} else {
okhttpHeaders.add(METHOD_HEADER);
}
okhttpHeaders.add(new Header(Header.TARGET_AUTHORITY, authority));
String path = defaultPath;
okhttpHeaders.add(new Header(Header.TARGET_PATH, path));
okhttpHeaders.add(new Header(GrpcUtil.USER_AGENT_KEY.name(), userAgent));
// All non-pseudo headers must come after pseudo headers.
okhttpHeaders.add(CONTENT_TYPE_HEADER);
okhttpHeaders.add(TE_HEADER);
// Now add any application-provided headers.
byte[][] serializedHeaders = TransportFrameUtil.toHttp2Headers(headers);
for (int i = 0; i < serializedHeaders.length; i += 2) {
ByteString key = ByteString.of(serializedHeaders[i]);
String keyString = key.utf8();
if (isApplicationHeader(keyString)) {
ByteString value = ByteString.of(serializedHeaders[i + 1]);
okhttpHeaders.add(new Header(key, value));
}
}
return okhttpHeaders;
}
/**
* Returns {@code true} if the given header is an application-provided header. Otherwise, returns
* {@code false} if the header is reserved by GRPC.
*/
private static boolean isApplicationHeader(String key) {
// Don't allow HTTP/2 pseudo headers or content-type to be added by the application.
return (!key.startsWith(":")
&& !CONTENT_TYPE_KEY.name().equalsIgnoreCase(key))
&& !USER_AGENT_KEY.name().equalsIgnoreCase(key);
}
}