Skip to content

Commit

Permalink
Copy relic package from serverpod repository
Browse files Browse the repository at this point in the history
  • Loading branch information
klkucaj committed Dec 13, 2024
1 parent ddc0321 commit 5c7cf91
Show file tree
Hide file tree
Showing 164 changed files with 25,367 additions and 26 deletions.
1 change: 1 addition & 0 deletions .pubignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test/ssl_certs.dart
37 changes: 32 additions & 5 deletions lib/relic.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,35 @@
/// Support for doing something awesome.
///
/// More dartdocs go here.
library;

export 'src/relic_base.dart';
/// Body related exports
export 'src/body/body.dart' show Body;
export 'src/body/types/body_type.dart' show BodyType;
export 'src/body/types/mime_type.dart' show MimeType;

// TODO: Export any libraries intended for clients of this package.
/// Handler related exports
export 'src/handler/cascade.dart' show Cascade;
export 'src/handler/handler.dart' show Handler;
export 'src/handler/pipeline.dart' show Pipeline;

// Headers related exports
export 'src/headers/headers.dart' show Headers;
export 'src/headers/typed/typed_headers.dart';
export 'src/headers/custom/custom_headers.dart' show CustomHeaders;

/// Hijack related exports
export 'src/hijack/exception/hijack_exception.dart' show HijackException;

/// Message related exports
export 'src/message/request.dart' show Request;
export 'src/message/response.dart' show Response;

/// Middleware related exports
export 'src/middleware/middleware_logger.dart' show logRequests;
export 'src/middleware/middleware.dart' show Middleware, createMiddleware;
export 'src/middleware/middleware_extensions.dart' show MiddlewareExtensions;

/// Relic server related exports
export 'src/relic_server.dart' show RelicServer;
export 'src/relic_server_serve.dart' show serve;

/// Static handler export
export 'src/static/static_handler.dart';
139 changes: 139 additions & 0 deletions lib/src/body/body.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:relic/src/body/types/body_type.dart';
import 'package:relic/src/body/types/mime_type.dart';

/// The body of a request or response.
///
/// This tracks whether the body has been read. It's separate from [Message]
/// because the message may be changed with [Message.copyWith], but each instance
/// should share a notion of whether the body was read.
class Body {
/// The contents of the message body.
///
/// This will be `null` after [read] is called.
Stream<Uint8List>? _stream;

/// The length of the stream returned by [read], or `null` if that can't be
/// determined efficiently.
final int? contentLength;

/// The content type of the body.
///
/// This will be `null` if the body is empty.
///
/// This is a convenience property that combines [mimeType] and [encoding].
/// Example:
/// ```dart
/// var body = Body.fromString('hello', mimeType: MimeType.plainText);
/// print(body.contentType); // ContentType(text/plain; charset=utf-8)
/// ```
final BodyType? contentType;

Body._(
this._stream,
this.contentLength, {
Encoding? encoding,
MimeType? mimeType,
}) : contentType = mimeType == null
? null
: BodyType(mimeType: mimeType, encoding: encoding);

/// Creates an empty body.
factory Body.empty({
Encoding encoding = utf8,
MimeType mimeType = MimeType.plainText,
}) =>
Body._(
Stream.empty(),
0,
encoding: encoding,
mimeType: mimeType,
);

/// Creates a body from a [HttpRequest].
factory Body.fromHttpRequest(HttpRequest request) {
var contentType = request.headers.contentType;
return Body._(
request,
request.contentLength <= 0 ? null : request.contentLength,
encoding: Encoding.getByName(contentType?.charset),
mimeType: contentType?.toMimeType,
);
}

/// Creates a body from a string.
factory Body.fromString(
String body, {
Encoding encoding = utf8,
MimeType mimeType = MimeType.plainText,
}) {
Uint8List encoded = Uint8List.fromList(encoding.encode(body));
return Body._(
Stream.value(encoded),
encoded.length,
encoding: encoding,
mimeType: mimeType,
);
}

/// Creates a body from a [Stream] of [Uint8List].
factory Body.fromDataStream(
Stream<Uint8List> body, {
Encoding? encoding = utf8,
MimeType? mimeType = MimeType.plainText,
int? contentLength,
}) {
return Body._(
body,
contentLength,
encoding: encoding,
mimeType: mimeType,
);
}

/// Creates a body from a [Uint8List].
factory Body.fromData(
Uint8List body, {
Encoding? encoding,
MimeType mimeType = MimeType.binary,
}) {
return Body._(
Stream.value(body),
body.length,
encoding: encoding,
mimeType: mimeType,
);
}

/// Returns a [Stream] representing the body.
///
/// Can only be called once.
Stream<Uint8List> read() {
var stream = _stream;
if (stream == null) {
throw StateError(
"The 'read' method can only be called once on a "
'Request/Response object.',
);
}
_stream = null;
return stream;
}

/// Returns the content type of the body as a [ContentType].
///
/// This is a convenience method that combines [mimeType] and [encoding].
ContentType? getContentType() {
var mContentType = contentType;
if (mContentType == null) return null;
return ContentType(
mContentType.mimeType.primaryType,
mContentType.mimeType.subType,
charset: mContentType.encoding?.name,
);
}
}
86 changes: 86 additions & 0 deletions lib/src/body/types/body_type.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import 'dart:convert';

import 'package:relic/src/body/types/mime_type.dart';

/// A body type.
class BodyType {
/// A body type for plain text.
static const plainText = BodyType(
mimeType: MimeType.plainText,
encoding: utf8,
);

/// A body type for HTML.
static const html = BodyType(
mimeType: MimeType.html,
encoding: utf8,
);

/// A body type for CSS.
static const css = BodyType(
mimeType: MimeType.css,
encoding: utf8,
);

/// A body type for CSV.
static const csv = BodyType(
mimeType: MimeType.csv,
encoding: utf8,
);

/// A body type for JavaScript.
static const javaScript = BodyType(
mimeType: MimeType.javaScript,
encoding: utf8,
);

/// A body type for JSON.
static const json = BodyType(
mimeType: MimeType.json,
encoding: utf8,
);

/// A body type for XML.
static const xml = BodyType(
mimeType: MimeType.xml,
encoding: utf8,
);

/// A body type for binary data.
static const binary = BodyType(
mimeType: MimeType.binary,
);

/// A body type for PDF.
static const pdf = BodyType(
mimeType: MimeType.pdf,
);

/// A body type for RTF.
static const rtf = BodyType(
mimeType: MimeType.rtf,
);

/// The mime type of the body.
final MimeType mimeType;

/// The encoding of the body.
final Encoding? encoding;

const BodyType({
required this.mimeType,
this.encoding,
});

/// Returns the value to use for the Content-Type header.
String toHeaderValue() {
if (encoding != null) {
return '${mimeType.toHeaderValue()}; charset=${encoding!.name}';
} else {
return mimeType.toHeaderValue();
}
}

@override
String toString() => 'BodyType(mimeType: $mimeType, encoding: $encoding)';
}
76 changes: 76 additions & 0 deletions lib/src/body/types/mime_type.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import 'dart:io';

/// A mime type.
class MimeType {
/// Text mime types.
static const plainText = MimeType('text', 'plain');

/// HTML mime type.
static const html = MimeType('text', 'html');

/// CSS mime type.
static const css = MimeType('text', 'css');

/// CSV mime type.
static const csv = MimeType('text', 'csv');

/// JavaScript mime type.
static const javaScript = MimeType('text', 'javascript');

/// JSON mime type.
static const json = MimeType('application', 'json');

/// XML mime type.
static const xml = MimeType('application', 'xml');

/// Binary mime type.
static const binary = MimeType('application', 'octet-stream');

/// PDF mime type.
static const pdf = MimeType('application', 'pdf');

/// RTF mime type.
static const rtf = MimeType('application', 'rtf');

/// The primary type of the mime type.
final String primaryType;

/// The sub type of the mime type.
final String subType;

const MimeType(this.primaryType, this.subType);

/// Parses a mime type from a string.
/// It splits the string on the '/' character and expects exactly two parts.
/// First part is the primary type, second is the sub type.
/// If the string is not a valid mime type then a [FormatException] is thrown.
factory MimeType.parse(String type) {
var parts = type.split('/');
if (parts.length != 2) {
throw FormatException('Invalid mime type $type');
}

var primaryType = parts[0];
var subType = parts[1];

if (primaryType.isEmpty || subType.isEmpty) {
throw FormatException('Invalid mime type $type');
}

return MimeType(primaryType, subType);
}

/// Returns the value to use for the Content-Type header.
String toHeaderValue() => '$primaryType/$subType';

@override
String toString() => 'MimeType(primaryType: $primaryType, subType: $subType)';
}

/// Extension to convert a [ContentType] to a [MimeType].
extension ContentTypeExtension on ContentType {
/// Converts a [ContentType] to a [MimeType].
/// We are calling this method 'toMimeType' to avoid conflict with the 'mimeType' property.
MimeType get toMimeType => MimeType(primaryType, subType);
}
Loading

0 comments on commit 5c7cf91

Please sign in to comment.