1
#pragma once
2

            
3
#include <string>
4
#include <tuple>
5

            
6
#include "envoy/http/header_map.h"
7
#include "envoy/http/protocol.h"
8

            
9
namespace Envoy {
10
namespace Http {
11

            
12
/**
13
 * Common interface for server and client header validators.
14
 */
15
class HeaderValidator {
16
public:
17
554
  virtual ~HeaderValidator() = default;
18

            
19
  // A class that holds either success condition or an error condition with tuple of
20
  // action and error details.
21
  template <typename ActionType> class Result {
22
  public:
23
    using Action = ActionType;
24

            
25
    // Helper for constructing successful results
26
20838
    static Result success() { return Result(ActionType::Accept, absl::string_view()); }
27

            
28
24730
    Result(ActionType action, absl::string_view details) : result_(action, details) {
29
24730
      ENVOY_BUG(action == ActionType::Accept || !details.empty(),
30
24730
                "Error details must not be empty in case of an error");
31
24730
    }
32

            
33
24270
    bool ok() const { return std::get<0>(result_) == ActionType::Accept; }
34
1136
    operator bool() const { return ok(); }
35
6541
    absl::string_view details() const { return std::get<1>(result_); }
36
3816
    Action action() const { return std::get<0>(result_); }
37

            
38
  private:
39
    const std::tuple<ActionType, std::string> result_;
40
  };
41

            
42
  enum class RejectAction { Accept, Reject };
43
  enum class RejectOrRedirectAction { Accept, Reject, Redirect };
44
  using RejectResult = Result<RejectAction>;
45
  using RejectOrRedirectResult = Result<RejectOrRedirectAction>;
46
  using TransformationResult = RejectResult;
47

            
48
  /**
49
   * Validate the entire request header map.
50
   * Returning the Reject value form this method causes the HTTP request to be rejected with 400
51
   * status, and the gRPC request with the INTERNAL (13) error code.
52
   */
53
  using ValidationResult = RejectResult;
54
  virtual ValidationResult validateRequestHeaders(const RequestHeaderMap& header_map) PURE;
55

            
56
  /**
57
   * Validate the entire response header map.
58
   * Returning the Reject value causes the HTTP request to be rejected with the 502 status,
59
   * and the gRPC request with the UNAVAILABLE (14) error code.
60
   */
61
  virtual ValidationResult validateResponseHeaders(const ResponseHeaderMap& header_map) PURE;
62

            
63
  /**
64
   * Validate the entire request trailer map.
65
   * Returning the Reject value causes the HTTP request to be rejected with the 502 status,
66
   * and the gRPC request with the UNAVAILABLE (14) error code.
67
   * If response headers have already been sent the request is reset.
68
   */
69
  virtual ValidationResult validateRequestTrailers(const RequestTrailerMap& trailer_map) PURE;
70

            
71
  /**
72
   * Validate the entire response trailer map.
73
   * Returning the Reject value causes the HTTP request to be reset.
74
   */
75
  virtual ValidationResult validateResponseTrailers(const ResponseTrailerMap& trailer_map) PURE;
76
};
77

            
78
/**
79
 * Interface for server header validators.
80
 */
81
class ServerHeaderValidator : public HeaderValidator {
82
public:
83
513
  ~ServerHeaderValidator() override = default;
84

            
85
  /**
86
   * Transform the entire request header map.
87
   * This method transforms the header map, for example by normalizing URI path, before processing
88
   * by the filter chain.
89
   * Returning the Reject value from this method causes the HTTP request to be rejected with 400
90
   * status, and the gRPC request with the INTERNAL (13) error code. Returning the Redirect
91
   * value causes the HTTP request to be redirected to the :path presudo header in the request map.
92
   * The gRPC request will still be rejected with the INTERNAL (13) error code.
93
   */
94
  using RequestHeadersTransformationResult = RejectOrRedirectResult;
95
  virtual RequestHeadersTransformationResult
96
  transformRequestHeaders(RequestHeaderMap& header_map) PURE;
97

            
98
  /**
99
   * Transform the entire request trailer map.
100
   * Returning the Reject value causes the HTTP request to be rejected with the 502 status,
101
   * and the gRPC request with the UNAVAILABLE (14) error code.
102
   * If response headers have already been sent the request is reset.
103
   */
104
  virtual TransformationResult transformRequestTrailers(RequestTrailerMap& header_map) PURE;
105

            
106
  /**
107
   * Transform the entire response header map.
108
   * HTTP/2 and HTTP/3 server header validator may transform the HTTP/1 upgrade response
109
   * to HTTP/2 extended CONNECT response, iff it transformed extended CONNECT to upgrade request
110
   * during request validation.
111
   * Returning the Reject value causes the HTTP request to be rejected with the 502 status,
112
   * and the gRPC request with the UNAVAILABLE (14) error code.
113
   */
114
  struct ResponseHeadersTransformationResult {
115
10
    static ResponseHeadersTransformationResult success() {
116
10
      return ResponseHeadersTransformationResult{RejectResult::success(), nullptr};
117
10
    }
118
    RejectResult status;
119
    ResponseHeaderMapPtr new_headers;
120
  };
121
  virtual ResponseHeadersTransformationResult
122
  transformResponseHeaders(const ResponseHeaderMap& header_map) PURE;
123
};
124

            
125
/**
126
 * Interface for server header validators.
127
 */
128
class ClientHeaderValidator : public HeaderValidator {
129
public:
130
41
  ~ClientHeaderValidator() override = default;
131

            
132
  /**
133
   * Transform the entire request header map.
134
   * This method can not mutate the header map as it is immutable after the terminal decoder filter.
135
   * However HTTP/2 and HTTP/3 header validators may need to change the request from the HTTP/1
136
   * upgrade to to the extended CONNECT. In this case the new header map is returned in the
137
   * `new_headers` member of the returned structure. Returning the Reject value form this method
138
   * causes the HTTP request to be rejected with 400 status, and the gRPC request with the INTERNAL
139
   * (13) error code.
140
   */
141
  struct RequestHeadersTransformationResult {
142
1
    static RequestHeadersTransformationResult success() {
143
1
      return RequestHeadersTransformationResult{RejectResult::success(), nullptr};
144
1
    }
145
    RejectResult status;
146
    RequestHeaderMapPtr new_headers;
147
  };
148
  virtual RequestHeadersTransformationResult
149
  transformRequestHeaders(const RequestHeaderMap& header_map) PURE;
150

            
151
  /**
152
   * Transform the entire response header map.
153
   * HTTP/2 and HTTP/3 client header validator may transform the extended CONNECT response
154
   * to HTTP/1 upgrade response, iff it transformed upgrade request to extended CONNECT
155
   * during request validation.
156
   * Returning the Reject value causes the HTTP request to be rejected with the 502 status,
157
   * and the gRPC request with the UNAVAILABLE (14) error code.
158
   */
159
  virtual TransformationResult transformResponseHeaders(ResponseHeaderMap& header_map) PURE;
160
};
161

            
162
using ServerHeaderValidatorPtr = std::unique_ptr<ServerHeaderValidator>;
163
using ClientHeaderValidatorPtr = std::unique_ptr<ClientHeaderValidator>;
164

            
165
/**
166
 * Interface for stats.
167
 */
168
class HeaderValidatorStats {
169
public:
170
83591
  virtual ~HeaderValidatorStats() = default;
171

            
172
  virtual void incDroppedHeadersWithUnderscores() PURE;
173
  virtual void incRequestsRejectedWithUnderscoresInHeaders() PURE;
174
  virtual void incMessagingError() PURE;
175
};
176

            
177
/**
178
 * Interface for creating header validators.
179
 * TODO(yanavlasov): split into factories dedicated to server and client header validators.
180
 */
181
class HeaderValidatorFactory {
182
public:
183
246
  virtual ~HeaderValidatorFactory() = default;
184

            
185
  /**
186
   * Create a new header validator for the specified protocol.
187
   */
188
  virtual ServerHeaderValidatorPtr createServerHeaderValidator(Protocol protocol,
189
                                                               HeaderValidatorStats& stats) PURE;
190
  virtual ClientHeaderValidatorPtr createClientHeaderValidator(Protocol protocol,
191
                                                               HeaderValidatorStats& stats) PURE;
192
};
193

            
194
using HeaderValidatorFactoryPtr = std::unique_ptr<HeaderValidatorFactory>;
195

            
196
} // namespace Http
197
} // namespace Envoy