Skip to content
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

Emulate shelf messaging #54

Merged
merged 18 commits into from Feb 14, 2017
Merged

Emulate shelf messaging #54

merged 18 commits into from Feb 14, 2017

Conversation

donny-dont
Copy link

Aligns http's Request and Response with what is present in shelf

@donny-dont
Copy link
Author

In headers.dart only the getHeader is currently being used. It was present in shelf so its there.

Copy link
Member

@nex3 nex3 left a 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.

@@ -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);
Copy link
Member

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.

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 can walk those changes back.

/// Adds a header with [name] and [value] to [headers], which may be null.
///
/// Returns a new map without modifying [headers].
Map<String, String> addHeader(
Copy link
Member

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.

Copy link
Author

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.

///
/// 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) {
Copy link
Member

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.

const _EmptyHttpUnmodifiableMap() : super(const {});

bool get _ignoreKeyCase => true;
Copy link
Member

Choose a reason for hiding this comment

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

Why this change?

Copy link
Author

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

Copy link
Author

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.

Copy link
Member

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.

import 'headers.dart';
import 'http_unmodifiable_map.dart';

Body getBody(Message message) => message._body;
Copy link
Member

Choose a reason for hiding this comment

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

Document this.

Copy link
Author

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.

Map<String, Object> context})
: super(body, encoding: encoding, headers: headers, context: context);

/// Creates a new [Request] for [url] using a "HEAD" method.
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 phrase these as e.g. Creates a new HEAD [Request] to [url].

: this('GET', url, headers: headers, context: context);

/// Creates a new [Request] for [url] using a "POST" method.
Request.post(Uri url,
Copy link
Member

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.

Copy link
Author

Choose a reason for hiding this comment

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

Fixed

/// 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 {
Copy link
Member

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.

Map<String, Object> context,
dynamic body}) {
final updatedHeaders = updateMap/*<String, String>*/(this.headers, headers);
final updatedContext = updateMap/*<String, Object>*/(this.context, context);
Copy link
Member

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?

map.forEach((key, value) => pairs.add([
Uri.encodeQueryComponent(key, encoding: encoding),
Uri.encodeQueryComponent(value, 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.

Please don't include unrelated formatting changes.

@donny-dont
Copy link
Author

Okay @nex3 I think I have everything resolved.

const _EmptyHttpUnmodifiableMap() : super(const {});

bool get _ignoreKeyCase => true;
Copy link
Member

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.

/// The URL to which the request will be sent.
final Uri url;

/// Creates a new [Request] for [url] using [method].
Copy link
Member

Choose a reason for hiding this comment

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

👍

@@ -12,11 +12,12 @@ import 'body.dart';
import 'headers.dart';
import 'http_unmodifiable_map.dart';

/// Retrieves the [Body] contained in the [message].
Copy link
Member

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.

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>({},
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 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.

Copy link
Author

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?

Copy link
Member

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.

///
/// 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`
Copy link
Member

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?

///
/// 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"`,
Copy link
Member

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"

@@ -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.
Copy link
Member

Choose a reason for hiding this comment

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

"an" is correct here.

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.

None yet

3 participants