Skip to content

Fix content type within Message #120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

donny-dont
Copy link

@donny-dont donny-dont commented Sep 22, 2017

Attempt to fix content-type within Message.

Fixes #101

@donny-dont
Copy link
Author

@nex3 if this is the approach you want I'll comment up the functions/methods before merging.

@donny-dont
Copy link
Author

@nex3 so I made change actually look at the value of body to determine if it was set during the change. This makes it so you can skip the internal headers adjustment which was something I was trying to avoid.

@@ -36,25 +38,20 @@ class Body {
/// used to convert it to a [Stream<List<int>>].
factory Body(body, [Encoding encoding]) {
if (body is Body) return body;
if (body == null)
return new Body._(new Stream.fromIterable([]), encoding, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new Stream.fromIterable() could be const Stream.empty(). It might be even cleaner to return a static _empty field here, though, to avoid any allocations in the common case of an empty body.

Nit: use curly braces.


if (body is Map) {
body = mapToQuery(body, encoding: encoding);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't this in the if/else chain with the other type tests?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value of body becomes a String at this point so it will end up in the is String which would then encode it.

body = mapToQuery(body, encoding: encoding);
}

if (body is String) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to the branch where encoding == null?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should never be null since the encoding is calculated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean when it's set to UTF8 above? But then you're marking ASCII-only bodies as UTF8 when a text/plain content type would do. The old behavior here was correct, there's no need to change it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I'll take a look at what 0.11 was doing here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 0.11, just the previous code in master.


Message._(Body body, Map<String, String> headers, Map<String, Object> context)
Message.__(body, MediaType contentType, Map<String, String> headers,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__ isn't a good name for a constructor--it doesn't communicate what the difference is between this and the other unnamed constructor.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

K I think I need to rename this anyways so it could be used in the multipart implementation.

I also didn't like fromValues but didn't have any better ideas last night.

Message._(Body body, Map<String, String> headers, Map<String, Object> context)
Message.__(body, MediaType contentType, Map<String, String> headers,
Map<String, Object> context)
: this._(new Body(body, encodingForMediaType(contentType, null)), contentType,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new Body(...) invocation looks wrong to me... the Body's encoding shouldn't ever come from the headers, it should only come from the explicit encoding passed by the user. So this should continue to be new Body(body, encoding), which means you don't have to do this many-layered-constructor thing anymore.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_determineMediaType is what determines the encoding for the body. If encoding is set directly then it should override what is in content-type header so that value can be used when creating the body.

This reflects the behavior of this test https://github.com/dart-lang/http/blob/master/test/request_test.dart#L152-L158

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way this is written currently, the encoding passed to new Body() can come from headers. That's not correct. It should only ever come from the encoding parameter, or from the default value (which should be UTF-8).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So just to be clear if someone were to set content-type: 'application/json; charset=iso-8859-1' and not set encoding to LATIN when creating a Request it should not encode the body with LATIN it should be UTF8 encoded?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, and the header should be updated accordingly.

///
/// This constructor should be used when no computation is required for the
/// [body], [headers] or [context].
Message.fromValues(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the performance motivation for having this constructor, but I'd like to focus on API shape and correctness for now and leave optimizations like this for later (ideally driven by real data).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I'll rework this accordingly.

@donny-dont donny-dont force-pushed the fix/content-type-message branch from 1fb0ee5 to 5c7b451 Compare September 28, 2017 00:38
@donny-dont
Copy link
Author

@nex3 should be good to go. I think I addressed all your feedback.

@@ -27,6 +29,9 @@ class Body {
/// determined efficiently.
final int contentLength;

/// An empty stream for use with empty bodies.
static const _emptyStream = const Stream.empty();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant store an instance of Body statically:

static _empty = new Body._(const Stream.empty(), null, 0);

Creating a static field for a const value doesn't do anything since const constructors are already canonicalized.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was looking at implementing this but the issue is that calling read removes the stream.

Do you instead want an EmptyBody class that lets you call read() multiple times?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you instead want an EmptyBody class that lets you call read() multiple times?

Yeah, I think this is the way to go. That matches the behavior of const Stream.empty(), too.

body = mapToQuery(body, encoding: encoding);
}

if (body is String) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean when it's set to UTF8 above? But then you're marking ASCII-only bodies as UTF8 when a text/plain content type would do. The old behavior here was correct, there's no need to change it.


Message._(Body body, Map<String, String> headers, Map<String, Object> context)
Message.withContentType(Body body, MediaType contentType,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want this constructor here. The shape of the constructors from before this CL is generally correct; the only change should be adding a {bool bodyIsMap: false} parameter to new Message._() and _adjustHeaders().

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had planned to use it with http.MultiPart since the MediaType requires a boundary which would be randomly generated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather have _adjustHeaders() do some logic like

if (body is MultipartBody) {
  contentType = "multipart/mixed; boundary=${body.boundary}";
}

@donny-dont donny-dont closed this Jan 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fix url encoded requests
3 participants