@@ -86,6 +86,7 @@ extension HeaderBlockValidator {
8686 for (name, value, _) in block {
8787 let fieldName = try HeaderFieldName ( name)
8888 try blockSection. validField ( fieldName)
89+ try fieldName. legalHeaderField ( value: value)
8990
9091 let thisPseudoHeaderFieldType = try seenPseudoHeaders. seenNewHeaderField ( fieldName)
9192
@@ -142,22 +143,28 @@ extension RequestBlockValidator: HeaderBlockValidator {
142143 // This is a bit awkward.
143144 //
144145 // For now we don't support extended-CONNECT, but when we do we'll need to update the logic here.
145- guard let pseudoHeaderType = pseudoHeaderType else {
146- // Nothing to do here.
147- return
148- }
146+ if let pseudoHeaderType = pseudoHeaderType {
147+ assert ( name. fieldType == . pseudoHeaderField)
148+
149+ switch pseudoHeaderType {
150+ case . method:
151+ // This is a method pseudo-header. Check if the value is CONNECT.
152+ self . isConnectRequest = value == " CONNECT "
153+ case . path:
154+ // This is a path pseudo-header. It must not be empty.
155+ if value. utf8. count == 0 {
156+ throw NIOHTTP2Errors . EmptyPathHeader ( )
157+ }
158+ default :
159+ break
160+ }
161+ } else {
162+ assert ( name. fieldType == . regularHeaderField)
149163
150- switch pseudoHeaderType {
151- case . method:
152- // This is a method pseudo-header. Check if the value is CONNECT.
153- self . isConnectRequest = value == " CONNECT "
154- case . path:
155- // This is a path pseudo-header. It must not be empty.
156- if value. utf8. count == 0 {
157- throw NIOHTTP2Errors . EmptyPathHeader ( )
164+ // We want to check that if the TE header field is present, it only contains "trailers".
165+ if name. baseName == " te " && value != " trailers " {
166+ throw NIOHTTP2Errors . ForbiddenHeaderField ( name: String ( name. baseName) , value: value)
158167 }
159- default :
160- break
161168 }
162169 }
163170
@@ -249,6 +256,27 @@ extension HeaderFieldName {
249256 throw NIOHTTP2Errors . InvalidHTTP2HeaderFieldName ( fieldName)
250257 }
251258 }
259+
260+ func legalHeaderField( value: String ) throws {
261+ // RFC 7540 § 8.1.2.2 forbids all connection-specific header fields. A connection-specific header field technically
262+ // is one that is listed in the Connection header, but could also be proxy-connection & transfer-encoding, even though
263+ // those are not usually listed in the Connection header. For defensiveness sake, we forbid those too.
264+ //
265+ // There is one more wrinkle, which is that the client is allowed to send TE: trailers, and forbidden from sending TE
266+ // with anything else. We police that separately, as TE is only defined on requests, so we can avoid checking for it
267+ // on responses and trailers.
268+ guard self . fieldType == . regularHeaderField else {
269+ // Pseudo-headers are never connection-specific.
270+ return
271+ }
272+
273+ switch self . baseName {
274+ case " connection " , " transfer-encoding " , " proxy-connection " :
275+ throw NIOHTTP2Errors . ForbiddenHeaderField ( name: String ( self . baseName) , value: value)
276+ default :
277+ return
278+ }
279+ }
252280}
253281
254282
0 commit comments