HTTP2ToRawGRPCStateMachine.swift 41 KB

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