http
http copied to clipboard
[http] ✨ Add `redirects` in `IOStreamedResponse`
The request provides the ability to extract the redirections from an IOStreamedResponse.
- [x] I’ve reviewed the contributor guide and applied the relevant portions to this PR.
Contribution guidelines:
- See our contributor guide for general expectations for PRs.
- Larger or significant changes should be discussed in an issue before creating a PR.
- Contributions to our repos should follow the Dart style guide and use
dart format. - Most changes should add an entry to the changelog and may need to rev the pubspec package version.
- Changes to packages require corresponding tests.
Note that many Dart repos have a weekly cadence for reviewing PRs - please allow for some latency before initial review feedback.
Why are you only adding this to
IOStreamedResponse?
Because RedirectInfo is available in dart:io. I can keep this implementation or add the same class in the package.
Please add redirects in IOStreamedResponse for workaround (https://github.com/dart-lang/http/pull/699) Then no breaking changes.
With this, we can cast and then get redirect(final) url in specific usecase. There's better than nothing.
When will you add Response.uri (https://github.com/dart-lang/http/pull/699)?
Http is one of most important feature in app. dart:io's http has no http2 no http3 dart:http has no Response.url. This is really annoying.
When will you add Response.uri (#699)
That is the next thing I'm considering.
@natebosch this is a less-breaking version of your change https://github.com/dart-lang/http/pull/699
My concern is that making this work only for IOClient will result in people writing more implementation-specific code.
Maybe it would make sense to do a major release with https://github.com/dart-lang/http/pull/699 and possibly also:
- progress notification: https://github.com/dart-lang/http/pull/579/files
- request cancellation/timeout: https://github.com/dart-lang/http/pull/521
Maybe it would make sense to do a major release with #699 and possibly also:
Yeah a long while ago I had anticipated bundling some breaking changes and doing a major version release, but it never bubbled up to a high enough priority that I took the time to plan out the full migration story.
This package requires incremental migration paths across major versions - we will need to be compatible with the same Flutter SDK version across both major versions, so that we can use the new version internally before publishing, and Flutter can wait for publish until it bumps a dependency.
- progress notification: https://github.com/dart-lang/http/pull/579/files
I still have concerns about the fidelity of this API. (Although I don't see my comments there - was there a similar PR before?) Have we verified that if we are communicating with a server that stops reading halfway through the request it is correctly reflected in the upload progress?
The web implementation looks like it can make the same promises as a supported JS API, so there shouldn't be a problem there. The VM implementation looks like it relies on there not being any caching anywhere between the user's Stream and the communicating socket, and that there is appropriate backpressure applied to the Stream. If there can be a large difference between the amount of events sent to .map and the amount of data actually added to the socket, this wouldn't be reliable.
My concern is that making this work only for
IOClientwill result in people writing more implementation-specific code.
+1. I would be OK with a temporary situation where the API is only available on the IO specific subclasses to minimize breakage while we roll it out, but I would much prefer consistency across the APIs as long as it's feasible to support on each platform. Can we support redirect on the web and with the cronet clients etc?
My concern is that making this work only for
IOClientwill result in people writing more implementation-specific code.+1. I would be OK with a temporary situation where the API is only available on the
IOspecific subclasses to minimize breakage while we roll it out, but I would much prefer consistency across the APIs as long as it's feasible to support on each platform. Can we supportredirecton the web and with the cronet clients etc?
We can support redirect everywhere except on the web (using XMLHTTPRequest). The formulation where we only provide the final URL (e.g. as with https://github.com/dart-lang/http/pull/699) is supportable everywhere.
How about this (your opinion would be useful here too @AlexV525):
- We modify this PR to capture just the final url rather than the complete redirect list. Maybe:
/// The final [Uri] returned by the server after any redirects.
///
/// [finalUri] will only be `null` in certain edge cases. For example, when fetching the "about:" URL in a browser, [finalUri]
/// may be `null`.
final Uri? finalUri;
- We plan on moving that definition to
BaseResponsein the next breaking release (with appropriate modifications toCronetClient,BrowserClientandCupertinoClientas well as conformance tests)
The redirects are still valuable for a response. I can add finalUri too. In dio, we also have a fork class for redirects and a field named realUri. Redirects is an empty list on the Web platform.
Meanwhile, can we push splitting basic http classes from io?
- https://pub.dev/documentation/dio/latest/dio/Response/realUri.html
- https://pub.dev/documentation/dio/latest/dio/Response/redirects.html
The redirects are still valuable for a response. I can add
finalUritoo. In dio, we also have a fork class for redirects and a field namedrealUri. Redirects is an empty list on the Web platform.
I think that adding an equivalent of realUri would be less controversial since it has a clear use case (https://github.com/dart-lang/http/issues/293) and can be implemented for all Client implementations.
Meanwhile, can we push splitting basic http classes from
io?
I don't know what you mean.
Please add redirects in IOStreamedResponse for workaround (#699) Then no breaking changes.
With this, we can cast and then get redirect(final) url in specific usecase. There's better than nothing.
When will you add Response.uri (#699)?
Http is one of most important feature in app. dart:io's http has no http2 no http3 dart:http has no Response.url. This is really annoying.
Fixing this in IOStreamedResponse won't fix your issue because IOClient only supports http1.
Meanwhile, can we push splitting basic http classes from
io?I don't know what you mean.
One of the reason I've only added this field to the IOStreamedResponse is https://github.com/dart-lang/http/pull/1076#issuecomment-1858677266.
Meanwhile, can we push splitting basic http classes from
io?I don't know what you mean.
One of the reason I've only added this field to the
IOStreamedResponseis #1076 (comment).
Ah, I understand. I think that the usual approach for package:http would be to define your own class. But now now maybe we can just support finalUri ;-)
Another approach that we could define a mixins like:
mixin FinalUrl on BaseResponse {
abstract Uri? finalUrl;
}
Users could consume it like:
void main() async {
final response = await client.get();
if (response is FinalUrl) {
doSomethingWithFinalUrl(response.finalUrl);
}
}
We could define a hidden class that implements that mixin. In the next breaking release, we could add finalUrl to BaseResponse and deprecate the mixin. Then remove it in package:http 3.0
Another approach that we could define a mixins
Interesting, the subclasses could publicly claim to support this interface which would allow the same code as adding them directly on those implementations, but also give a way to use it without a platform specific import.
I'd think we wouldn't want the if (response is FinalUrl) { patterns to spread very far, but having to keep the mixins around until version 3.0 might not be too bad.
We might want to flesh this idea out some more and see if there are any negative implications.
Please don't hesitate to make breaking changes. I'll try adding a new class for redirects and adding finalUri too.
Please don't hesitate to make breaking changes.
That would go against our general policy when developing packages ;-)
I'll try adding a new class for redirects and adding
finalUritoo.
How about just for finalUri?
I'll try adding a new class for redirects and adding
finalUritoo.How about just for
finalUri?
That would be fine too, but I don't see any strong reason to abandon this PR.
I'll try adding a new class for redirects and adding
finalUritoo.How about just for
finalUri?That would be fine too, but I don't see any strong reason to abandon this PR.
You don't need to abandon this PR but I would start with just finalUri because:
- we have a use case for it
- it is less complex to implement
- it is implementable in all of our
Clients
Marking as ready for review again.
ping @brianquinlan
ping @brianquinlan
-
Are you sure that this is needed? Now that the final URL is available in
BaseResponse, do we need a list of redirects? -
If we do need the list of redirects, could we follow the pattern of https://github.com/dart-lang/http/pull/1109 so that other clients can offer that data too?
Of the clients that I know about:
IOClient: can provide (location, status, method)package:cupertino_http: can provide (location, status, method)package:cronet_http: can provide (location, status, method)package:fetch_client: I think that it can provide (location, status, method) but it might be expensive - @ZekfadBrowserClient: redirects are opaque
- after this change lands, we should update
package:http_client_conformance_testsredirect_tests.dart to ensure that allClients are implementing this consistently.
Browser fetch can at least provide info if there was (or not) redirect and final URL at no additional cost:
https://github.com/Zekfad/fetch_api/blob/master/lib/src/response/response.dart#L53
https://github.com/Zekfad/fetch_api/blob/master/lib/src/response/response.dart#L69
But manual redirect handling is expensive, as you point out it requires additional HEAD (or GET) request to retrieve final URL and forge a fake redirect response accordingly.
XHR has responseURL and checked if normalized initial URI != responseURL would partially polyfill fetch behavior, though I haven't checked it personally.
- Are you sure that this is needed? Now that the final URL is available in
BaseResponse, do we need a list of redirects?
I believe we should definitely provide such info to users.
- If we do need the list of redirects, could we follow the pattern of Add
BaseResponseWithUrl.url#1109 so that other clients can offer that data too?
That's a great suggestion. I'll take a look
- after this change lands, we should update
package:http_client_conformance_testsredirect_tests.dart to ensure that allClients are implementing this consistently.
Sure, will check this later.
- Are you sure that this is needed? Now that the final URL is available in
BaseResponse, do we need a list of redirects?I believe we should definitely provide such info to users.
I'll let this be your decision but, as far as I know, we don't have an actual use case for this.
- If we do need the list of redirects, could we follow the pattern of Add
BaseResponseWithUrl.url#1109 so that other clients can offer that data too?That's a great suggestion. I'll take a look
- after this change lands, we should update
package:http_client_conformance_testsredirect_tests.dart to ensure that allClients are implementing this consistently.Sure, will check this later.