Skip to content

Commit

Permalink
Add some additional header tests (dart-lang#1006)
Browse files Browse the repository at this point in the history
* Add some additional header tests

- Tests for folder headers
- Tests for headers values containing spaces
- Tests for header names that are upper case
  • Loading branch information
brianquinlan committed Aug 15, 2023
1 parent 9f167a7 commit df1f625
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 4 deletions.
20 changes: 20 additions & 0 deletions pkgs/http/lib/src/base_response.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,26 @@ abstract class BaseResponse {

// TODO(nweiz): automatically parse cookies from headers

/// The HTTP headers returned by the server.
///
/// The header names are converted to lowercase and stored with their
/// associated header values.
///
/// If the server returns multiple headers with the same name then the header
/// values will be associated with a single key and seperated by commas and
/// possibly whitespace. For example:
/// ```dart
/// // HTTP/1.1 200 OK
/// // Fruit: Apple
/// // Fruit: Banana
/// // Fruit: Grape
/// final values = response.headers['fruit']!.split(RegExp(r'\s*,\s*'));
/// // values = ['Apple', 'Banana', 'Grape']
/// ```
///
/// If a header value contains whitespace then that whitespace may be replaced
/// by a single space. Leading and trailing whitespace in header values are
/// always removed.
// TODO(nweiz): make this a HttpHeaders object.
final Map<String, String> headers;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,47 @@ void testResponseHeaders(Client client) async {
expect(response.headers['foo'], 'bar');
});

test('UPPERCASE header name', () async {
// RFC 2616 14.44 states that header field names are case-insensitive.
// http.Client canonicalizes field names into lower case.
httpServerChannel.sink.add('FOO: bar\r\n');

final response = await client.get(Uri.http(host, ''));
expect(response.headers['foo'], 'bar');
});

test('UPPERCASE header value', () async {
httpServerChannel.sink.add('foo: BAR\r\n');

final response = await client.get(Uri.http(host, ''));
// RFC 2616 14.44 states that header field names are case-insensitive.
// http.Client canonicalizes field names into lower case.
expect(response.headers['foo'], 'BAR');
});

test('space surrounding header value', () async {
httpServerChannel.sink.add('foo: \t BAR \t \r\n');

final response = await client.get(Uri.http(host, ''));
// RFC 2616 14.44 states that header field names are case-insensitive.
// http.Client canonicalizes field names into lower case.
expect(response.headers['foo'], 'BAR');
});

test('space in header value', () async {
httpServerChannel.sink.add('foo: BAR BAZ\r\n');

final response = await client.get(Uri.http(host, ''));
expect(response.headers['foo'], 'BAR BAZ');
});

test('multiple spaces in header value', () async {
// RFC 2616 4.2 allows LWS between header values to be replace with a
// single space.
// See https://datatracker.ietf.org/doc/html/rfc2616#section-4.2
httpServerChannel.sink.add('foo: BAR \t BAZ\r\n');

final response = await client.get(Uri.http(host, ''));
expect(
response.headers['foo'], matches(RegExp('BAR {0,2}[ \t] {0,3}BAZ')));
});

test('multiple headers', () async {
httpServerChannel.sink
.add('field1: value1\r\n' 'field2: value2\r\n' 'field3: value3\r\n');
Expand Down Expand Up @@ -130,5 +153,30 @@ void testResponseHeaders(Client client) async {
client.get(Uri.http(host, '')), throwsA(isA<ClientException>()));
});
});

group('folded headers', () {
// RFC2616 says that HTTP Headers can be split across multiple lines.
// See https://datatracker.ietf.org/doc/html/rfc2616#section-2.2
test('leading space', () async {
httpServerChannel.sink.add('foo: BAR\r\n BAZ\r\n');

final response = await client.get(Uri.http(host, ''));
expect(response.headers['foo'], 'BAR BAZ');
},
skip: 'Enable after https://github.com/dart-lang/sdk/issues/53185 '
'is fixed');

test('extra whitespace', () async {
httpServerChannel.sink.add('foo: BAR \t \r\n \t BAZ \t \r\n');

final response = await client.get(Uri.http(host, ''));
// RFC 2616 4.2 allows LWS between header values to be replace with a
// single space.
expect(
response.headers['foo'],
allOf(matches(RegExp(r'BAR {0,3}[ \t]? {0,7}[ \t]? {0,3}BAZ')),
contains(' ')));
});
});
});
}

0 comments on commit df1f625

Please sign in to comment.