-
Notifications
You must be signed in to change notification settings - Fork 381
Emulate shelf messaging #54
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
Conversation
In |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good! I have a fair number of comments, but they're all fairly minor.
lib/src/body.dart
Outdated
@@ -44,14 +42,14 @@ class Body { | |||
stream = new Stream.fromIterable([]); | |||
} else if (body is String) { | |||
if (encoding == null) { | |||
var encoded = UTF8.encode(body); | |||
final encoded = UTF8.encode(body); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final
locals is emphatically not the style this package (or pretty much any Dart-team-authored code) uses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
K I can walk those changes back.
lib/src/headers.dart
Outdated
/// Adds a header with [name] and [value] to [headers], which may be null. | ||
/// | ||
/// Returns a new map without modifying [headers]. | ||
Map<String, String> addHeader( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this actually used? In shelf
, it's only used for adding headers for specialized Response constructors that don't exist here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just getHeader
is used so far. I wasn't completely positive if the others would be of use as we moved further. I'll remove and add back if needed.
lib/src/headers.dart
Outdated
/// | ||
/// This works even if [headers] is `null`, or if it's not yet a | ||
/// case-insensitive map. | ||
bool hasHeader(Map<String, String> headers, String name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also looks like it's not used.
lib/src/http_unmodifiable_map.dart
Outdated
const _EmptyHttpUnmodifiableMap() : super(const {}); | ||
|
||
bool get _ignoreKeyCase => true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lint rule there that I had enabled, http://dart-lang.github.io/linter/lints/sort_constructors_first.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can change it back if you desire. I like the rule because it keeps things consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. In general, please don't change things here just because lints say to—this package doesn't use the linter and it causes churn.
lib/src/message.dart
Outdated
import 'headers.dart'; | ||
import 'http_unmodifiable_map.dart'; | ||
|
||
Body getBody(Message message) => message._body; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Document this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can do. It wasn't documented in shelf
so I had assumed it was more of a utility function.
lib/src/request.dart
Outdated
Map<String, Object> context}) | ||
: super(body, encoding: encoding, headers: headers, context: context); | ||
|
||
/// Creates a new [Request] for [url] using a "HEAD" method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd phrase these as e.g. Creates a new HEAD [Request] to [url].
lib/src/request.dart
Outdated
: this('GET', url, headers: headers, context: context); | ||
|
||
/// Creates a new [Request] for [url] using a "POST" method. | ||
Request.post(Uri url, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constructors for methods that typically have entities should make the body a required parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
lib/src/response.dart
Outdated
/// using the `charset` parameter of the `Content-Type` header field, if | ||
/// available. If it's unavailable or if the encoding name is unknown, | ||
/// [LATIN1] is used by default, as per [RFC 2616][]. | ||
class Response extends Message { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At some point this should utility getters like shelf.Response.expires
et al. That doesn't need to happen in this PR though.
lib/src/request.dart
Outdated
Map<String, Object> context, | ||
dynamic body}) { | ||
final updatedHeaders = updateMap/*<String, String>*/(this.headers, headers); | ||
final updatedContext = updateMap/*<String, Object>*/(this.context, context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these explicit type annotations necessary? Can't it infer the type from the parameters?
lib/src/utils.dart
Outdated
map.forEach((key, value) => pairs.add([ | ||
Uri.encodeQueryComponent(key, encoding: encoding), | ||
Uri.encodeQueryComponent(value, encoding: encoding) | ||
])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't include unrelated formatting changes.
Okay @nex3 I think I have everything resolved. |
lib/src/http_unmodifiable_map.dart
Outdated
const _EmptyHttpUnmodifiableMap() : super(const {}); | ||
|
||
bool get _ignoreKeyCase => true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. In general, please don't change things here just because lints say to—this package doesn't use the linter and it causes churn.
lib/src/request.dart
Outdated
/// The URL to which the request will be sent. | ||
final Uri url; | ||
|
||
/// Creates a new [Request] for [url] using [method]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
lib/src/message.dart
Outdated
@@ -12,11 +12,12 @@ import 'body.dart'; | |||
import 'headers.dart'; | |||
import 'http_unmodifiable_map.dart'; | |||
|
|||
/// Retrieves the [Body] contained in the [message]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explain that it's a separate function so the message body is accessible within shelf but hidden elsewhere.
lib/src/message.dart
Outdated
Body getBody(Message message) => message._body; | ||
|
||
/// The default set of headers for a message created with no body and no | ||
/// explicit headers. | ||
final _defaultHeaders = new HttpUnmodifiableMap<String>({"content-length": "0"}, | ||
final _defaultHeaders = new HttpUnmodifiableMap<String>({}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think just making this empty is enough. We still need to send content-length: 0
for null
-bodied POSTs and other requests that have content.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok so I'm not totally sure the best way to get all this working as you would expect. So how about I create unit tests on what your expectation is and we go from there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, re-reading the spec, it says
The presence of a message-body in a request is signaled by the inclusion of a Content-Length or Transfer-Encoding header field in the request's message-headers.
So it's probably fine to just not include a content-length
header for requests that have no entity body, regardless of their method. We'll need to make sure that dart:io
doesn't force a chunked transfer encoding in those cases, though.
lib/src/message.dart
Outdated
/// | ||
/// For requests, this is used to pass data to inner middleware and handlers; | ||
/// for responses, it's used to pass data to outer middleware and handlers. | ||
/// | ||
/// Context properties that are used by a particular package should begin with | ||
/// that package's name followed by a period. For example, if [logRequests] | ||
/// that package's name followed by a period. For example, if `logRequests` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Referring to logRequests
here seems strange since that's not middleware that exists—and probably not something this package will ever provide. Maybe rephrase this as describing a hypothetical middleware?
lib/src/message.dart
Outdated
/// | ||
/// For requests, this is used to pass data to inner middleware and handlers; | ||
/// for responses, it's used to pass data to outer middleware and handlers. | ||
/// | ||
/// Context properties that are used by a particular package should begin with | ||
/// that package's name followed by a period. For example, if [logRequests] | ||
/// that package's name followed by a period. For example, if `logRequests` | ||
/// wanted to take a prefix, its property name would be `"http.prefix"`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"take a prefix" -> "take a context property"
lib/src/request.dart
Outdated
@@ -7,62 +7,124 @@ import 'dart:convert'; | |||
import 'message.dart'; | |||
import 'utils.dart'; | |||
|
|||
/// Represents an HTTP request to be processed by a `http` application. | |||
/// Represents a HTTP request to be sent to a server. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"an" is correct here.
Aligns
http
's Request and Response with what is present inshelf