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/** 025 * Represents an HTTP message, either an HTTP request or a part of a multipart HTTP request. 026 */ 027public interface HttpMessage { 028 /** Returns the value of the {@code Content-Type} header, if any. */ 029 Optional<String> getContentType(); 030 031 /** Returns the numeric value of the {@code Content-Length} header. */ 032 long getContentLength(); 033 034 /** 035 * Returns the character encoding specified in the {@code Content-Type} header, 036 * or {@code Optional.empty()} if there is no {@code Content-Type} header or it does not have the 037 * {@code charset} parameter. 038 */ 039 Optional<String> getCharacterEncoding(); 040 041 /** 042 * Returns an {@link InputStream} that can be used to read the body of this HTTP request. 043 * Every call to this method on the same {@link HttpMessage} will return the same object. 044 * This method is typically used to read binary data. If the body is text, the 045 * {@link #getReader()} method is more appropriate. 046 * 047 * @throws IOException if a valid {@link InputStream} cannot be returned for some reason. 048 * @throws IllegalStateException if {@link #getReader()} has already been called on this instance. 049 */ 050 InputStream getInputStream() throws IOException; 051 052 /** 053 * Returns a {@link BufferedReader} that can be used to read the text body of this HTTP request. 054 * Every call to this method on the same {@link HttpMessage} will return the same object. 055 * 056 * @throws IOException if a valid {@link BufferedReader} cannot be returned for some reason. 057 * @throws IllegalStateException if {@link #getInputStream()} has already been called on this 058 * instance. 059 */ 060 BufferedReader getReader() throws IOException; 061 062 /** 063 * Returns a map describing the headers of this HTTP request, or this part of a multipart 064 * request. If the headers look like this... 065 * 066 * <pre> 067 * Content-Type: text/plain 068 * Some-Header: some value 069 * Some-Header: another value 070 * </pre> 071 * 072 * ...then the returned value will map {@code Content-Type} to a one-element list containing 073 * {@code text/plain}, and {@code Some-Header} to a two-element list containing {@code some value} 074 * and {@code another value}. 075 */ 076 Map<String, List<String>> getHeaders(); 077 078 /** 079 * Convenience method that returns the value of the first header with the given name. If the 080 * headers look like this... 081 * 082 * <pre> 083 * Content-Type: text/plain 084 * Some-Header: some value 085 * Some-Header: another value 086 * </pre> 087 * 088 * ...then {@code getFirstHeader("Some-Header")} will return {@code Optional.of("some value")}, 089 * and {@code getFirstHeader("Another-Header")} will return {@code Optional.empty()}. 090 */ 091 default Optional<String> getFirstHeader(String name) { 092 List<String> headers = getHeaders().get(name); 093 if (headers == null || headers.isEmpty()) { 094 return Optional.empty(); 095 } 096 return Optional.of(headers.get(0)); 097 } 098}