add: working on request class port from symfony
This commit is contained in:
parent
b4d9009266
commit
f88021d0ce
7 changed files with 1590 additions and 3 deletions
|
@ -0,0 +1,18 @@
|
||||||
|
import 'package:protevus_http/foundation_exception.dart';
|
||||||
|
|
||||||
|
/// Exception thrown when an HTTP request contains headers with conflicting information.
|
||||||
|
///
|
||||||
|
/// This exception is a subclass of [UnexpectedValueException] and implements
|
||||||
|
/// [RequestExceptionInterface]. It is used to indicate that the headers in an
|
||||||
|
/// HTTP request contain conflicting or inconsistent information.
|
||||||
|
///
|
||||||
|
/// Example usage:
|
||||||
|
/// ```dart
|
||||||
|
/// throw ConflictingHeadersException('Content-Type and Content-Encoding headers are incompatible');
|
||||||
|
/// ```
|
||||||
|
/// @author Magnus Nordlander <magnus@fervo.se>
|
||||||
|
class ConflictingHeadersException extends UnexpectedValueException
|
||||||
|
implements RequestExceptionInterface {
|
||||||
|
/// Creates a new instance of [ConflictingHeadersException].
|
||||||
|
ConflictingHeadersException([super.message]);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import 'package:protevus_http/foundation_exception.dart';
|
||||||
|
|
||||||
|
/// This exception is typically thrown when there's an issue with JSON parsing,
|
||||||
|
/// serialization, or deserialization. It extends [UnexpectedValueException]
|
||||||
|
/// and implements [RequestExceptionInterface].
|
||||||
|
///
|
||||||
|
/// Example usage:
|
||||||
|
/// ```dart
|
||||||
|
/// try {
|
||||||
|
/// // Some JSON operation
|
||||||
|
/// } catch (e) {
|
||||||
|
/// throw JsonException('Failed to parse JSON: $e');
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// @author Magnus Nordlander <magnus@fervo.se>
|
||||||
|
class JsonException extends UnexpectedValueException
|
||||||
|
implements RequestExceptionInterface {
|
||||||
|
/// Creates a new instance of [JsonException].
|
||||||
|
JsonException([super.message]);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import 'package:protevus_http/foundation_exception.dart';
|
||||||
|
import 'package:protevus_mime/mime_exception.dart';
|
||||||
|
|
||||||
|
/// Raised when a session does not exist. This happens in the following cases:
|
||||||
|
/// - the session is not enabled
|
||||||
|
/// - attempt to read a session outside a request context (i.e., CLI script).
|
||||||
|
class SessionNotFoundException extends LogicException
|
||||||
|
implements RequestExceptionInterface {
|
||||||
|
/// Creates a new [SessionNotFoundException] with the given [message], [code], and [previous] exception.
|
||||||
|
SessionNotFoundException({
|
||||||
|
String message = 'There is currently no session available.',
|
||||||
|
int code = 0,
|
||||||
|
Exception? previous,
|
||||||
|
}) : super(message, code, previous);
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import 'package:protevus_http/foundation_exception.dart';
|
||||||
|
|
||||||
|
/// Exception thrown when a suspicious operation is detected during an HTTP request.
|
||||||
|
///
|
||||||
|
/// This exception is a subclass of [UnexpectedValueException] and implements
|
||||||
|
/// [RequestExceptionInterface]. It is used to indicate that a potentially
|
||||||
|
/// unsafe or unexpected operation has been attempted or detected during
|
||||||
|
/// the processing of an HTTP request.
|
||||||
|
///
|
||||||
|
/// Example usage:
|
||||||
|
/// ```dart
|
||||||
|
/// throw SuspiciousOperationException('Attempted to access restricted resource');
|
||||||
|
/// ```
|
||||||
|
/// @author Magnus Nordlander <magnus@fervo.se>
|
||||||
|
class SuspiciousOperationException extends UnexpectedValueException
|
||||||
|
implements RequestExceptionInterface {
|
||||||
|
/// Creates a new instance of [ConflictingHeadersException].
|
||||||
|
SuspiciousOperationException([super.message]);
|
||||||
|
}
|
130
packages/http/lib/src/foundation/file_bag.dart
Normal file
130
packages/http/lib/src/foundation/file_bag.dart
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:collection';
|
||||||
|
import 'package:protevus_http/foundation.dart';
|
||||||
|
import 'package:protevus_http/foundation_file.dart';
|
||||||
|
import 'package:protevus_mime/mime_exception.dart';
|
||||||
|
//import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
/// FileBag is a container for uploaded files.
|
||||||
|
///
|
||||||
|
/// This class is ported from Symfony's HttpFoundation component.
|
||||||
|
class FileBag extends ParameterBag
|
||||||
|
with IterableMixin<MapEntry<String, dynamic>> {
|
||||||
|
static const List<String> _fileKeys = [
|
||||||
|
'error',
|
||||||
|
'full_path',
|
||||||
|
'name',
|
||||||
|
'size',
|
||||||
|
'tmp_name',
|
||||||
|
'type'
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Constructs a FileBag instance.
|
||||||
|
///
|
||||||
|
/// [parameters] is an array of HTTP files.
|
||||||
|
FileBag([Map<String, dynamic> parameters = const {}]) {
|
||||||
|
replace(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces the current files with a new set.
|
||||||
|
@override
|
||||||
|
void replace(Map<String, dynamic> files) {
|
||||||
|
parameters.clear();
|
||||||
|
add(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets a file in the bag.
|
||||||
|
@override
|
||||||
|
void set(String key, dynamic value) {
|
||||||
|
if (value is! Map<String, dynamic> && value is! UploadedFile) {
|
||||||
|
throw InvalidArgumentException(
|
||||||
|
'An uploaded file must be a Map or an instance of UploadedFile.');
|
||||||
|
}
|
||||||
|
|
||||||
|
super.set(key, _convertFileInformation(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds multiple files to the bag.
|
||||||
|
@override
|
||||||
|
void add(Map<String, dynamic> files) {
|
||||||
|
files.forEach((key, file) {
|
||||||
|
set(key, file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts uploaded files to UploadedFile instances.
|
||||||
|
dynamic _convertFileInformation(dynamic file) {
|
||||||
|
if (file is UploadedFile) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file is Map<String, dynamic>) {
|
||||||
|
file = _fixDartFilesMap(file);
|
||||||
|
List<String> keys = (file.keys.toList()..add('full_path'))..sort();
|
||||||
|
|
||||||
|
if (listEquals(_fileKeys, keys)) {
|
||||||
|
if (file['error'] == HttpStatus.noContent) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return UploadedFile(
|
||||||
|
file['tmp_name'],
|
||||||
|
file['full_path'] ?? file['name'],
|
||||||
|
file['type'],
|
||||||
|
file['error'],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return file.map((key, value) {
|
||||||
|
if (value is UploadedFile || value is Map<String, dynamic>) {
|
||||||
|
return MapEntry(key, _convertFileInformation(value));
|
||||||
|
}
|
||||||
|
return MapEntry(key, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fixes a malformed Dart file upload map.
|
||||||
|
///
|
||||||
|
/// This method is equivalent to PHP's fixPhpFilesArray.
|
||||||
|
Map<String, dynamic> _fixDartFilesMap(Map<String, dynamic> data) {
|
||||||
|
List<String> keys = (data.keys.toList()..add('full_path'))..sort();
|
||||||
|
|
||||||
|
if (!listEquals(_fileKeys, keys) ||
|
||||||
|
!data.containsKey('name') ||
|
||||||
|
data['name'] is! Map) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> files = Map.from(data);
|
||||||
|
for (String k in _fileKeys) {
|
||||||
|
files.remove(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
(data['name'] as Map).forEach((key, name) {
|
||||||
|
files[key] = _fixDartFilesMap({
|
||||||
|
'error': data['error'][key],
|
||||||
|
'name': name,
|
||||||
|
'type': data['type'][key],
|
||||||
|
'tmp_name': data['tmp_name'][key],
|
||||||
|
'size': data['size'][key],
|
||||||
|
if (data.containsKey('full_path') && data['full_path'].containsKey(key))
|
||||||
|
'full_path': data['full_path'][key],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility function to compare two lists for equality.
|
||||||
|
bool listEquals<T>(List<T> a, List<T> b) {
|
||||||
|
if (a.length != b.length) return false;
|
||||||
|
for (int i = 0; i < a.length; i++) {
|
||||||
|
if (a[i] != b[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
1333
packages/http/lib/src/foundation/request.dart
Normal file
1333
packages/http/lib/src/foundation/request.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,57 @@
|
||||||
import 'package:protevus_mime/src/exception/exception_interface.dart';
|
class LogicException implements Exception {
|
||||||
|
final String message;
|
||||||
|
final int code;
|
||||||
|
final Exception? previous;
|
||||||
|
final StackTrace? stackTrace;
|
||||||
|
|
||||||
class LogicException extends StateError implements ExceptionInterface {
|
LogicException(
|
||||||
LogicException(super.message);
|
[this.message = "", this.code = 0, this.previous, this.stackTrace]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return "LogicException: $message";
|
||||||
|
}
|
||||||
|
|
||||||
|
String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
Exception? getPrevious() {
|
||||||
|
return previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getFile() {
|
||||||
|
final frames = stackTrace?.toString().split('\n');
|
||||||
|
if (frames != null && frames.isNotEmpty) {
|
||||||
|
final frame = frames.first;
|
||||||
|
final fileInfo = frame.split(' ').last;
|
||||||
|
return fileInfo.split(':').first;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLine() {
|
||||||
|
final frames = stackTrace?.toString().split('\n');
|
||||||
|
if (frames != null && frames.isNotEmpty) {
|
||||||
|
final frame = frames.first;
|
||||||
|
final fileInfo = frame.split(' ').last;
|
||||||
|
final lineInfo = fileInfo.split(':');
|
||||||
|
if (lineInfo.length > 1) {
|
||||||
|
return int.tryParse(lineInfo[1]) ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> getTrace() {
|
||||||
|
return stackTrace?.toString().split('\n') ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
String getTraceAsString() {
|
||||||
|
return stackTrace?.toString() ?? "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue