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
IOClient
will 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
IOClient
will 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 supportredirect
on 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
BaseResponse
in the next breaking release (with appropriate modifications toCronetClient
,BrowserClient
andCupertinoClient
as 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
finalUri
too. 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
IOStreamedResponse
is #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
finalUri
too.
How about just for finalUri
?
I'll try adding a new class for redirects and adding
finalUri
too.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
finalUri
too.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
Client
s
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 - @Zekfad -
BrowserClient
: redirects are opaque
- after this change lands, we should update
package:http_client_conformance_tests
redirect_tests.dart to ensure that allClient
s 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_tests
redirect_tests.dart to ensure that allClient
s 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_tests
redirect_tests.dart to ensure that allClient
s are implementing this consistently.Sure, will check this later.