HTTP2ToRawGRPCStateMachine.swift 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271
  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. import Logging
  17. import NIOCore
  18. import NIOHPACK
  19. import NIOHTTP2
  20. struct HTTP2ToRawGRPCStateMachine {
  21. /// The current state.
  22. private var state: State = .requestIdleResponseIdle
  23. }
  24. extension HTTP2ToRawGRPCStateMachine {
  25. enum State {
  26. // Both peers are idle. Nothing has happened to the stream.
  27. case requestIdleResponseIdle
  28. // Received valid headers. Nothing has been sent in response.
  29. case requestOpenResponseIdle(RequestOpenResponseIdleState)
  30. // Received valid headers and request(s). Response headers have been sent.
  31. case requestOpenResponseOpen(RequestOpenResponseOpenState)
  32. // Received valid headers and request(s) but not end of the request stream. Response stream has
  33. // been closed.
  34. case requestOpenResponseClosed
  35. // The request stream is closed. Nothing has been sent in response.
  36. case requestClosedResponseIdle(RequestClosedResponseIdleState)
  37. // The request stream is closed. Response headers have been sent.
  38. case requestClosedResponseOpen(RequestClosedResponseOpenState)
  39. // Both streams are closed. This state is terminal.
  40. case requestClosedResponseClosed
  41. }
  42. struct RequestOpenResponseIdleState {
  43. /// A length prefixed message reader for request messages.
  44. var reader: LengthPrefixedMessageReader
  45. /// A length prefixed message writer for response messages.
  46. var writer: CoalescingLengthPrefixedMessageWriter
  47. /// The content type of the RPC.
  48. var contentType: ContentType
  49. /// An accept encoding header to send in the response headers indicating the message encoding
  50. /// that the server supports.
  51. var acceptEncoding: String?
  52. /// A message encoding header to send in the response headers indicating the encoding which will
  53. /// be used for responses.
  54. var responseEncoding: String?
  55. /// Whether to normalize user-provided metadata.
  56. var normalizeHeaders: Bool
  57. /// The pipeline configuration state.
  58. var configurationState: ConfigurationState
  59. }
  60. struct RequestClosedResponseIdleState {
  61. /// A length prefixed message reader for request messages.
  62. var reader: LengthPrefixedMessageReader
  63. /// A length prefixed message writer for response messages.
  64. var writer: CoalescingLengthPrefixedMessageWriter
  65. /// The content type of the RPC.
  66. var contentType: ContentType
  67. /// An accept encoding header to send in the response headers indicating the message encoding
  68. /// that the server supports.
  69. var acceptEncoding: String?
  70. /// A message encoding header to send in the response headers indicating the encoding which will
  71. /// be used for responses.
  72. var responseEncoding: String?
  73. /// Whether to normalize user-provided metadata.
  74. var normalizeHeaders: Bool
  75. /// The pipeline configuration state.
  76. var configurationState: ConfigurationState
  77. init(from state: RequestOpenResponseIdleState) {
  78. self.reader = state.reader
  79. self.writer = state.writer
  80. self.contentType = state.contentType
  81. self.acceptEncoding = state.acceptEncoding
  82. self.responseEncoding = state.responseEncoding
  83. self.normalizeHeaders = state.normalizeHeaders
  84. self.configurationState = state.configurationState
  85. }
  86. }
  87. struct RequestOpenResponseOpenState {
  88. /// A length prefixed message reader for request messages.
  89. var reader: LengthPrefixedMessageReader
  90. /// A length prefixed message writer for response messages.
  91. var writer: CoalescingLengthPrefixedMessageWriter
  92. /// Whether to normalize user-provided metadata.
  93. var normalizeHeaders: Bool
  94. init(from state: RequestOpenResponseIdleState) {
  95. self.reader = state.reader
  96. self.writer = state.writer
  97. self.normalizeHeaders = state.normalizeHeaders
  98. }
  99. }
  100. struct RequestClosedResponseOpenState {
  101. /// A length prefixed message reader for request messages.
  102. var reader: LengthPrefixedMessageReader
  103. /// A length prefixed message writer for response messages.
  104. var writer: CoalescingLengthPrefixedMessageWriter
  105. /// Whether to normalize user-provided metadata.
  106. var normalizeHeaders: Bool
  107. init(from state: RequestOpenResponseOpenState) {
  108. self.reader = state.reader
  109. self.writer = state.writer
  110. self.normalizeHeaders = state.normalizeHeaders
  111. }
  112. init(from state: RequestClosedResponseIdleState) {
  113. self.reader = state.reader
  114. self.writer = state.writer
  115. self.normalizeHeaders = state.normalizeHeaders
  116. }
  117. }
  118. /// The pipeline configuration state.
  119. enum ConfigurationState {
  120. /// The pipeline is being configured. Any message data will be buffered into an appropriate
  121. /// message reader.
  122. case configuring(HPACKHeaders)
  123. /// The pipeline is configured.
  124. case configured
  125. /// Returns true if the configuration is in the `.configured` state.
  126. var isConfigured: Bool {
  127. switch self {
  128. case .configuring:
  129. return false
  130. case .configured:
  131. return true
  132. }
  133. }
  134. /// Configuration has completed.
  135. mutating func configured() -> HPACKHeaders {
  136. switch self {
  137. case .configured:
  138. preconditionFailure("Invalid state: already configured")
  139. case let .configuring(headers):
  140. self = .configured
  141. return headers
  142. }
  143. }
  144. }
  145. }
  146. extension HTTP2ToRawGRPCStateMachine {
  147. enum PipelineConfiguredAction {
  148. /// Forward the given headers.
  149. case forwardHeaders(HPACKHeaders)
  150. /// Forward the given headers and try reading the next message.
  151. case forwardHeadersAndRead(HPACKHeaders)
  152. }
  153. enum ReceiveHeadersAction {
  154. /// Configure the RPC to use the given server handler.
  155. case configure(GRPCServerHandlerProtocol)
  156. /// Reject the RPC by writing out the given headers and setting end-stream.
  157. case rejectRPC(HPACKHeaders)
  158. }
  159. enum ReadNextMessageAction {
  160. /// Do nothing.
  161. case none
  162. /// Forward the buffer.
  163. case forwardMessage(ByteBuffer)
  164. /// Forward the buffer and try reading the next message.
  165. case forwardMessageThenReadNextMessage(ByteBuffer)
  166. /// Forward the 'end' of stream request part.
  167. case forwardEnd
  168. /// Throw an error down the pipeline.
  169. case errorCaught(Error)
  170. }
  171. struct StateAndReceiveHeadersAction {
  172. /// The next state.
  173. var state: State
  174. /// The action to take.
  175. var action: ReceiveHeadersAction
  176. }
  177. struct StateAndReceiveDataAction {
  178. /// The next state.
  179. var state: State
  180. /// The action to take
  181. var action: ReceiveDataAction
  182. }
  183. enum ReceiveDataAction: Hashable {
  184. /// Try to read the next message from the state machine.
  185. case tryReading
  186. /// Invoke 'finish' on the RPC handler.
  187. case finishHandler
  188. /// Do nothing.
  189. case nothing
  190. }
  191. enum SendEndAction {
  192. /// Send trailers to the client.
  193. case sendTrailers(HPACKHeaders)
  194. /// Send trailers to the client and invoke 'finish' on the RPC handler.
  195. case sendTrailersAndFinish(HPACKHeaders)
  196. /// Fail any promise associated with this send.
  197. case failure(Error)
  198. }
  199. }
  200. // MARK: Receive Headers
  201. // This is the only state in which we can receive headers.
  202. extension HTTP2ToRawGRPCStateMachine.State {
  203. private func _receive(
  204. headers: HPACKHeaders,
  205. eventLoop: EventLoop,
  206. errorDelegate: ServerErrorDelegate?,
  207. remoteAddress: SocketAddress?,
  208. logger: Logger,
  209. allocator: ByteBufferAllocator,
  210. responseWriter: GRPCServerResponseWriter,
  211. closeFuture: EventLoopFuture<Void>,
  212. services: [Substring: CallHandlerProvider],
  213. encoding: ServerMessageEncoding,
  214. normalizeHeaders: Bool
  215. ) -> HTTP2ToRawGRPCStateMachine.StateAndReceiveHeadersAction {
  216. // Extract and validate the content type. If it's nil we need to close.
  217. guard let contentType = self.extractContentType(from: headers) else {
  218. return self.unsupportedContentType()
  219. }
  220. // Now extract the request message encoding and setup an appropriate message reader.
  221. // We may send back a list of acceptable request message encodings as well.
  222. let reader: LengthPrefixedMessageReader
  223. let acceptableRequestEncoding: String?
  224. switch self.extractRequestEncoding(from: headers, encoding: encoding) {
  225. case let .valid(messageReader, acceptEncodingHeader):
  226. reader = messageReader
  227. acceptableRequestEncoding = acceptEncodingHeader
  228. case let .invalid(status, acceptableRequestEncoding):
  229. return self.invalidRequestEncoding(
  230. status: status,
  231. acceptableRequestEncoding: acceptableRequestEncoding,
  232. contentType: contentType
  233. )
  234. }
  235. // Figure out which encoding we should use for responses.
  236. let (writer, responseEncoding) = self.extractResponseEncoding(
  237. from: headers,
  238. encoding: encoding,
  239. allocator: allocator
  240. )
  241. // Parse the path, and create a call handler.
  242. guard let path = headers.first(name: ":path") else {
  243. return self.methodNotImplemented("", contentType: contentType)
  244. }
  245. guard let callPath = CallPath(requestURI: path),
  246. let service = services[Substring(callPath.service)]
  247. else {
  248. return self.methodNotImplemented(path, contentType: contentType)
  249. }
  250. // Create a call handler context, i.e. a bunch of 'stuff' we need to create the handler with,
  251. // some of which is exposed to service providers.
  252. let context = CallHandlerContext(
  253. errorDelegate: errorDelegate,
  254. logger: logger,
  255. encoding: encoding,
  256. eventLoop: eventLoop,
  257. path: path,
  258. remoteAddress: remoteAddress,
  259. responseWriter: responseWriter,
  260. allocator: allocator,
  261. closeFuture: closeFuture
  262. )
  263. // We have a matching service, hopefully we have a provider for the method too.
  264. let method = Substring(callPath.method)
  265. if let handler = service.handle(method: method, context: context) {
  266. let nextState = HTTP2ToRawGRPCStateMachine.RequestOpenResponseIdleState(
  267. reader: reader,
  268. writer: writer,
  269. contentType: contentType,
  270. acceptEncoding: acceptableRequestEncoding,
  271. responseEncoding: responseEncoding,
  272. normalizeHeaders: normalizeHeaders,
  273. configurationState: .configuring(headers)
  274. )
  275. return .init(
  276. state: .requestOpenResponseIdle(nextState),
  277. action: .configure(handler)
  278. )
  279. } else {
  280. return self.methodNotImplemented(path, contentType: contentType)
  281. }
  282. }
  283. /// The 'content-type' is not supported; close with status code 415.
  284. private func unsupportedContentType() -> HTTP2ToRawGRPCStateMachine.StateAndReceiveHeadersAction {
  285. // From: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
  286. //
  287. // If 'content-type' does not begin with "application/grpc", gRPC servers SHOULD respond
  288. // with HTTP status of 415 (Unsupported Media Type). This will prevent other HTTP/2
  289. // clients from interpreting a gRPC error response, which uses status 200 (OK), as
  290. // successful.
  291. let trailers = HPACKHeaders([(":status", "415")])
  292. return .init(
  293. state: .requestClosedResponseClosed,
  294. action: .rejectRPC(trailers)
  295. )
  296. }
  297. /// The RPC method is not implemented. Close with an appropriate status.
  298. private func methodNotImplemented(
  299. _ path: String,
  300. contentType: ContentType
  301. ) -> HTTP2ToRawGRPCStateMachine.StateAndReceiveHeadersAction {
  302. let trailers = HTTP2ToRawGRPCStateMachine.makeResponseTrailersOnly(
  303. for: GRPCStatus(code: .unimplemented, message: "'\(path)' is not implemented"),
  304. contentType: contentType,
  305. acceptableRequestEncoding: nil,
  306. userProvidedHeaders: nil,
  307. normalizeUserProvidedHeaders: false
  308. )
  309. return .init(
  310. state: .requestClosedResponseClosed,
  311. action: .rejectRPC(trailers)
  312. )
  313. }
  314. /// The request encoding specified by the client is not supported. Close with an appropriate
  315. /// status.
  316. private func invalidRequestEncoding(
  317. status: GRPCStatus,
  318. acceptableRequestEncoding: String?,
  319. contentType: ContentType
  320. ) -> HTTP2ToRawGRPCStateMachine.StateAndReceiveHeadersAction {
  321. let trailers = HTTP2ToRawGRPCStateMachine.makeResponseTrailersOnly(
  322. for: status,
  323. contentType: contentType,
  324. acceptableRequestEncoding: acceptableRequestEncoding,
  325. userProvidedHeaders: nil,
  326. normalizeUserProvidedHeaders: false
  327. )
  328. return .init(
  329. state: .requestClosedResponseClosed,
  330. action: .rejectRPC(trailers)
  331. )
  332. }
  333. /// Makes a 'GRPCStatus' and response trailers suitable for returning to the client when the
  334. /// request message encoding is not supported.
  335. ///
  336. /// - Parameters:
  337. /// - encoding: The unsupported request message encoding sent by the client.
  338. /// - acceptable: The list if acceptable request message encoding the client may use.
  339. /// - Returns: The status and trailers to return to the client.
  340. private func makeStatusAndTrailersForUnsupportedEncoding(
  341. _ encoding: String,
  342. advertisedEncoding: [String]
  343. ) -> (GRPCStatus, acceptEncoding: String?) {
  344. let status: GRPCStatus
  345. let acceptEncoding: String?
  346. if advertisedEncoding.isEmpty {
  347. // No compression is supported; there's nothing to tell the client about.
  348. status = GRPCStatus(code: .unimplemented, message: "compression is not supported")
  349. acceptEncoding = nil
  350. } else {
  351. // Return a list of supported encodings which we advertise. (The list we advertise may be a
  352. // subset of the encodings we support.)
  353. acceptEncoding = advertisedEncoding.joined(separator: ",")
  354. status = GRPCStatus(
  355. code: .unimplemented,
  356. message: "\(encoding) compression is not supported, supported algorithms are "
  357. + "listed in '\(GRPCHeaderName.acceptEncoding)'"
  358. )
  359. }
  360. return (status, acceptEncoding)
  361. }
  362. /// Extract and validate the 'content-type' sent by the client.
  363. /// - Parameter headers: The headers to extract the 'content-type' from
  364. private func extractContentType(from headers: HPACKHeaders) -> ContentType? {
  365. return headers.first(name: GRPCHeaderName.contentType).flatMap(ContentType.init)
  366. }
  367. /// The result of validating the request encoding header.
  368. private enum RequestEncodingValidation {
  369. /// The encoding was valid.
  370. case valid(messageReader: LengthPrefixedMessageReader, acceptEncoding: String?)
  371. /// The encoding was invalid, the RPC should be terminated with this status.
  372. case invalid(status: GRPCStatus, acceptEncoding: String?)
  373. }
  374. /// Extract and validate the request message encoding header.
  375. /// - Parameters:
  376. /// - headers: The headers to extract the message encoding header from.
  377. /// - Returns: `RequestEncodingValidation`, either a message reader suitable for decoding requests
  378. /// and an accept encoding response header if the request encoding was valid, or a pair of
  379. /// `GRPCStatus` and trailers to close the RPC with.
  380. private func extractRequestEncoding(
  381. from headers: HPACKHeaders,
  382. encoding: ServerMessageEncoding
  383. ) -> RequestEncodingValidation {
  384. let encodingValues = headers.values(forHeader: GRPCHeaderName.encoding, canonicalForm: true)
  385. var encodingIterator = encodingValues.makeIterator()
  386. let encodingHeader = encodingIterator.next()
  387. // Fail if there's more than one encoding header.
  388. if let first = encodingHeader, let second = encodingIterator.next() {
  389. var encodings: [Substring] = []
  390. encodings.reserveCapacity(8)
  391. encodings.append(first)
  392. encodings.append(second)
  393. while let next = encodingIterator.next() {
  394. encodings.append(next)
  395. }
  396. let status = GRPCStatus(
  397. code: .invalidArgument,
  398. message:
  399. "'\(GRPCHeaderName.encoding)' must contain no more than one value but was '\(encodings.joined(separator: ", "))'"
  400. )
  401. return .invalid(status: status, acceptEncoding: nil)
  402. }
  403. let result: RequestEncodingValidation
  404. let validator = MessageEncodingHeaderValidator(encoding: encoding)
  405. switch validator.validate(requestEncoding: encodingHeader.map { String($0) }) {
  406. case let .supported(algorithm, decompressionLimit, acceptEncoding):
  407. // Request message encoding is valid and supported.
  408. result = .valid(
  409. messageReader: LengthPrefixedMessageReader(
  410. compression: algorithm,
  411. decompressionLimit: decompressionLimit
  412. ),
  413. acceptEncoding: acceptEncoding.isEmpty ? nil : acceptEncoding.joined(separator: ",")
  414. )
  415. case .noCompression:
  416. // No message encoding header was present. This means no compression is being used.
  417. result = .valid(
  418. messageReader: LengthPrefixedMessageReader(),
  419. acceptEncoding: nil
  420. )
  421. case let .unsupported(encoding, acceptable):
  422. // Request encoding is not supported.
  423. let (status, acceptEncoding) = self.makeStatusAndTrailersForUnsupportedEncoding(
  424. encoding,
  425. advertisedEncoding: acceptable
  426. )
  427. result = .invalid(status: status, acceptEncoding: acceptEncoding)
  428. }
  429. return result
  430. }
  431. /// Extract a suitable message encoding for responses.
  432. /// - Parameters:
  433. /// - headers: The headers to extract the acceptable response message encoding from.
  434. /// - configuration: The encoding configuration for the server.
  435. /// - Returns: A message writer and the response encoding header to send back to the client.
  436. private func extractResponseEncoding(
  437. from headers: HPACKHeaders,
  438. encoding: ServerMessageEncoding,
  439. allocator: ByteBufferAllocator
  440. ) -> (CoalescingLengthPrefixedMessageWriter, String?) {
  441. let writer: CoalescingLengthPrefixedMessageWriter
  442. let responseEncoding: String?
  443. switch encoding {
  444. case let .enabled(configuration):
  445. // Extract the encodings acceptable to the client for response messages.
  446. let acceptableResponseEncoding = headers[canonicalForm: GRPCHeaderName.acceptEncoding]
  447. // Select the first algorithm that we support and have enabled. If we don't find one then we
  448. // won't compress response messages.
  449. let algorithm = acceptableResponseEncoding.lazy.compactMap { value in
  450. CompressionAlgorithm(rawValue: value)
  451. }.first {
  452. configuration.enabledAlgorithms.contains($0)
  453. }
  454. writer = .init(compression: algorithm, allocator: allocator)
  455. responseEncoding = algorithm?.name
  456. case .disabled:
  457. // The server doesn't have compression enabled.
  458. writer = .init(compression: .none, allocator: allocator)
  459. responseEncoding = nil
  460. }
  461. return (writer, responseEncoding)
  462. }
  463. }
  464. // MARK: - Receive Data
  465. extension HTTP2ToRawGRPCStateMachine.RequestOpenResponseIdleState {
  466. mutating func receive(
  467. buffer: inout ByteBuffer,
  468. endStream: Bool
  469. ) -> HTTP2ToRawGRPCStateMachine.StateAndReceiveDataAction {
  470. // Append the bytes to the reader.
  471. self.reader.append(buffer: &buffer)
  472. let state: HTTP2ToRawGRPCStateMachine.State
  473. let action: HTTP2ToRawGRPCStateMachine.ReceiveDataAction
  474. switch (self.configurationState.isConfigured, endStream) {
  475. case (true, true):
  476. /// Configured and end stream: read from the buffer, end will be sent as a result of draining
  477. /// the reader in the next state.
  478. state = .requestClosedResponseIdle(.init(from: self))
  479. action = .tryReading
  480. case (true, false):
  481. /// Configured but not end stream, just read from the buffer.
  482. state = .requestOpenResponseIdle(self)
  483. action = .tryReading
  484. case (false, true):
  485. // Not configured yet, but end of stream. Request stream is now closed but there's no point
  486. // reading yet.
  487. state = .requestClosedResponseIdle(.init(from: self))
  488. action = .nothing
  489. case (false, false):
  490. // Not configured yet, not end stream. No point reading a message yet since we don't have
  491. // anywhere to deliver it.
  492. state = .requestOpenResponseIdle(self)
  493. action = .nothing
  494. }
  495. return .init(state: state, action: action)
  496. }
  497. }
  498. extension HTTP2ToRawGRPCStateMachine.RequestOpenResponseOpenState {
  499. mutating func receive(
  500. buffer: inout ByteBuffer,
  501. endStream: Bool
  502. ) -> HTTP2ToRawGRPCStateMachine.StateAndReceiveDataAction {
  503. self.reader.append(buffer: &buffer)
  504. let state: HTTP2ToRawGRPCStateMachine.State
  505. if endStream {
  506. // End stream, so move to the closed state. Any end of request stream events events will
  507. // happen as a result of reading from the closed state.
  508. state = .requestClosedResponseOpen(.init(from: self))
  509. } else {
  510. state = .requestOpenResponseOpen(self)
  511. }
  512. return .init(state: state, action: .tryReading)
  513. }
  514. }
  515. // MARK: - Send Headers
  516. extension HTTP2ToRawGRPCStateMachine.RequestOpenResponseIdleState {
  517. func send(headers userProvidedHeaders: HPACKHeaders) -> HPACKHeaders {
  518. return HTTP2ToRawGRPCStateMachine.makeResponseHeaders(
  519. contentType: self.contentType,
  520. responseEncoding: self.responseEncoding,
  521. acceptableRequestEncoding: self.acceptEncoding,
  522. userProvidedHeaders: userProvidedHeaders,
  523. normalizeUserProvidedHeaders: self.normalizeHeaders
  524. )
  525. }
  526. }
  527. extension HTTP2ToRawGRPCStateMachine.RequestClosedResponseIdleState {
  528. func send(headers userProvidedHeaders: HPACKHeaders) -> HPACKHeaders {
  529. return HTTP2ToRawGRPCStateMachine.makeResponseHeaders(
  530. contentType: self.contentType,
  531. responseEncoding: self.responseEncoding,
  532. acceptableRequestEncoding: self.acceptEncoding,
  533. userProvidedHeaders: userProvidedHeaders,
  534. normalizeUserProvidedHeaders: self.normalizeHeaders
  535. )
  536. }
  537. }
  538. // MARK: - Send Data
  539. extension HTTP2ToRawGRPCStateMachine.RequestOpenResponseOpenState {
  540. mutating func send(
  541. buffer: ByteBuffer,
  542. compress: Bool,
  543. promise: EventLoopPromise<Void>?
  544. ) {
  545. self.writer.append(buffer: buffer, compress: compress, promise: promise)
  546. }
  547. }
  548. extension HTTP2ToRawGRPCStateMachine.RequestClosedResponseOpenState {
  549. mutating func send(
  550. buffer: ByteBuffer,
  551. compress: Bool,
  552. promise: EventLoopPromise<Void>?
  553. ) {
  554. self.writer.append(buffer: buffer, compress: compress, promise: promise)
  555. }
  556. }
  557. // MARK: - Send End
  558. extension HTTP2ToRawGRPCStateMachine.RequestOpenResponseIdleState {
  559. func send(
  560. status: GRPCStatus,
  561. trailers userProvidedTrailers: HPACKHeaders
  562. ) -> HPACKHeaders {
  563. return HTTP2ToRawGRPCStateMachine.makeResponseTrailersOnly(
  564. for: status,
  565. contentType: self.contentType,
  566. acceptableRequestEncoding: self.acceptEncoding,
  567. userProvidedHeaders: userProvidedTrailers,
  568. normalizeUserProvidedHeaders: self.normalizeHeaders
  569. )
  570. }
  571. }
  572. extension HTTP2ToRawGRPCStateMachine.RequestClosedResponseIdleState {
  573. func send(
  574. status: GRPCStatus,
  575. trailers userProvidedTrailers: HPACKHeaders
  576. ) -> HPACKHeaders {
  577. return HTTP2ToRawGRPCStateMachine.makeResponseTrailersOnly(
  578. for: status,
  579. contentType: self.contentType,
  580. acceptableRequestEncoding: self.acceptEncoding,
  581. userProvidedHeaders: userProvidedTrailers,
  582. normalizeUserProvidedHeaders: self.normalizeHeaders
  583. )
  584. }
  585. }
  586. extension HTTP2ToRawGRPCStateMachine.RequestClosedResponseOpenState {
  587. func send(
  588. status: GRPCStatus,
  589. trailers userProvidedTrailers: HPACKHeaders
  590. ) -> HPACKHeaders {
  591. return HTTP2ToRawGRPCStateMachine.makeResponseTrailers(
  592. for: status,
  593. userProvidedHeaders: userProvidedTrailers,
  594. normalizeUserProvidedHeaders: true
  595. )
  596. }
  597. }
  598. extension HTTP2ToRawGRPCStateMachine.RequestOpenResponseOpenState {
  599. func send(
  600. status: GRPCStatus,
  601. trailers userProvidedTrailers: HPACKHeaders
  602. ) -> HPACKHeaders {
  603. return HTTP2ToRawGRPCStateMachine.makeResponseTrailers(
  604. for: status,
  605. userProvidedHeaders: userProvidedTrailers,
  606. normalizeUserProvidedHeaders: true
  607. )
  608. }
  609. }
  610. // MARK: - Pipeline Configured
  611. extension HTTP2ToRawGRPCStateMachine.RequestOpenResponseIdleState {
  612. mutating func pipelineConfigured() -> HTTP2ToRawGRPCStateMachine.PipelineConfiguredAction {
  613. let headers = self.configurationState.configured()
  614. let action: HTTP2ToRawGRPCStateMachine.PipelineConfiguredAction
  615. // If there are unprocessed bytes then we need to read messages as well.
  616. let hasUnprocessedBytes = self.reader.unprocessedBytes != 0
  617. if hasUnprocessedBytes {
  618. // If there are unprocessed bytes, we need to try to read after sending the metadata.
  619. action = .forwardHeadersAndRead(headers)
  620. } else {
  621. // No unprocessed bytes; the reader is empty. Just send the metadata.
  622. action = .forwardHeaders(headers)
  623. }
  624. return action
  625. }
  626. }
  627. extension HTTP2ToRawGRPCStateMachine.RequestClosedResponseIdleState {
  628. mutating func pipelineConfigured() -> HTTP2ToRawGRPCStateMachine.PipelineConfiguredAction {
  629. let headers = self.configurationState.configured()
  630. // Since we're already closed, we need to forward the headers and start reading.
  631. return .forwardHeadersAndRead(headers)
  632. }
  633. }
  634. // MARK: - Read Next Request
  635. extension HTTP2ToRawGRPCStateMachine {
  636. static func read(
  637. from reader: inout LengthPrefixedMessageReader,
  638. requestStreamClosed: Bool,
  639. maxLength: Int
  640. ) -> HTTP2ToRawGRPCStateMachine.ReadNextMessageAction {
  641. do {
  642. if let buffer = try reader.nextMessage(maxLength: maxLength) {
  643. if reader.unprocessedBytes > 0 || requestStreamClosed {
  644. // Either there are unprocessed bytes or the request stream is now closed: deliver the
  645. // message and then try to read. The subsequent read may be another message or it may
  646. // be end stream.
  647. return .forwardMessageThenReadNextMessage(buffer)
  648. } else {
  649. // Nothing left to process and the stream isn't closed yet, just forward the message.
  650. return .forwardMessage(buffer)
  651. }
  652. } else if requestStreamClosed {
  653. return .forwardEnd
  654. } else {
  655. return .none
  656. }
  657. } catch {
  658. return .errorCaught(error)
  659. }
  660. }
  661. }
  662. extension HTTP2ToRawGRPCStateMachine.RequestOpenResponseIdleState {
  663. mutating func readNextRequest(
  664. maxLength: Int
  665. ) -> HTTP2ToRawGRPCStateMachine.ReadNextMessageAction {
  666. return HTTP2ToRawGRPCStateMachine.read(
  667. from: &self.reader,
  668. requestStreamClosed: false,
  669. maxLength: maxLength
  670. )
  671. }
  672. }
  673. extension HTTP2ToRawGRPCStateMachine.RequestOpenResponseOpenState {
  674. mutating func readNextRequest(
  675. maxLength: Int
  676. ) -> HTTP2ToRawGRPCStateMachine.ReadNextMessageAction {
  677. return HTTP2ToRawGRPCStateMachine.read(
  678. from: &self.reader,
  679. requestStreamClosed: false,
  680. maxLength: maxLength
  681. )
  682. }
  683. }
  684. extension HTTP2ToRawGRPCStateMachine.RequestClosedResponseIdleState {
  685. mutating func readNextRequest(
  686. maxLength: Int
  687. ) -> HTTP2ToRawGRPCStateMachine.ReadNextMessageAction {
  688. return HTTP2ToRawGRPCStateMachine.read(
  689. from: &self.reader,
  690. requestStreamClosed: true,
  691. maxLength: maxLength
  692. )
  693. }
  694. }
  695. extension HTTP2ToRawGRPCStateMachine.RequestClosedResponseOpenState {
  696. mutating func readNextRequest(
  697. maxLength: Int
  698. ) -> HTTP2ToRawGRPCStateMachine.ReadNextMessageAction {
  699. return HTTP2ToRawGRPCStateMachine.read(
  700. from: &self.reader,
  701. requestStreamClosed: true,
  702. maxLength: maxLength
  703. )
  704. }
  705. }
  706. // MARK: - Top Level State Changes
  707. extension HTTP2ToRawGRPCStateMachine {
  708. /// Receive request headers.
  709. mutating func receive(
  710. headers: HPACKHeaders,
  711. eventLoop: EventLoop,
  712. errorDelegate: ServerErrorDelegate?,
  713. remoteAddress: SocketAddress?,
  714. logger: Logger,
  715. allocator: ByteBufferAllocator,
  716. responseWriter: GRPCServerResponseWriter,
  717. closeFuture: EventLoopFuture<Void>,
  718. services: [Substring: CallHandlerProvider],
  719. encoding: ServerMessageEncoding,
  720. normalizeHeaders: Bool
  721. ) -> ReceiveHeadersAction {
  722. return self.state.receive(
  723. headers: headers,
  724. eventLoop: eventLoop,
  725. errorDelegate: errorDelegate,
  726. remoteAddress: remoteAddress,
  727. logger: logger,
  728. allocator: allocator,
  729. responseWriter: responseWriter,
  730. closeFuture: closeFuture,
  731. services: services,
  732. encoding: encoding,
  733. normalizeHeaders: normalizeHeaders
  734. )
  735. }
  736. /// Receive request buffer.
  737. /// - Parameters:
  738. /// - buffer: The received buffer.
  739. /// - endStream: Whether end stream was set.
  740. /// - Returns: Returns whether the caller should try to read a message from the buffer.
  741. mutating func receive(buffer: inout ByteBuffer, endStream: Bool) -> ReceiveDataAction {
  742. self.state.receive(buffer: &buffer, endStream: endStream)
  743. }
  744. /// Send response headers.
  745. mutating func send(headers: HPACKHeaders) -> Result<HPACKHeaders, Error> {
  746. self.state.send(headers: headers)
  747. }
  748. /// Send a response buffer.
  749. mutating func send(
  750. buffer: ByteBuffer,
  751. compress: Bool,
  752. promise: EventLoopPromise<Void>?
  753. ) -> Result<Void, Error> {
  754. self.state.send(buffer: buffer, compress: compress, promise: promise)
  755. }
  756. mutating func nextResponse() -> (Result<ByteBuffer, Error>, EventLoopPromise<Void>?)? {
  757. self.state.nextResponse()
  758. }
  759. /// Send status and trailers.
  760. mutating func send(
  761. status: GRPCStatus,
  762. trailers: HPACKHeaders
  763. ) -> HTTP2ToRawGRPCStateMachine.SendEndAction {
  764. self.state.send(status: status, trailers: trailers)
  765. }
  766. /// The pipeline has been configured with a service provider.
  767. mutating func pipelineConfigured() -> PipelineConfiguredAction {
  768. self.state.pipelineConfigured()
  769. }
  770. /// Try to read a request message.
  771. mutating func readNextRequest(maxLength: Int) -> ReadNextMessageAction {
  772. self.state.readNextRequest(maxLength: maxLength)
  773. }
  774. }
  775. extension HTTP2ToRawGRPCStateMachine.State {
  776. mutating func pipelineConfigured() -> HTTP2ToRawGRPCStateMachine.PipelineConfiguredAction {
  777. switch self {
  778. case .requestIdleResponseIdle:
  779. preconditionFailure("Invalid state: pipeline configured before receiving request headers")
  780. case var .requestOpenResponseIdle(state):
  781. let action = state.pipelineConfigured()
  782. self = .requestOpenResponseIdle(state)
  783. return action
  784. case var .requestClosedResponseIdle(state):
  785. let action = state.pipelineConfigured()
  786. self = .requestClosedResponseIdle(state)
  787. return action
  788. case .requestOpenResponseOpen,
  789. .requestOpenResponseClosed,
  790. .requestClosedResponseOpen,
  791. .requestClosedResponseClosed:
  792. preconditionFailure("Invalid state: response stream opened before pipeline was configured")
  793. }
  794. }
  795. mutating func receive(
  796. headers: HPACKHeaders,
  797. eventLoop: EventLoop,
  798. errorDelegate: ServerErrorDelegate?,
  799. remoteAddress: SocketAddress?,
  800. logger: Logger,
  801. allocator: ByteBufferAllocator,
  802. responseWriter: GRPCServerResponseWriter,
  803. closeFuture: EventLoopFuture<Void>,
  804. services: [Substring: CallHandlerProvider],
  805. encoding: ServerMessageEncoding,
  806. normalizeHeaders: Bool
  807. ) -> HTTP2ToRawGRPCStateMachine.ReceiveHeadersAction {
  808. switch self {
  809. // These are the only states in which we can receive headers. Everything else is invalid.
  810. case .requestIdleResponseIdle,
  811. .requestClosedResponseClosed:
  812. let stateAndAction = self._receive(
  813. headers: headers,
  814. eventLoop: eventLoop,
  815. errorDelegate: errorDelegate,
  816. remoteAddress: remoteAddress,
  817. logger: logger,
  818. allocator: allocator,
  819. responseWriter: responseWriter,
  820. closeFuture: closeFuture,
  821. services: services,
  822. encoding: encoding,
  823. normalizeHeaders: normalizeHeaders
  824. )
  825. self = stateAndAction.state
  826. return stateAndAction.action
  827. // We can't receive headers in any of these states.
  828. case .requestOpenResponseIdle,
  829. .requestOpenResponseOpen,
  830. .requestOpenResponseClosed,
  831. .requestClosedResponseIdle,
  832. .requestClosedResponseOpen:
  833. preconditionFailure("Invalid state: \(self)")
  834. }
  835. }
  836. /// Receive a buffer from the client.
  837. mutating func receive(
  838. buffer: inout ByteBuffer,
  839. endStream: Bool
  840. ) -> HTTP2ToRawGRPCStateMachine.ReceiveDataAction {
  841. switch self {
  842. case .requestIdleResponseIdle:
  843. /// This isn't allowed: we must receive the request headers first.
  844. preconditionFailure("Invalid state")
  845. case var .requestOpenResponseIdle(state):
  846. let stateAndAction = state.receive(buffer: &buffer, endStream: endStream)
  847. self = stateAndAction.state
  848. return stateAndAction.action
  849. case var .requestOpenResponseOpen(state):
  850. let stateAndAction = state.receive(buffer: &buffer, endStream: endStream)
  851. self = stateAndAction.state
  852. return stateAndAction.action
  853. case .requestClosedResponseIdle,
  854. .requestClosedResponseOpen:
  855. preconditionFailure("Invalid state: the request stream is already closed")
  856. case .requestOpenResponseClosed:
  857. if endStream {
  858. // Server has finish responding and this is the end of the request stream; we're done for
  859. // this RPC now, finish the handler.
  860. self = .requestClosedResponseClosed
  861. return .finishHandler
  862. } else {
  863. // Server has finished responding but this isn't the end of the request stream; ignore the
  864. // input, we need to wait for end stream before tearing down the handler.
  865. return .nothing
  866. }
  867. case .requestClosedResponseClosed:
  868. return .nothing
  869. }
  870. }
  871. mutating func readNextRequest(
  872. maxLength: Int
  873. ) -> HTTP2ToRawGRPCStateMachine.ReadNextMessageAction {
  874. switch self {
  875. case .requestIdleResponseIdle:
  876. preconditionFailure("Invalid state")
  877. case var .requestOpenResponseIdle(state):
  878. let action = state.readNextRequest(maxLength: maxLength)
  879. self = .requestOpenResponseIdle(state)
  880. return action
  881. case var .requestOpenResponseOpen(state):
  882. let action = state.readNextRequest(maxLength: maxLength)
  883. self = .requestOpenResponseOpen(state)
  884. return action
  885. case var .requestClosedResponseIdle(state):
  886. let action = state.readNextRequest(maxLength: maxLength)
  887. self = .requestClosedResponseIdle(state)
  888. return action
  889. case var .requestClosedResponseOpen(state):
  890. let action = state.readNextRequest(maxLength: maxLength)
  891. self = .requestClosedResponseOpen(state)
  892. return action
  893. case .requestOpenResponseClosed,
  894. .requestClosedResponseClosed:
  895. return .none
  896. }
  897. }
  898. mutating func send(headers: HPACKHeaders) -> Result<HPACKHeaders, Error> {
  899. switch self {
  900. case .requestIdleResponseIdle:
  901. preconditionFailure("Invalid state: the request stream isn't open")
  902. case let .requestOpenResponseIdle(state):
  903. let headers = state.send(headers: headers)
  904. self = .requestOpenResponseOpen(.init(from: state))
  905. return .success(headers)
  906. case let .requestClosedResponseIdle(state):
  907. let headers = state.send(headers: headers)
  908. self = .requestClosedResponseOpen(.init(from: state))
  909. return .success(headers)
  910. case .requestOpenResponseOpen,
  911. .requestOpenResponseClosed,
  912. .requestClosedResponseOpen,
  913. .requestClosedResponseClosed:
  914. return .failure(GRPCError.AlreadyComplete())
  915. }
  916. }
  917. mutating func send(
  918. buffer: ByteBuffer,
  919. compress: Bool,
  920. promise: EventLoopPromise<Void>?
  921. ) -> Result<Void, Error> {
  922. switch self {
  923. case .requestIdleResponseIdle:
  924. preconditionFailure("Invalid state: the request stream is still closed")
  925. case .requestOpenResponseIdle,
  926. .requestClosedResponseIdle:
  927. let error = GRPCError.InvalidState("Response headers must be sent before response message")
  928. return .failure(error)
  929. case var .requestOpenResponseOpen(state):
  930. self = .requestClosedResponseClosed
  931. state.send(buffer: buffer, compress: compress, promise: promise)
  932. self = .requestOpenResponseOpen(state)
  933. return .success(())
  934. case var .requestClosedResponseOpen(state):
  935. self = .requestClosedResponseClosed
  936. state.send(buffer: buffer, compress: compress, promise: promise)
  937. self = .requestClosedResponseOpen(state)
  938. return .success(())
  939. case .requestOpenResponseClosed,
  940. .requestClosedResponseClosed:
  941. return .failure(GRPCError.AlreadyComplete())
  942. }
  943. }
  944. mutating func nextResponse() -> (Result<ByteBuffer, Error>, EventLoopPromise<Void>?)? {
  945. switch self {
  946. case .requestIdleResponseIdle:
  947. preconditionFailure("Invalid state: the request stream is still closed")
  948. case .requestOpenResponseIdle,
  949. .requestClosedResponseIdle:
  950. return nil
  951. case var .requestOpenResponseOpen(state):
  952. self = .requestClosedResponseClosed
  953. let result = state.writer.next()
  954. self = .requestOpenResponseOpen(state)
  955. return result
  956. case var .requestClosedResponseOpen(state):
  957. self = .requestClosedResponseClosed
  958. let result = state.writer.next()
  959. self = .requestClosedResponseOpen(state)
  960. return result
  961. case .requestOpenResponseClosed,
  962. .requestClosedResponseClosed:
  963. return nil
  964. }
  965. }
  966. mutating func send(
  967. status: GRPCStatus,
  968. trailers: HPACKHeaders
  969. ) -> HTTP2ToRawGRPCStateMachine.SendEndAction {
  970. switch self {
  971. case .requestIdleResponseIdle:
  972. preconditionFailure("Invalid state: the request stream is still closed")
  973. case let .requestOpenResponseIdle(state):
  974. self = .requestOpenResponseClosed
  975. return .sendTrailers(state.send(status: status, trailers: trailers))
  976. case let .requestClosedResponseIdle(state):
  977. self = .requestClosedResponseClosed
  978. return .sendTrailersAndFinish(state.send(status: status, trailers: trailers))
  979. case let .requestOpenResponseOpen(state):
  980. self = .requestOpenResponseClosed
  981. return .sendTrailers(state.send(status: status, trailers: trailers))
  982. case let .requestClosedResponseOpen(state):
  983. self = .requestClosedResponseClosed
  984. return .sendTrailersAndFinish(state.send(status: status, trailers: trailers))
  985. case .requestOpenResponseClosed,
  986. .requestClosedResponseClosed:
  987. return .failure(GRPCError.AlreadyComplete())
  988. }
  989. }
  990. }
  991. // MARK: - Helpers
  992. extension HTTP2ToRawGRPCStateMachine {
  993. static func makeResponseHeaders(
  994. contentType: ContentType,
  995. responseEncoding: String?,
  996. acceptableRequestEncoding: String?,
  997. userProvidedHeaders: HPACKHeaders,
  998. normalizeUserProvidedHeaders: Bool
  999. ) -> HPACKHeaders {
  1000. // 4 because ':status' and 'content-type' are required. We may send back 'grpc-encoding' and
  1001. // 'grpc-accept-encoding' as well.
  1002. let capacity = 4 + userProvidedHeaders.count
  1003. var headers = HPACKHeaders()
  1004. headers.reserveCapacity(capacity)
  1005. headers.add(name: ":status", value: "200")
  1006. headers.add(name: GRPCHeaderName.contentType, value: contentType.canonicalValue)
  1007. if let responseEncoding = responseEncoding {
  1008. headers.add(name: GRPCHeaderName.encoding, value: responseEncoding)
  1009. }
  1010. if let acceptEncoding = acceptableRequestEncoding {
  1011. headers.add(name: GRPCHeaderName.acceptEncoding, value: acceptEncoding)
  1012. }
  1013. // Add user provided headers, normalizing if required.
  1014. headers.add(contentsOf: userProvidedHeaders, normalize: normalizeUserProvidedHeaders)
  1015. return headers
  1016. }
  1017. static func makeResponseTrailersOnly(
  1018. for status: GRPCStatus,
  1019. contentType: ContentType,
  1020. acceptableRequestEncoding: String?,
  1021. userProvidedHeaders: HPACKHeaders?,
  1022. normalizeUserProvidedHeaders: Bool
  1023. ) -> HPACKHeaders {
  1024. // 5 because ':status', 'content-type', 'grpc-status' are required. We may also send back
  1025. // 'grpc-message' and 'grpc-accept-encoding'.
  1026. let capacity = 5 + (userProvidedHeaders.map { $0.count } ?? 0)
  1027. var headers = HPACKHeaders()
  1028. headers.reserveCapacity(capacity)
  1029. // Add the required trailers.
  1030. headers.add(name: ":status", value: "200")
  1031. headers.add(name: GRPCHeaderName.contentType, value: contentType.canonicalValue)
  1032. headers.add(name: GRPCHeaderName.statusCode, value: String(describing: status.code.rawValue))
  1033. if let message = status.message.flatMap(GRPCStatusMessageMarshaller.marshall) {
  1034. headers.add(name: GRPCHeaderName.statusMessage, value: message)
  1035. }
  1036. // We may include this if the requested encoding was not valid.
  1037. if let acceptEncoding = acceptableRequestEncoding {
  1038. headers.add(name: GRPCHeaderName.acceptEncoding, value: acceptEncoding)
  1039. }
  1040. if let userProvided = userProvidedHeaders {
  1041. headers.add(contentsOf: userProvided, normalize: normalizeUserProvidedHeaders)
  1042. }
  1043. return headers
  1044. }
  1045. static func makeResponseTrailers(
  1046. for status: GRPCStatus,
  1047. userProvidedHeaders: HPACKHeaders,
  1048. normalizeUserProvidedHeaders: Bool
  1049. ) -> HPACKHeaders {
  1050. // Most RPCs should end with status code 'ok' (hopefully!), and if the user didn't provide any
  1051. // additional trailers, then we can use a pre-canned set of headers to avoid an extra
  1052. // allocation.
  1053. if status == .ok, userProvidedHeaders.isEmpty {
  1054. return Self.gRPCStatusOkTrailers
  1055. }
  1056. // 2 because 'grpc-status' is required, we may also send back 'grpc-message'.
  1057. let capacity = 2 + userProvidedHeaders.count
  1058. var trailers = HPACKHeaders()
  1059. trailers.reserveCapacity(capacity)
  1060. // status code.
  1061. trailers.add(name: GRPCHeaderName.statusCode, value: String(describing: status.code.rawValue))
  1062. // status message, if present.
  1063. if let message = status.message.flatMap(GRPCStatusMessageMarshaller.marshall) {
  1064. trailers.add(name: GRPCHeaderName.statusMessage, value: message)
  1065. }
  1066. // user provided trailers.
  1067. trailers.add(contentsOf: userProvidedHeaders, normalize: normalizeUserProvidedHeaders)
  1068. return trailers
  1069. }
  1070. private static let gRPCStatusOkTrailers: HPACKHeaders = [
  1071. GRPCHeaderName.statusCode: String(describing: GRPCStatus.Code.ok.rawValue)
  1072. ]
  1073. }
  1074. extension HPACKHeaders {
  1075. fileprivate mutating func add(contentsOf other: HPACKHeaders, normalize: Bool) {
  1076. if normalize {
  1077. self.add(
  1078. contentsOf: other.lazy.map { name, value, indexable in
  1079. (name: name.lowercased(), value: value, indexable: indexable)
  1080. }
  1081. )
  1082. } else {
  1083. self.add(contentsOf: other)
  1084. }
  1085. }
  1086. }