MessageEncodingHeaderValidator.swift 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /*
  2. * Copyright 2020, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. struct MessageEncodingHeaderValidator {
  17. var encoding: ServerMessageEncoding
  18. enum ValidationResult {
  19. /// The requested compression is supported.
  20. case supported(
  21. algorithm: CompressionAlgorithm,
  22. decompressionLimit: DecompressionLimit,
  23. acceptEncoding: [String]
  24. )
  25. /// The `requestEncoding` is not supported; `acceptEncoding` contains all algorithms we do
  26. /// support.
  27. case unsupported(requestEncoding: String, acceptEncoding: [String])
  28. /// No compression was requested.
  29. case noCompression
  30. }
  31. /// Validates the value of the 'grpc-encoding' header against compression algorithms supported and
  32. /// advertised by this peer.
  33. ///
  34. /// - Parameter requestEncoding: The value of the 'grpc-encoding' header.
  35. func validate(requestEncoding: String?) -> ValidationResult {
  36. switch (self.encoding, requestEncoding) {
  37. // Compression is enabled and the client sent a message encoding header. Do we support it?
  38. case let (.enabled(configuration), .some(header)):
  39. guard let algorithm = CompressionAlgorithm(rawValue: header) else {
  40. return .unsupported(
  41. requestEncoding: header,
  42. acceptEncoding: configuration.enabledAlgorithms.map { $0.name }
  43. )
  44. }
  45. if configuration.enabledAlgorithms.contains(algorithm) {
  46. return .supported(
  47. algorithm: algorithm,
  48. decompressionLimit: configuration.decompressionLimit,
  49. acceptEncoding: []
  50. )
  51. } else {
  52. // From: https://github.com/grpc/grpc/blob/master/doc/compression.md
  53. //
  54. // Note that a peer MAY choose to not disclose all the encodings it supports. However, if
  55. // it receives a message compressed in an undisclosed but supported encoding, it MUST
  56. // include said encoding in the response's grpc-accept-encoding header.
  57. return .supported(
  58. algorithm: algorithm,
  59. decompressionLimit: configuration.decompressionLimit,
  60. acceptEncoding: configuration.enabledAlgorithms.map { $0.name } + CollectionOfOne(header)
  61. )
  62. }
  63. // Compression is disabled and the client sent a message encoding header. We don't support this
  64. // unless the header is "identity", which is no compression. Note this is different to the
  65. // supported but not advertised case since we have explicitly not enabled compression.
  66. case let (.disabled, .some(header)):
  67. guard let algorithm = CompressionAlgorithm(rawValue: header) else {
  68. return .unsupported(
  69. requestEncoding: header,
  70. acceptEncoding: []
  71. )
  72. }
  73. if algorithm == .identity {
  74. return .noCompression
  75. } else {
  76. return .unsupported(requestEncoding: header, acceptEncoding: [])
  77. }
  78. // The client didn't send a message encoding header.
  79. case (_, .none):
  80. return .noCompression
  81. }
  82. }
  83. }