1
#pragma once
2

            
3
#include "envoy/extensions/http/header_validators/envoy_default/v3/header_validator.pb.h"
4
#include "envoy/http/header_validator.h"
5

            
6
#include "source/extensions/http/header_validators/envoy_default/config_overrides.h"
7

            
8
namespace Envoy {
9
namespace Extensions {
10
namespace Http {
11
namespace HeaderValidators {
12
namespace EnvoyDefault {
13

            
14
class PathNormalizer {
15
public:
16
  PathNormalizer(
17
      const envoy::extensions::http::header_validators::envoy_default::v3::HeaderValidatorConfig&
18
          config,
19
      const ConfigOverrides& config_overrides);
20

            
21
  using PathNormalizationResult = ::Envoy::Http::HeaderValidator::RejectOrRedirectResult;
22

            
23
  /*
24
   * Normalize the path component of the :path header and update the header value. This method does
25
   * not perform any validation of the normalized :path such as validating the character set.
26
   */
27
  PathNormalizationResult normalizePathUri(::Envoy::Http::RequestHeaderMap& header_map) const;
28

            
29
  /*
30
   * The result of attempting to normalize and decode a percent-encoded octet.
31
   */
32
  enum class PercentDecodeResult {
33
    // The percent encoding is invalid and could not be decoded.
34
    Invalid,
35
    // The percent encoding is valid but decodes to an unallowed character.
36
    Reject,
37
    // The percent encoding is valid and was normalized to UPPERCASE.
38
    Normalized,
39
    // The percent encoding is valid and was decoded.
40
    Decoded,
41
    // The percent ending is valid, was decoded, and, based on the active configuration, the
42
    // response should redirect to the normalized path.
43
    DecodedRedirect
44
  };
45

            
46
  /*
47
   * A decoded octet consisting of the decode result and the decoded character.
48
   */
49
  class DecodedOctet {
50
  public:
51
87
    DecodedOctet(PercentDecodeResult result, char octet = '\0') : result_(result), octet_(octet) {}
52

            
53
87
    PercentDecodeResult result() const { return result_; }
54
34
    char octet() const { return octet_; }
55

            
56
  private:
57
    PercentDecodeResult result_;
58
    char octet_;
59
  };
60

            
61
  /*
62
   * Normalize a percent encoded octet (%XX) to uppercase and attempt to decode to a character. The
63
   * octet argument must start with the "%" character and is normalized in-place to UPPERCASE.
64
   */
65
  DecodedOctet normalizeAndDecodeOctet(std::string::iterator iter, std::string::iterator end) const;
66

            
67
private:
68
  /*
69
   * Normalization pass: normalize percent-encoded octets to UPPERCASE and decode valid octets.
70
   */
71
  PathNormalizationResult decodePass(std::string& path) const;
72
  /*
73
   * Normalization pass: merge duplicate slashes.
74
   */
75
  PathNormalizationResult mergeSlashesPass(std::string& path) const;
76
  /*
77
   * Normalization pass: collapse dot and dot-dot segments.
78
   */
79
  PathNormalizationResult collapseDotSegmentsPass(std::string& path) const;
80
  /*
81
   * Split the path and query parameters / fragment components. The return value is a 2-item tuple:
82
   * (path, query_params).
83
   */
84
  std::tuple<absl::string_view, absl::string_view>
85
  splitPathAndQueryParams(absl::string_view path_and_query_params) const;
86
  /**
87
   * Translate backslash to forward slash. Enabled by the
88
   * envoy.reloadable_features.uhv_translate_backslash_to_slash flag.
89
   */
90
  void translateBackToForwardSlashes(std::string& path) const;
91

            
92
  const envoy::extensions::http::header_validators::envoy_default::v3::HeaderValidatorConfig
93
      config_;
94
  const ConfigOverrides config_overrides_;
95
};
96

            
97
using PathNormalizerPtr = std::unique_ptr<PathNormalizer>;
98

            
99
} // namespace EnvoyDefault
100
} // namespace HeaderValidators
101
} // namespace Http
102
} // namespace Extensions
103
} // namespace Envoy