Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion pkgs/http/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## 1.6.1-wip

* Add `BrowserCredentialsMode` and `BrowserClient.credentialsMode` to support
the `omit` browser fetch credentials mode. Deprecate `withCredentials`.
* Clarified the behavior of response headers in API documentation comments.
* Make it more clear that `close` must be called for correctness.
* Replace references to `dart:web` with `package:web` dartdoc.
Expand Down Expand Up @@ -46,7 +48,8 @@
## 1.2.0

* Add `MockClient.pngResponse`, which makes it easier to fake image responses.
* Added the ability to fetch the URL of the response through `BaseResponseWithUrl`.
* Added the ability to fetch the URL of the response through
`BaseResponseWithUrl`.
* Add the ability to get headers as a `Map<String, List<String>` to
`BaseResponse`.

Expand Down
74 changes: 72 additions & 2 deletions pkgs/http/lib/src/browser_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,38 @@ external JSPromise<Response> _fetch(
RequestInit init,
]);

/// The browser `fetch` credentials mode represented by [RequestCredentials].
///
/// Controls whether the browser sends credentials such as cookies, TLS client
/// certificates, or authorization headers with a request.
///
/// See also:
/// - https://fetch.spec.whatwg.org/#requestcredentials
enum RequestCredentials {
/// Never send credentials with the request and never include credentials in
/// the response.
///
/// This corresponds to the browser `fetch` credentials mode `omit`.
omit('omit'),

/// Send credentials for same-origin requests only and only include
/// credentials in same-origin replies.
///
/// This corresponds to the browser `fetch` credentials mode `same-origin`.
sameOrigin('same-origin'),

/// Always send credentials, even for cross-origin requests, and include them
/// in all responses.
///
/// This corresponds to the browser `fetch` credentials mode `include`.
include('include');

const RequestCredentials(this._value);

/// The value passed to the browser `fetch` `RequestInit.credentials` field.
final String _value;
}

/// A `package:web`-based HTTP client that runs in the browser and is backed by
/// [`window.fetch`](https://fetch.spec.whatwg.org/).
///
Expand All @@ -52,11 +84,49 @@ external JSPromise<Response> _fetch(
/// Responses are streamed but requests are not. A request will only be sent
/// once all the data is available.
class BrowserClient extends BaseClient {
/// Create a [BrowserClient].
///
/// By default, credentials are sent for same-origin requests only.
BrowserClient(
{RequestCredentials requestCredentials = RequestCredentials.sameOrigin})
: _requestCredentials = requestCredentials;

/// The internal browser `fetch` credentials mode used for requests.
RequestCredentials _requestCredentials;

/// The browser `fetch` credentials mode used for requests.
///
/// Defaults to [RequestCredentials.sameOrigin], which matches the
/// previous behavior when [withCredentials] was `false`.
RequestCredentials get requestCredentials => _requestCredentials;

/// Whether to send credentials such as cookies or authorization headers for
/// cross-site requests.
///
/// Defaults to `false`.
bool withCredentials = false;
///
/// This property is deprecated because it can only represent two of the three
/// browser `fetch` credentials modes (`same-origin` and `include`). Use
/// [_requestCredentials] instead to also support [RequestCredentials.omit].
///
/// Reading this property returns `true` only when [_requestCredentials] is
/// [RequestCredentials.include].
@Deprecated('Use requestCredentials instead.')
bool get withCredentials => _requestCredentials == RequestCredentials.include;

/// Whether to send credentials such as cookies or authorization headers for
/// cross-site requests.
///
/// Setting this to `true` sets [_requestCredentials] to
/// [RequestCredentials.include].
///
/// Setting this to `false` sets [_requestCredentials] to
/// [RequestCredentials.sameOrigin].
@Deprecated('Use the requestCredentials constructor parameter instead.')
set withCredentials(bool value) {
_requestCredentials =
value ? RequestCredentials.include : RequestCredentials.sameOrigin;
}

bool _isClosed = false;
final _openRequestAbortControllers = <AbortController>[];
Expand Down Expand Up @@ -85,7 +155,7 @@ class BrowserClient extends BaseClient {
RequestInit(
method: request.method,
body: bodyBytes.isNotEmpty ? bodyBytes.toJS : null,
credentials: withCredentials ? 'include' : 'same-origin',
credentials: _requestCredentials._value,
headers: {
if (request.contentLength case final contentLength?)
'content-length': contentLength,
Expand Down