001// Copyright 2019 Google LLC 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package com.google.cloud.functions; 016 017import java.io.BufferedReader; 018import java.io.IOException; 019import java.io.InputStream; 020import java.util.List; 021import java.util.Map; 022import java.util.Optional; 023 024/** Represents an HTTP message, either an HTTP request or a part of a multipart HTTP request. */ 025public interface HttpMessage { 026 /** 027 * Returns the value of the {@code Content-Type} header, if any. 028 * 029 * @return the content type, if any. 030 */ 031 Optional<String> getContentType(); 032 033 /** 034 * Returns the numeric value of the {@code Content-Length} header. 035 * 036 * @return the content length. 037 */ 038 long getContentLength(); 039 040 /** 041 * Returns the character encoding specified in the {@code Content-Type} header, or {@code 042 * Optional.empty()} if there is no {@code Content-Type} header or it does not have the {@code 043 * charset} parameter. 044 * 045 * @return the character encoding for the content type, if one is specified. 046 */ 047 Optional<String> getCharacterEncoding(); 048 049 /** 050 * Returns an {@link InputStream} that can be used to read the body of this HTTP request. Every 051 * call to this method on the same {@link HttpMessage} will return the same object. This method is 052 * typically used to read binary data. If the body is text, the {@link #getReader()} method is 053 * more appropriate. 054 * 055 * @return an {@link InputStream} that can be used to read the body of this HTTP request. 056 * @throws IOException if a valid {@link InputStream} cannot be returned for some reason. 057 * @throws IllegalStateException if {@link #getReader()} has already been called on this instance. 058 */ 059 InputStream getInputStream() throws IOException; 060 061 /** 062 * Returns a {@link BufferedReader} that can be used to read the text body of this HTTP request. 063 * Every call to this method on the same {@link HttpMessage} will return the same object. 064 * 065 * @return a {@link BufferedReader} that can be used to read the text body of this HTTP request. 066 * @throws IOException if a valid {@link BufferedReader} cannot be returned for some reason. 067 * @throws IllegalStateException if {@link #getInputStream()} has already been called on this 068 * instance. 069 */ 070 BufferedReader getReader() throws IOException; 071 072 /** 073 * Returns a map describing the headers of this HTTP request, or this part of a multipart request. 074 * If the headers look like this... 075 * 076 * <pre> 077 * Content-Type: text/plain 078 * Some-Header: some value 079 * Some-Header: another value 080 * </pre> 081 * 082 * ...then the returned value will map {@code "Content-Type"} to a one-element list containing 083 * {@code "text/plain"}, and {@code "Some-Header"} to a two-element list containing {@code "some 084 * value"} and {@code "another value"}. 085 * 086 * @return a map where each key is an HTTP header and the corresponding {@code List} value has one 087 * element for each occurrence of that header. 088 */ 089 Map<String, List<String>> getHeaders(); 090 091 /** 092 * Convenience method that returns the value of the first header with the given name. If the 093 * headers look like this... 094 * 095 * <pre> 096 * Content-Type: text/plain 097 * Some-Header: some value 098 * Some-Header: another value 099 * </pre> 100 * 101 * ...then {@code getFirstHeader("Some-Header")} will return {@code Optional.of("some value")}, 102 * and {@code getFirstHeader("Another-Header")} will return {@code Optional.empty()}. 103 * 104 * @param name an HTTP header name. 105 * @return the first value of the given header, if present. 106 */ 107 default Optional<String> getFirstHeader(String name) { 108 List<String> headers = getHeaders().get(name); 109 if (headers == null || headers.isEmpty()) { 110 return Optional.empty(); 111 } 112 return Optional.of(headers.get(0)); 113 } 114}