ServerErrorProcessor.swift 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /*
  2. * Copyright 2021, 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. import NIOHPACK
  17. @usableFromInline
  18. internal enum ServerErrorProcessor {
  19. /// Processes a library error to form a `GRPCStatus` and trailers to send back to the client.
  20. /// - Parameter error: The error to process.
  21. /// - Returns: The status and trailers to send to the client.
  22. @usableFromInline
  23. internal static func processLibraryError(
  24. _ error: Error,
  25. delegate: ServerErrorDelegate?
  26. ) -> (GRPCStatus, HPACKHeaders) {
  27. // Observe the error if we have a delegate.
  28. delegate?.observeLibraryError(error)
  29. // What status are we terminating this RPC with?
  30. // - If we have a delegate, try transforming the error. If the delegate returns trailers, merge
  31. // them with any on the call context.
  32. // - If we don't have a delegate, then try to transform the error to a status.
  33. // - Fallback to a generic error.
  34. let status: GRPCStatus
  35. let trailers: HPACKHeaders
  36. if let transformed = delegate?.transformLibraryError(error) {
  37. status = transformed.status
  38. trailers = transformed.trailers ?? [:]
  39. } else if let grpcStatusTransformable = error as? GRPCStatusTransformable {
  40. status = grpcStatusTransformable.makeGRPCStatus()
  41. trailers = [:]
  42. } else {
  43. // Eh... well, we don't know what status to use. Use a generic one.
  44. status = .processingError(cause: error)
  45. trailers = [:]
  46. }
  47. return (status, trailers)
  48. }
  49. /// Processes an error, transforming it into a 'GRPCStatus' and any trailers to send to the peer.
  50. @usableFromInline
  51. internal static func processObserverError(
  52. _ error: Error,
  53. headers: HPACKHeaders,
  54. trailers: HPACKHeaders,
  55. delegate: ServerErrorDelegate?
  56. ) -> (GRPCStatus, HPACKHeaders) {
  57. // Observe the error if we have a delegate.
  58. delegate?.observeRequestHandlerError(error, headers: headers)
  59. // What status are we terminating this RPC with?
  60. // - If we have a delegate, try transforming the error. If the delegate returns trailers, merge
  61. // them with any on the call context.
  62. // - If we don't have a delegate, then try to transform the error to a status.
  63. // - Fallback to a generic error.
  64. let status: GRPCStatus
  65. let mergedTrailers: HPACKHeaders
  66. if let transformed = delegate?.transformRequestHandlerError(error, headers: headers) {
  67. status = transformed.status
  68. if var transformedTrailers = transformed.trailers {
  69. // The delegate returned trailers: merge in those from the context as well.
  70. transformedTrailers.add(contentsOf: trailers)
  71. mergedTrailers = transformedTrailers
  72. } else {
  73. mergedTrailers = trailers
  74. }
  75. } else if let grpcStatusTransformable = error as? GRPCStatusTransformable {
  76. status = grpcStatusTransformable.makeGRPCStatus()
  77. mergedTrailers = trailers
  78. } else {
  79. // Eh... well, we don't what status to use. Use a generic one.
  80. status = .processingError(cause: error)
  81. mergedTrailers = trailers
  82. }
  83. return (status, mergedTrailers)
  84. }
  85. }