Skip to content

Commit 6a8c3c5

Browse files
authored
Add responseHeaders extension on XMLHttpRequest (#298)
* Add `responseHeaders` extension on `XMLHttpRequest` Move this extension from `package:http` to here, it might also be used in `package:grpc`. * Add test * Reformat * Add changelog * Use LineSplitter * Use `update` * Use split instead of indexOf
1 parent fcd8123 commit 6a8c3c5

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

web/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
`getter`s and `setter`s, respectively.
1111
- Exposed constants with primitive values as non-`external` so they can be
1212
`switch`ed over.
13+
- Add an extension `responseHeaders` to `XMLHttpRequest`.
1314

1415
## 1.0.0
1516

web/lib/src/helpers/extensions.dart

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
/// * conversions: for example to wrap a `TouchList` as a `List<Touch>`
2222
library;
2323

24+
import 'dart:convert';
2425
import 'dart:js_interop';
2526
import 'dart:math' show Point;
2627

@@ -103,3 +104,33 @@ extension TouchListConvert on TouchList {
103104
@Deprecated('Use JSImmutableListWrapper<TouchList, Touch> directly instead.')
104105
List<Touch> toList() => JSImmutableListWrapper<TouchList, Touch>(this);
105106
}
107+
108+
/// Returns all response headers as a key-value map.
109+
///
110+
/// Multiple values for the same header key can be combined into one,
111+
/// separated by a comma and a space.
112+
///
113+
/// See: http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
114+
extension XMLHttpRequestGlue on XMLHttpRequest {
115+
Map<String, String> get responseHeaders {
116+
// from Closure's goog.net.Xhrio.getResponseHeaders.
117+
final headers = <String, String>{};
118+
final headersString = getAllResponseHeaders();
119+
final headersList =
120+
LineSplitter.split(headersString).where((header) => header.isNotEmpty);
121+
for (final header in headersList) {
122+
final split = header.split(': ');
123+
if (split.length <= 1) {
124+
continue;
125+
}
126+
final key = split[0].toLowerCase();
127+
final value = split.skip(1).join(': ');
128+
headers.update(
129+
key,
130+
(oldValue) => '$oldValue, $value',
131+
ifAbsent: () => value,
132+
);
133+
}
134+
return headers;
135+
}
136+
}

web/test/helpers_test.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,23 @@ void main() {
3636
// Ensure accessing any arbitrary item in the list does not throw.
3737
expect(() => dartList[0], returnsNormally);
3838
});
39+
40+
test('responseHeaders transforms headers into a map', () async {
41+
final request = XMLHttpRequest()
42+
..open('GET', 'www.google.com')
43+
..send();
44+
45+
await request.onLoad.first;
46+
47+
expect(
48+
request.responseHeaders,
49+
allOf(
50+
containsPair('content-length', '10'),
51+
containsPair('content-type', 'text/plain; charset=utf-8'),
52+
containsPair('x-content-type-options', 'nosniff'),
53+
containsPair('x-frame-options', 'SAMEORIGIN'),
54+
containsPair('x-xss-protection', '1; mode=block'),
55+
),
56+
);
57+
});
3958
}

0 commit comments

Comments
 (0)