Skip to content

Commit

Permalink
feat: see changelog
Browse files Browse the repository at this point in the history
  • Loading branch information
Seven Du committed Jan 18, 2024
1 parent 90a82bd commit 6965548
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 36 deletions.
6 changes: 0 additions & 6 deletions docs/advanced/application.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,6 @@ You can set the encoding of the request body through `app.encoding`. The default
app.encoding = utf8;
```

::: tip

Response body encoding cannot be configured in `dart:io`. Internally `dart:io` will try to read the `charset` field of `Content-Type` to determine the encoding of the response body. Otherwise, `utf-8` encoding is used.

:::

## `x-powered-by`

You can set the `x-powered-by` header through `app.poweredBy`. The default is `Spry/<version>`.
Expand Down
25 changes: 24 additions & 1 deletion packages/spry/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
# SPry v3.2.1
# Spry v3.2.2

To install Spry v3.2.2 run the following command:

```bash
dart pub add spry:3.2.2
```

Or update your `pubspec.yaml` file:

```yaml
dependencies:
spry: ^3.2.2
```
## What's Changed
- fix response not using encoding
- fix `FormData` response charset
- `Responsesible` support `HttpClientResponse` of `dart:io`
- `Responsesible` support `HttpResponse` of `dart:io`
- `Responsesible` support `TypedData`

# Spry v3.2.1

To install Spry v3.2.1 run the following command:

Expand Down
19 changes: 1 addition & 18 deletions packages/spry/example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,7 @@ import 'package:spry/spry.dart';
final app = Application.late();

void main(List<String> args) async {
app.get('/', (request) => 'Hello, Spry!');
app.get('/hello/:name', (request) => 'Hello, ${request.params.get('name')}!');
app.get('/hello/:name/:age', (request) {
final name = request.params.get('name');
final age = request.params.get('age');

return 'Hello, $name! You are $age years old.';
});
app.get(
'/hello',
(request) => {
'/': 'Hello, Spry!',
'/hello': 'Index of hello.',
'/hello/:name': 'Say hello to someone.',
'/hello/:name/:age': 'Say hello to someone with age.',
},
);
app.post('/hello', (request) async => 'Hello, ${await request.text()}!');
app.get('hello', (request) => 'Hello, Spry!');

await app.run(port: 3000);

Expand Down
4 changes: 2 additions & 2 deletions packages/spry/lib/src/request/request+json.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ extension Request$Json on HttpRequest {

// Try decode the request body as a JSON object.
try {
return locals[_key] = _codec.decode(await text());
return locals[_key] = jsonCodec.decode(await text());
} catch (_) {
return locals[_key] = null;
} finally {
Expand All @@ -30,7 +30,7 @@ extension Request$Json on HttpRequest {
}

/// Returns JSON codec.
convert.JsonCodec get _codec {
convert.JsonCodec get jsonCodec {
return locals.valueOf<convert.JsonCodec>(_codecKey, (_) {
return application.locals.valueOf<convert.JsonCodec>(_codecKey, (_) {
return convert.JsonCodec();
Expand Down
75 changes: 66 additions & 9 deletions packages/spry/lib/src/response/responsible.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:path/path.dart' show basename;
import 'package:webfetch/webfetch.dart' as webfetch;
Expand All @@ -8,6 +8,10 @@ import 'package:webfetch/webfetch.dart' as webfetch;
import 'package:webfetch/src/_internal/generate_boundary.dart'
show generateBoundary;

import '../application+encoding.dart';
import '../request/request+application.dart';
import '../request/request+json.dart';

abstract interface class Responsible {
/// Responds to the [request].
Future<void> respond(HttpRequest request);
Expand All @@ -30,19 +34,64 @@ abstract interface class Responsible {
/// - Dart scalar types, Eg: `String`, `int`, `double`, `bool`...
factory Responsible.create(Object? object) {
return switch (object) {
webfetch.Blob blob => _StreamResponsible(blob.stream()),
webfetch.FormData formData => _FormDataResponsible(formData),
webfetch.Response response => _WebfetchResponseResponsible(response),
Responsible responsible => responsible,
HttpClientResponse response => _HttpClientResponsesible(response),
HttpResponse _ => const _NullResponsible(),
Map map => _JsonResponsible(map),
Iterable iterable => _JsonResponsible(iterable.toList(growable: false)),
Stream<List<int>> stream => _StreamResponsible(stream),
webfetch.FormData formData => _FormDataResponsible(formData),
webfetch.Response response => _WebfetchResponseResponsible(response),
TypedData typedData => _TypedDataResponsible(typedData),
File file => _FileResponsible(file),
null => const _NullResponsible(),
_ => _NominalResponsible(object),
};
}
}

class _TypedDataResponsible implements Responsible {
final TypedData typedData;

const _TypedDataResponsible(this.typedData);

@override
Future<void> respond(HttpRequest request) async {
final response = request.response;
final encoding = request.application.encoding;
final bytes = typedData.buffer.asUint8List();

response.headers.contentType = response.headers.contentType =
ContentType('application', 'octet-stream', charset: encoding.name);
response.add(bytes);
}
}

class _HttpClientResponsesible implements Responsible {
final HttpClientResponse response;

const _HttpClientResponsesible(this.response);

@override
Future<void> respond(HttpRequest request) async {
final innerResponse = request.response;

innerResponse.statusCode = response.statusCode;
innerResponse.contentLength = response.contentLength;
innerResponse.cookies.addAll(response.cookies);
response.headers.forEach((name, values) {
for (final value in values) {
innerResponse.headers.add(name, value);
}
});

await for (final chunk in response) {
innerResponse.add(chunk);
}
}
}

class _NullResponsible implements Responsible {
const _NullResponsible();

Expand Down Expand Up @@ -113,10 +162,14 @@ class _FormDataResponsible implements Responsible {
final boundary = this.boundary;

final stream = webfetch.FormData.encode(formData, boundary);
response.headers.contentType =
ContentType('multipart', 'form-data', parameters: {
'boundary': boundary,
});
response.headers.contentType = ContentType(
'multipart',
'form-data',
parameters: {
'boundary': boundary,
},
charset: request.application.encoding.name,
);

await response.addStream(stream);
}
Expand Down Expand Up @@ -146,8 +199,12 @@ class _JsonResponsible implements Responsible {
@override
Future<void> respond(HttpRequest request) async {
final response = request.response;
final encoding = request.application.encoding;
final value = request.jsonCodec.encode(object);
final bytes = encoding.encode(value);

response.headers.contentType = ContentType.json;
response.write(json.encode(object));
response.headers.contentType = response.headers.contentType =
ContentType('application', 'json', charset: encoding.name);
response.add(bytes);
}
}

1 comment on commit 6965548

@vercel
Copy link

@vercel vercel bot commented on 6965548 Jan 18, 2024

Choose a reason for hiding this comment

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

Please sign in to comment.