diff --git a/packages/contracts/lib/auth.dart b/packages/contracts/lib/auth.dart deleted file mode 100644 index 7ab2298..0000000 --- a/packages/contracts/lib/auth.dart +++ /dev/null @@ -1,19 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Auth Contracts -export 'src/auth/access/authorizable.dart'; -export 'src/auth/access/gate.dart'; -export 'src/auth/middleware/authenticates_request.dart'; -export 'src/auth/authenticatable.dart'; -export 'src/auth/can_reset_password.dart'; -export 'src/auth/factory.dart'; -export 'src/auth/guard.dart'; -export 'src/auth/must_verify_email.dart'; -export 'src/auth/password_broker_factory.dart'; -export 'src/auth/password_broker.dart'; -export 'src/auth/stateful_guard.dart'; -export 'src/auth/supports_basic_auth.dart'; -export 'src/auth/user_provider.dart'; diff --git a/packages/contracts/lib/broadcasting.dart b/packages/contracts/lib/broadcasting.dart deleted file mode 100644 index 1f6bff6..0000000 --- a/packages/contracts/lib/broadcasting.dart +++ /dev/null @@ -1,12 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Broadcasting Contracts -export 'src/broadcasting/broadcaster.dart'; -export 'src/broadcasting/factory.dart'; -export 'src/broadcasting/has_broadcast_channel.dart'; -export 'src/broadcasting/should_be_unique.dart'; -export 'src/broadcasting/should_broadcast.dart'; -export 'src/broadcasting/should_broadcast_now.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/bus.dart b/packages/contracts/lib/bus.dart deleted file mode 100644 index 1842b4f..0000000 --- a/packages/contracts/lib/bus.dart +++ /dev/null @@ -1,8 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Bus Contracts -export 'src/bus/dispatcher.dart'; -export 'src/bus/queueing_dispatcher.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/cache.dart b/packages/contracts/lib/cache.dart deleted file mode 100644 index f240784..0000000 --- a/packages/contracts/lib/cache.dart +++ /dev/null @@ -1,12 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Cache Contracts -export 'src/cache/factory.dart'; -export 'src/cache/lock.dart'; -export 'src/cache/lock_provider.dart'; -export 'src/cache/lock_timeout_exception.dart'; -export 'src/cache/repository.dart'; -export 'src/cache/store.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/config.dart b/packages/contracts/lib/config.dart deleted file mode 100644 index df1c24a..0000000 --- a/packages/contracts/lib/config.dart +++ /dev/null @@ -1,7 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Config Contracts -export 'src/config/repository.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/console.dart b/packages/contracts/lib/console.dart deleted file mode 100644 index 792fa5b..0000000 --- a/packages/contracts/lib/console.dart +++ /dev/null @@ -1,10 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Console Contracts -export 'src/console/application.dart'; -export 'src/console/isolatable.dart'; -export 'src/console/kernel.dart'; -export 'src/console/prompts_for_missing_input.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/container.dart b/packages/contracts/lib/container.dart deleted file mode 100644 index f12f0c2..0000000 --- a/packages/contracts/lib/container.dart +++ /dev/null @@ -1,10 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Container Contracts -export 'src/container/binding_resolution_exception.dart'; -export 'src/container/circular_dependency_exception.dart'; -export 'src/container/container.dart'; -export 'src/container/contextual_binding_builder.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/cookie.dart b/packages/contracts/lib/cookie.dart deleted file mode 100644 index bb24aea..0000000 --- a/packages/contracts/lib/cookie.dart +++ /dev/null @@ -1,8 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Cookie Contract -export 'src/cookie/factory.dart'; -export 'src/cookie/queueing_factory.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/database.dart b/packages/contracts/lib/database.dart deleted file mode 100644 index dd600d2..0000000 --- a/packages/contracts/lib/database.dart +++ /dev/null @@ -1,19 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Database Eloquent Contracts -export 'src/database/eloquent/builder.dart'; -export 'src/database/eloquent/castable.dart'; -export 'src/database/eloquent/casts_attributes.dart'; -export 'src/database/eloquent/casts_inbound_attributes.dart'; -export 'src/database/eloquent/deviates_castable_attributes.dart'; -export 'src/database/eloquent/serializes_castable_attributes.dart'; -export 'src/database/eloquent/supports_partial_relations.dart'; - -// Database Events Contracts -export 'src/database/events/migration_event.dart'; - -// Database Contracts -export 'src/database/model_identifier.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/database_query.dart b/packages/contracts/lib/database_query.dart deleted file mode 100644 index 16c2ca8..0000000 --- a/packages/contracts/lib/database_query.dart +++ /dev/null @@ -1,9 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Database Query Contracts -export 'src/database/query/builder.dart'; -export 'src/database/query/condition_expression.dart'; -export 'src/database/query/expression.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/debug.dart b/packages/contracts/lib/debug.dart deleted file mode 100644 index 11f5428..0000000 --- a/packages/contracts/lib/debug.dart +++ /dev/null @@ -1,7 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Debug Contracts -export 'src/debug/exception_handler.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/encryption.dart b/packages/contracts/lib/encryption.dart deleted file mode 100644 index af5ec92..0000000 --- a/packages/contracts/lib/encryption.dart +++ /dev/null @@ -1,10 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Encryption Contracts -export 'src/encryption/decrypt_exception.dart'; -export 'src/encryption/encrypt_exception.dart'; -export 'src/encryption/encrypter.dart'; -export 'src/encryption/string_encrypter.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/events.dart b/packages/contracts/lib/events.dart deleted file mode 100644 index 6ca98aa..0000000 --- a/packages/contracts/lib/events.dart +++ /dev/null @@ -1,9 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Events Contracts -export 'src/events/dispatcher.dart'; -export 'src/events/should_dispatch_after_commit.dart'; -export 'src/events/should_handle_events_after_commit.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/filesystem.dart b/packages/contracts/lib/filesystem.dart deleted file mode 100644 index d35b224..0000000 --- a/packages/contracts/lib/filesystem.dart +++ /dev/null @@ -1,11 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Filesystem Contracts -export 'src/filesystem/cloud.dart'; -export 'src/filesystem/factory.dart'; -export 'src/filesystem/file_not_found_exception.dart'; -export 'src/filesystem/filesystem.dart'; -export 'src/filesystem/lock_timeout_exception.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/foundation.dart b/packages/contracts/lib/foundation.dart deleted file mode 100644 index babb08c..0000000 --- a/packages/contracts/lib/foundation.dart +++ /dev/null @@ -1,11 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Foundation Contracts -export 'src/foundation/application.dart'; -export 'src/foundation/caches_configuration.dart'; -export 'src/foundation/caches_routes.dart'; -export 'src/foundation/exception_renderer.dart'; -export 'src/foundation/maintenance_mode.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/hashing.dart b/packages/contracts/lib/hashing.dart deleted file mode 100644 index 06b7009..0000000 --- a/packages/contracts/lib/hashing.dart +++ /dev/null @@ -1,7 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Hashing Contracts -export 'src/hashing/hasher.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/http.dart b/packages/contracts/lib/http.dart deleted file mode 100644 index 1d1dd62..0000000 --- a/packages/contracts/lib/http.dart +++ /dev/null @@ -1,7 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Http Contracts -export 'src/http/kernel.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/mail.dart b/packages/contracts/lib/mail.dart deleted file mode 100644 index f669a63..0000000 --- a/packages/contracts/lib/mail.dart +++ /dev/null @@ -1,11 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Mail Contracts -export 'src/mail/attachable.dart'; -export 'src/mail/factory.dart'; -export 'src/mail/mail_queue.dart'; -export 'src/mail/mailable.dart'; -export 'src/mail/mailer.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/notifications.dart b/packages/contracts/lib/notifications.dart deleted file mode 100644 index 4356fa6..0000000 --- a/packages/contracts/lib/notifications.dart +++ /dev/null @@ -1,8 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Notifications Contracts -export 'src/notifications/dispatcher.dart'; -export 'src/notifications/factory.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/pagination.dart b/packages/contracts/lib/pagination.dart deleted file mode 100644 index 4e8335b..0000000 --- a/packages/contracts/lib/pagination.dart +++ /dev/null @@ -1,9 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Pagination Contracts -export 'src/pagination/cursor_paginator.dart'; -export 'src/pagination/length_aware_paginator.dart'; -export 'src/pagination/paginator.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/pipeline.dart b/packages/contracts/lib/pipeline.dart deleted file mode 100644 index d8c20f6..0000000 --- a/packages/contracts/lib/pipeline.dart +++ /dev/null @@ -1,8 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Pipeline Contracts -export 'src/pipeline/hub.dart'; -export 'src/pipeline/pipeline.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/process.dart b/packages/contracts/lib/process.dart deleted file mode 100644 index cd0a9a5..0000000 --- a/packages/contracts/lib/process.dart +++ /dev/null @@ -1,8 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Process Contracts -export 'src/process/invoked_process.dart'; -export 'src/process/process_result.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/queue.dart b/packages/contracts/lib/queue.dart deleted file mode 100644 index 96a2956..0000000 --- a/packages/contracts/lib/queue.dart +++ /dev/null @@ -1,20 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Queue Contracts -export 'src/queue/clearable_queue.dart'; -export 'src/queue/entity_not_found_exception.dart'; -export 'src/queue/entity_resolver.dart'; -export 'src/queue/factory.dart'; -export 'src/queue/job.dart'; -export 'src/queue/monitor.dart'; -export 'src/queue/queue.dart'; -export 'src/queue/queueable_collection.dart'; -export 'src/queue/queueable_entity.dart'; -export 'src/queue/should_be_encrypted.dart'; -export 'src/queue/should_be_unique.dart'; -export 'src/queue/should_be_unique_until_processing.dart'; -export 'src/queue/should_queue.dart'; -export 'src/queue/should_queue_after_commit.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/redis.dart b/packages/contracts/lib/redis.dart deleted file mode 100644 index 4d54684..0000000 --- a/packages/contracts/lib/redis.dart +++ /dev/null @@ -1,10 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Redis Contracts -export 'src/redis/connection.dart'; -export 'src/redis/connector.dart'; -export 'src/redis/factory.dart'; -export 'src/redis/limiter_timeout_exception.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/routing.dart b/packages/contracts/lib/routing.dart deleted file mode 100644 index 4084f01..0000000 --- a/packages/contracts/lib/routing.dart +++ /dev/null @@ -1,11 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Routing Contracts -export 'src/routing/binding_registrar.dart'; -export 'src/routing/registrar.dart'; -export 'src/routing/response_factory.dart'; -export 'src/routing/url_generator.dart'; -export 'src/routing/url_routable.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/session.dart b/packages/contracts/lib/session.dart deleted file mode 100644 index cc05bcd..0000000 --- a/packages/contracts/lib/session.dart +++ /dev/null @@ -1,10 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Session Middleware Contracts -export 'src/session/middleware/authenticates_sessions.dart'; - -// Session Contracts -export 'src/session/session.dart'; \ No newline at end of file diff --git a/packages/mime/example/.gitkeep b/packages/contracts/lib/src/.gitkeep similarity index 100% rename from packages/mime/example/.gitkeep rename to packages/contracts/lib/src/.gitkeep diff --git a/packages/contracts/lib/src/auth/access/authorizable.dart b/packages/contracts/lib/src/auth/access/authorizable.dart deleted file mode 100644 index d8cdf97..0000000 --- a/packages/contracts/lib/src/auth/access/authorizable.dart +++ /dev/null @@ -1,9 +0,0 @@ -abstract class Authorizable { - /// Determine if the entity has a given ability. - /// - /// [abilities] can be an Iterable or a String. - /// [arguments] can be a List or a dynamic type. - /// - /// Returns a boolean indicating if the entity has the given ability. - bool can(dynamic abilities, [List arguments = const []]); -} diff --git a/packages/contracts/lib/src/auth/access/gate.dart b/packages/contracts/lib/src/auth/access/gate.dart deleted file mode 100644 index 56035ab..0000000 --- a/packages/contracts/lib/src/auth/access/gate.dart +++ /dev/null @@ -1,51 +0,0 @@ -// import 'package:meta/meta.dart'; - -abstract class Gate { - /// Determine if a given ability has been defined. - bool has(String ability); - - /// Define a new ability. - Gate define(String ability, dynamic callback); - - /// Define abilities for a resource. - Gate resource(String name, String className, [List? abilities]); - - /// Define a policy class for a given class type. - Gate policy(String className, String policy); - - /// Register a callback to run before all Gate checks. - Gate before(Function callback); - - /// Register a callback to run after all Gate checks. - Gate after(Function callback); - - /// Determine if all of the given abilities should be granted for the current user. - bool allows(dynamic ability, [dynamic arguments]); - - /// Determine if any of the given abilities should be denied for the current user. - bool denies(dynamic ability, [dynamic arguments]); - - /// Determine if all of the given abilities should be granted for the current user. - bool check(dynamic abilities, [dynamic arguments]); - - /// Determine if any one of the given abilities should be granted for the current user. - bool any(dynamic abilities, [dynamic arguments]); - - /// Determine if the given ability should be granted for the current user. - dynamic authorize(String ability, [dynamic arguments]); - - /// Inspect the user for the given ability. - dynamic inspect(String ability, [dynamic arguments]); - - /// Get the raw result from the authorization callback. - dynamic raw(String ability, [dynamic arguments]); - - /// Get a policy instance for a given class. - dynamic getPolicyFor(dynamic className); - - /// Get a guard instance for the given user. - Gate forUser(dynamic user); - - /// Get all of the defined abilities. - List abilities(); -} diff --git a/packages/contracts/lib/src/auth/authenticatable.dart b/packages/contracts/lib/src/auth/authenticatable.dart deleted file mode 100644 index 0663181..0000000 --- a/packages/contracts/lib/src/auth/authenticatable.dart +++ /dev/null @@ -1,37 +0,0 @@ -abstract class Authenticatable { - /// Get the name of the unique identifier for the user. - /// - /// @return string - String getAuthIdentifierName(); - - /// Get the unique identifier for the user. - /// - /// @return dynamic - dynamic getAuthIdentifier(); - - /// Get the name of the password attribute for the user. - /// - /// @return string - String getAuthPasswordName(); - - /// Get the password for the user. - /// - /// @return string - String getAuthPassword(); - - /// Get the token value for the "remember me" session. - /// - /// @return string - String getRememberToken(); - - /// Set the token value for the "remember me" session. - /// - /// @param string value - /// @return void - void setRememberToken(String value); - - /// Get the column name for the "remember me" token. - /// - /// @return string - String getRememberTokenName(); -} diff --git a/packages/contracts/lib/src/auth/can_reset_password.dart b/packages/contracts/lib/src/auth/can_reset_password.dart deleted file mode 100644 index c6b8e9d..0000000 --- a/packages/contracts/lib/src/auth/can_reset_password.dart +++ /dev/null @@ -1,12 +0,0 @@ -abstract class CanResetPassword { - /// Get the e-mail address where password reset links are sent. - /// - /// @return string - String getEmailForPasswordReset(); - - /// Send the password reset notification. - /// - /// @param string token - /// @return void - void sendPasswordResetNotification(String token); -} diff --git a/packages/contracts/lib/src/auth/factory.dart b/packages/contracts/lib/src/auth/factory.dart deleted file mode 100644 index 774bf35..0000000 --- a/packages/contracts/lib/src/auth/factory.dart +++ /dev/null @@ -1,16 +0,0 @@ -//import 'package:your_project_path/contracts/auth/guard.dart'; -//import 'package:your_project_path/contracts/auth/stateful_guard.dart'; -import 'package:protevus_contracts/auth.dart'; - -abstract class Factory { - /// Get a guard instance by name. - /// - /// @param [name] The name of the guard instance to retrieve. - /// @return An instance of [Guard] or [StatefulGuard]. - Guard guard(String? name); - - /// Set the default guard the factory should serve. - /// - /// @param [name] The name of the default guard. - void shouldUse(String name); -} diff --git a/packages/contracts/lib/src/auth/guard.dart b/packages/contracts/lib/src/auth/guard.dart deleted file mode 100644 index f55d818..0000000 --- a/packages/contracts/lib/src/auth/guard.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'authenticatable.dart'; -abstract class Guard { - /// Determine if the current user is authenticated. - /// - /// @return bool - bool check(); - - /// Determine if the current user is a guest. - /// - /// @return bool - bool guest(); - - /// Get the currently authenticated user. - /// - /// @return Authenticatable|null - Authenticatable? user(); - - /// Get the ID for the currently authenticated user. - /// - /// @return int|string|null - dynamic id(); - - /// Validate a user's credentials. - /// - /// @param Map credentials - /// @return bool - bool validate(Map credentials); - - /// Determine if the guard has a user instance. - /// - /// @return bool - bool hasUser(); - - /// Set the current user. - /// - /// @param Authenticatable user - /// @return Guard - Guard setUser(Authenticatable user); -} - -//abstract class Authenticatable { -// String getIdentifier(); -//} diff --git a/packages/contracts/lib/src/auth/middleware/authenticates_request.dart b/packages/contracts/lib/src/auth/middleware/authenticates_request.dart deleted file mode 100644 index d2e3d2a..0000000 --- a/packages/contracts/lib/src/auth/middleware/authenticates_request.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class AuthenticatesRequests { - // Define abstract methods or properties if needed -} diff --git a/packages/contracts/lib/src/auth/must_verify_email.dart b/packages/contracts/lib/src/auth/must_verify_email.dart deleted file mode 100644 index 94f7408..0000000 --- a/packages/contracts/lib/src/auth/must_verify_email.dart +++ /dev/null @@ -1,21 +0,0 @@ -abstract class MustVerifyEmail { - /// Determine if the user has verified their email address. - /// - /// @return bool - bool hasVerifiedEmail(); - - /// Mark the given user's email as verified. - /// - /// @return bool - bool markEmailAsVerified(); - - /// Send the email verification notification. - /// - /// @return void - void sendEmailVerificationNotification(); - - /// Get the email address that should be used for verification. - /// - /// @return string - String getEmailForVerification(); -} diff --git a/packages/contracts/lib/src/auth/password_broker.dart b/packages/contracts/lib/src/auth/password_broker.dart deleted file mode 100644 index 0b7c5b0..0000000 --- a/packages/contracts/lib/src/auth/password_broker.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'dart:async'; - -typedef Closure = FutureOr Function(); - -abstract class PasswordBroker { - /// Constant representing a successfully sent reminder. - static const String RESET_LINK_SENT = 'passwords.sent'; - - /// Constant representing a successfully reset password. - static const String PASSWORD_RESET = 'passwords.reset'; - - /// Constant representing the user not found response. - static const String INVALID_USER = 'passwords.user'; - - /// Constant representing an invalid token. - static const String INVALID_TOKEN = 'passwords.token'; - - /// Constant representing a throttled reset attempt. - static const String RESET_THROTTLED = 'passwords.throttled'; - - /// Send a password reset link to a user. - /// - /// @param Map credentials - /// @param Closure? callback - /// @return Future - Future sendResetLink(Map credentials, [Closure? callback]); - - /// Reset the password for the given token. - /// - /// @param Map credentials - /// @param Closure callback - /// @return Future - Future reset(Map credentials, Closure callback); -} diff --git a/packages/contracts/lib/src/auth/password_broker_factory.dart b/packages/contracts/lib/src/auth/password_broker_factory.dart deleted file mode 100644 index 2948608..0000000 --- a/packages/contracts/lib/src/auth/password_broker_factory.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'password_broker.dart'; - -abstract class PasswordBrokerFactory { - /// Get a password broker instance by name. - /// - /// @param String? name - /// @return PasswordBroker - PasswordBroker broker([String? name]); -} diff --git a/packages/contracts/lib/src/auth/stateful_guard.dart b/packages/contracts/lib/src/auth/stateful_guard.dart deleted file mode 100644 index a747756..0000000 --- a/packages/contracts/lib/src/auth/stateful_guard.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'authenticatable.dart'; -import 'guard.dart'; - -abstract class StatefulGuard extends Guard { - /// Attempt to authenticate a user using the given credentials. - /// - /// [credentials] are the user's credentials. - /// [remember] indicates if the user should be remembered. - /// Returns true if authentication was successful. - Future attempt(Map credentials, {bool remember = false}); - - /// Log a user into the application without sessions or cookies. - /// - /// [credentials] are the user's credentials. - /// Returns true if authentication was successful. - Future once(Map credentials); - - /// Log a user into the application. - /// - /// [user] is the user to log in. - /// [remember] indicates if the user should be remembered. - void login(Authenticatable user, {bool remember = false}); - - /// Log the given user ID into the application. - /// - /// [id] is the ID of the user. - /// [remember] indicates if the user should be remembered. - /// Returns the authenticated user or false if authentication failed. - Future loginUsingId(dynamic id, {bool remember = false}); - - /// Log the given user ID into the application without sessions or cookies. - /// - /// [id] is the ID of the user. - /// Returns the authenticated user or false if authentication failed. - Future onceUsingId(dynamic id); - - /// Determine if the user was authenticated via "remember me" cookie. - /// - /// Returns true if authenticated via "remember me" cookie. - bool viaRemember(); - - /// Log the user out of the application. - void logout(); -} diff --git a/packages/contracts/lib/src/auth/supports_basic_auth.dart b/packages/contracts/lib/src/auth/supports_basic_auth.dart deleted file mode 100644 index 7525ea6..0000000 --- a/packages/contracts/lib/src/auth/supports_basic_auth.dart +++ /dev/null @@ -1,19 +0,0 @@ -//import 'package:symfony/http_foundation.dart'; - -abstract class SupportsBasicAuth { - /// Attempt to authenticate using HTTP Basic Auth. - /// - /// @param String field - /// @param Map extraConditions - /// @return Response|null - Response? basic({String field = 'email', Map extraConditions = const {}}); - - /// Perform a stateless HTTP Basic login attempt. - /// - /// @param String field - /// @param Map extraConditions - /// @return Response|null - Response? onceBasic({String field = 'email', Map extraConditions = const {}}); -} - -// TODO: Find a dart package to replace symfony package for Response. \ No newline at end of file diff --git a/packages/contracts/lib/src/auth/user_provider.dart b/packages/contracts/lib/src/auth/user_provider.dart deleted file mode 100644 index 222427d..0000000 --- a/packages/contracts/lib/src/auth/user_provider.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'authenticatable.dart'; - -abstract class UserProvider { - /// Retrieve a user by their unique identifier. - /// - /// @param dynamic identifier - /// @return Authenticatable|null - Future retrieveById(dynamic identifier); - - /// Retrieve a user by their unique identifier and "remember me" token. - /// - /// @param dynamic identifier - /// @param String token - /// @return Authenticatable|null - Future retrieveByToken(dynamic identifier, String token); - - /// Update the "remember me" token for the given user in storage. - /// - /// @param Authenticatable user - /// @param String token - /// @return void - Future updateRememberToken(Authenticatable user, String token); - - /// Retrieve a user by the given credentials. - /// - /// @param Map credentials - /// @return Authenticatable|null - Future retrieveByCredentials(Map credentials); - - /// Validate a user against the given credentials. - /// - /// @param Authenticatable user - /// @param Map credentials - /// @return bool - Future validateCredentials(Authenticatable user, Map credentials); - - /// Rehash the user's password if required and supported. - /// - /// @param Authenticatable user - /// @param Map credentials - /// @param bool force - /// @return void - Future rehashPasswordIfRequired(Authenticatable user, Map credentials, {bool force = false}); -} diff --git a/packages/contracts/lib/src/broadcasting/broadcaster.dart b/packages/contracts/lib/src/broadcasting/broadcaster.dart deleted file mode 100644 index 1bccc69..0000000 --- a/packages/contracts/lib/src/broadcasting/broadcaster.dart +++ /dev/null @@ -1,36 +0,0 @@ -//import 'package:some_http_package/some_http_package.dart'; // Replace with actual HTTP package - -abstract class Broadcaster { - /// Authenticate the incoming request for a given channel. - /// - /// @param Request request - /// @return mixed - Future auth(Request request); - - /// Return the valid authentication response. - /// - /// @param Request request - /// @param mixed result - /// @return mixed - Future validAuthenticationResponse(Request request, dynamic result); - - /// Broadcast the given event. - /// - /// @param List channels - /// @param String event - /// @param Map payload - /// @return void - /// - /// @throws BroadcastException - Future broadcast(List channels, String event, {Map payload = const {}}); -} - -class BroadcastException implements Exception { - final String message; - BroadcastException(this.message); - - @override - String toString() => 'BroadcastException: $message'; -} - -// TODO: Find dart library to replace symfony for Request Class. \ No newline at end of file diff --git a/packages/contracts/lib/src/broadcasting/factory.dart b/packages/contracts/lib/src/broadcasting/factory.dart deleted file mode 100644 index 3d8c3d0..0000000 --- a/packages/contracts/lib/src/broadcasting/factory.dart +++ /dev/null @@ -1,10 +0,0 @@ - -import 'broadcaster.dart'; - -abstract class Factory { - /// Get a broadcaster implementation by name. - /// - /// @param [name] The name of the broadcaster. - /// @return A [Broadcaster] implementation. - Broadcaster connection([String? name]); -} diff --git a/packages/contracts/lib/src/broadcasting/has_broadcast_channel.dart b/packages/contracts/lib/src/broadcasting/has_broadcast_channel.dart deleted file mode 100644 index 6f1c201..0000000 --- a/packages/contracts/lib/src/broadcasting/has_broadcast_channel.dart +++ /dev/null @@ -1,12 +0,0 @@ - -abstract class HasBroadcastChannel { - /// Get the broadcast channel route definition that is associated with the given entity. - /// - /// @return string - String broadcastChannelRoute(); - - /// Get the broadcast channel name that is associated with the given entity. - /// - /// @return string - String broadcastChannel(); -} diff --git a/packages/contracts/lib/src/broadcasting/should_be_unique.dart b/packages/contracts/lib/src/broadcasting/should_be_unique.dart deleted file mode 100644 index 2361d18..0000000 --- a/packages/contracts/lib/src/broadcasting/should_be_unique.dart +++ /dev/null @@ -1,4 +0,0 @@ - -abstract class ShouldBeUnique { - // No methods or properties defined; serves as a marker interface -} diff --git a/packages/contracts/lib/src/broadcasting/should_broadcast.dart b/packages/contracts/lib/src/broadcasting/should_broadcast.dart deleted file mode 100644 index 0133c7c..0000000 --- a/packages/contracts/lib/src/broadcasting/should_broadcast.dart +++ /dev/null @@ -1,6 +0,0 @@ -abstract class ShouldBroadcast { - /// Get the channels the event should broadcast on. - /// - /// Returns either a single channel or a list of channels. - dynamic broadcastOn(); -} diff --git a/packages/contracts/lib/src/broadcasting/should_broadcast_now.dart b/packages/contracts/lib/src/broadcasting/should_broadcast_now.dart deleted file mode 100644 index 7b45ccf..0000000 --- a/packages/contracts/lib/src/broadcasting/should_broadcast_now.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'should_broadcast.dart'; - -abstract class ShouldBroadcastNow implements ShouldBroadcast { - // Additional methods and properties can be added here if needed. -} diff --git a/packages/contracts/lib/src/bus/dispatcher.dart b/packages/contracts/lib/src/bus/dispatcher.dart deleted file mode 100644 index b847a49..0000000 --- a/packages/contracts/lib/src/bus/dispatcher.dart +++ /dev/null @@ -1,47 +0,0 @@ -abstract class Dispatcher { - /// Dispatch a command to its appropriate handler. - /// - /// @param dynamic command - /// @return dynamic - dynamic dispatch(dynamic command); - - /// Dispatch a command to its appropriate handler in the current process. - /// - /// Queueable jobs will be dispatched to the "sync" queue. - /// - /// @param dynamic command - /// @param dynamic handler - /// @return dynamic - dynamic dispatchSync(dynamic command, [dynamic handler]); - - /// Dispatch a command to its appropriate handler in the current process. - /// - /// @param dynamic command - /// @param dynamic handler - /// @return dynamic - dynamic dispatchNow(dynamic command, [dynamic handler]); - - /// Determine if the given command has a handler. - /// - /// @param dynamic command - /// @return bool - bool hasCommandHandler(dynamic command); - - /// Retrieve the handler for a command. - /// - /// @param dynamic command - /// @return bool|dynamic - dynamic getCommandHandler(dynamic command); - - /// Set the pipes commands should be piped through before dispatching. - /// - /// @param List pipes - /// @return this - Dispatcher pipeThrough(List pipes); - - /// Map a command to a handler. - /// - /// @param Map map - /// @return this - Dispatcher map(Map map); -} diff --git a/packages/contracts/lib/src/bus/queueing_dispatcher.dart b/packages/contracts/lib/src/bus/queueing_dispatcher.dart deleted file mode 100644 index b83683a..0000000 --- a/packages/contracts/lib/src/bus/queueing_dispatcher.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dispatcher.dart'; -import 'batch.dart'; -import 'pending_batch.dart'; - -// TODO: Missing imports will come from other ports refer to original PHP file. - -abstract class QueueingDispatcher implements Dispatcher { - /// Attempt to find the batch with the given ID. - /// - /// @param String batchId - /// @return Batch|null - Future findBatch(String batchId); - - /// Create a new batch of queueable jobs. - /// - /// @param List jobs - /// @return PendingBatch - PendingBatch batch(List jobs); - - /// Dispatch a command to its appropriate handler behind a queue. - /// - /// @param dynamic command - /// @return dynamic - Future dispatchToQueue(dynamic command); -} diff --git a/packages/contracts/lib/src/cache/factory.dart b/packages/contracts/lib/src/cache/factory.dart deleted file mode 100644 index 23c22b7..0000000 --- a/packages/contracts/lib/src/cache/factory.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'repository.dart'; - -abstract class Factory { - /// Get a cache store instance by name. - /// - /// @param String? name - /// @return Repository - Repository store([String? name]); -} diff --git a/packages/contracts/lib/src/cache/lock.dart b/packages/contracts/lib/src/cache/lock.dart deleted file mode 100644 index be1e14e..0000000 --- a/packages/contracts/lib/src/cache/lock.dart +++ /dev/null @@ -1,29 +0,0 @@ -abstract class Lock { - /// Attempt to acquire the lock. - /// - /// @param Function? callback - /// @return dynamic - Future get([Function? callback]); - - /// Attempt to acquire the lock for the given number of seconds. - /// - /// @param int seconds - /// @param Function? callback - /// @return dynamic - Future block(int seconds, [Function? callback]); - - /// Release the lock. - /// - /// @return bool - Future release(); - - /// Returns the current owner of the lock. - /// - /// @return String - Future owner(); - - /// Releases this lock in disregard of ownership. - /// - /// @return void - Future forceRelease(); -} diff --git a/packages/contracts/lib/src/cache/lock_provider.dart b/packages/contracts/lib/src/cache/lock_provider.dart deleted file mode 100644 index a6f42a4..0000000 --- a/packages/contracts/lib/src/cache/lock_provider.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'lock.dart'; -abstract class LockProvider { - /// Get a lock instance. - /// - /// @param String name - /// @param int seconds - /// @param String|null owner - /// @return Lock - Lock lock(String name, {int seconds = 0, String? owner}); - - /// Restore a lock instance using the owner identifier. - /// - /// @param String name - /// @param String owner - /// @return Lock - Lock restoreLock(String name, String owner); -} diff --git a/packages/contracts/lib/src/cache/lock_timeout_exception.dart b/packages/contracts/lib/src/cache/lock_timeout_exception.dart deleted file mode 100644 index 50e8245..0000000 --- a/packages/contracts/lib/src/cache/lock_timeout_exception.dart +++ /dev/null @@ -1,11 +0,0 @@ - -class LockTimeoutException implements Exception { - final String message; - - LockTimeoutException([this.message = '']); - - @override - String toString() { - return 'LockTimeoutException: $message'; - } -} diff --git a/packages/contracts/lib/src/cache/repository.dart b/packages/contracts/lib/src/cache/repository.dart deleted file mode 100644 index 2207cd7..0000000 --- a/packages/contracts/lib/src/cache/repository.dart +++ /dev/null @@ -1,96 +0,0 @@ -import 'package:meta/meta.dart'; -import 'package:psr/simple_cache.dart'; -import 'dart:async'; - -// TODO: Find dart replacements for missing imports. - -abstract class Repository implements CacheInterface { - /// Retrieve an item from the cache and delete it. - /// - /// @template TCacheValue - /// - /// @param List|String key - /// @param TCacheValue|Future Function() default - /// @return Future - Future pull(dynamic key, [dynamic defaultValue]); - - /// Store an item in the cache. - /// - /// @param String key - /// @param dynamic value - /// @param DateTime|Duration|int|null ttl - /// @return Future - Future put(String key, dynamic value, [dynamic ttl]); - - /// Store an item in the cache if the key does not exist. - /// - /// @param String key - /// @param dynamic value - /// @param DateTime|Duration|int|null ttl - /// @return Future - Future add(String key, dynamic value, [dynamic ttl]); - - /// Increment the value of an item in the cache. - /// - /// @param String key - /// @param dynamic value - /// @return Future - Future increment(String key, [int value = 1]); - - /// Decrement the value of an item in the cache. - /// - /// @param String key - /// @param dynamic value - /// @return Future - Future decrement(String key, [int value = 1]); - - /// Store an item in the cache indefinitely. - /// - /// @param String key - /// @param dynamic value - /// @return Future - Future forever(String key, dynamic value); - - /// Get an item from the cache, or execute the given Closure and store the result. - /// - /// @template TCacheValue - /// - /// @param String key - /// @param DateTime|Duration|Future Function()|int|null ttl - /// @param Future Function() callback - /// @return Future - Future remember(String key, dynamic ttl, Future Function() callback); - - /// Get an item from the cache, or execute the given Closure and store the result forever. - /// - /// @template TCacheValue - /// - /// @param String key - /// @param Future Function() callback - /// @return Future - Future sear(String key, Future Function() callback); - - /// Get an item from the cache, or execute the given Closure and store the result forever. - /// - /// @template TCacheValue - /// - /// @param String key - /// @param Future Function() callback - /// @return Future - Future rememberForever(String key, Future Function() callback); - - /// Remove an item from the cache. - /// - /// @param String key - /// @return Future - Future forget(String key); - - /// Get the cache store implementation. - /// - /// @return CacheStore - CacheStore getStore(); -} - -abstract class CacheStore { - // Define methods that a CacheStore should have. -} diff --git a/packages/contracts/lib/src/cache/store.dart b/packages/contracts/lib/src/cache/store.dart deleted file mode 100644 index ebd5f3b..0000000 --- a/packages/contracts/lib/src/cache/store.dart +++ /dev/null @@ -1,67 +0,0 @@ -abstract class Store { - /// Retrieve an item from the cache by key. - /// - /// @param String key - /// @return dynamic - dynamic get(String key); - - /// Retrieve multiple items from the cache by key. - /// - /// Items not found in the cache will have a null value. - /// - /// @param List keys - /// @return Map - Map many(List keys); - - /// Store an item in the cache for a given number of seconds. - /// - /// @param String key - /// @param dynamic value - /// @param int seconds - /// @return bool - bool put(String key, dynamic value, int seconds); - - /// Store multiple items in the cache for a given number of seconds. - /// - /// @param Map values - /// @param int seconds - /// @return bool - bool putMany(Map values, int seconds); - - /// Increment the value of an item in the cache. - /// - /// @param String key - /// @param dynamic value - /// @return int|bool - dynamic increment(String key, {dynamic value = 1}); - - /// Decrement the value of an item in the cache. - /// - /// @param String key - /// @param dynamic value - /// @return int|bool - dynamic decrement(String key, {dynamic value = 1}); - - /// Store an item in the cache indefinitely. - /// - /// @param String key - /// @param dynamic value - /// @return bool - bool forever(String key, dynamic value); - - /// Remove an item from the cache. - /// - /// @param String key - /// @return bool - bool forget(String key); - - /// Remove all items from the cache. - /// - /// @return bool - bool flush(); - - /// Get the cache key prefix. - /// - /// @return String - String getPrefix(); -} diff --git a/packages/contracts/lib/src/config/repository.dart b/packages/contracts/lib/src/config/repository.dart deleted file mode 100644 index 1765bee..0000000 --- a/packages/contracts/lib/src/config/repository.dart +++ /dev/null @@ -1,40 +0,0 @@ -abstract class Repository { - /// Determine if the given configuration value exists. - /// - /// @param String key - /// @return bool - bool has(String key); - - /// Get the specified configuration value. - /// - /// @param String key - /// @param dynamic defaultValue - /// @return dynamic - dynamic get(String key, [dynamic defaultValue]); - - /// Get all of the configuration items for the application. - /// - /// @return Map - Map all(); - - /// Set a given configuration value. - /// - /// @param String key - /// @param dynamic value - /// @return void - void set(String key, [dynamic value]); - - /// Prepend a value onto an array configuration value. - /// - /// @param String key - /// @param dynamic value - /// @return void - void prepend(String key, dynamic value); - - /// Push a value onto an array configuration value. - /// - /// @param String key - /// @param dynamic value - /// @return void - void push(String key, dynamic value); -} diff --git a/packages/contracts/lib/src/console/application.dart b/packages/contracts/lib/src/console/application.dart deleted file mode 100644 index 599b8fa..0000000 --- a/packages/contracts/lib/src/console/application.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:symfony_console/symfony_console.dart'; - -abstract class Application { - /// Run an Artisan console command by name. - /// - /// [command] is the name of the command to run. - /// [parameters] is the list of parameters to pass to the command. - /// [outputBuffer] is the buffer to capture the command output. - /// - /// Returns the exit code of the command. - int call(String command, {List parameters = const [], OutputInterface? outputBuffer}); - - /// Get the output from the last command. - /// - /// Returns the output as a string. - String output(); -} diff --git a/packages/contracts/lib/src/console/isolatable.dart b/packages/contracts/lib/src/console/isolatable.dart deleted file mode 100644 index e3f5284..0000000 --- a/packages/contracts/lib/src/console/isolatable.dart +++ /dev/null @@ -1,4 +0,0 @@ - -abstract class Isolatable { - // Abstract class with no methods -} diff --git a/packages/contracts/lib/src/console/kernel.dart b/packages/contracts/lib/src/console/kernel.dart deleted file mode 100644 index ae7b550..0000000 --- a/packages/contracts/lib/src/console/kernel.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:symfony_console/symfony_console.dart'; - -// TODO: Replace missing imports with dart equivalents. - -abstract class Kernel { - /// Bootstrap the application for artisan commands. - void bootstrap(); - - /// Handle an incoming console command. - /// - /// @param InputInterface input - /// @param OutputInterface? output - /// @return int - int handle(InputInterface input, [OutputInterface? output]); - - /// Run an Artisan console command by name. - /// - /// @param String command - /// @param List parameters - /// @param OutputInterface? outputBuffer - /// @return int - int call(String command, [List parameters = const [], OutputInterface? outputBuffer]); - - /// Queue an Artisan console command by name. - /// - /// @param String command - /// @param List parameters - /// @return PendingDispatch - PendingDispatch queue(String command, [List parameters = const []]); - - /// Get all of the commands registered with the console. - /// - /// @return List - List all(); - - /// Get the output for the last run command. - /// - /// @return String - String output(); - - /// Terminate the application. - /// - /// @param InputInterface input - /// @param int status - /// @return void - void terminate(InputInterface input, int status); -} - -class PendingDispatch { - // Implement the PendingDispatch class here -} diff --git a/packages/contracts/lib/src/console/prompts_for_missing_input.dart b/packages/contracts/lib/src/console/prompts_for_missing_input.dart deleted file mode 100644 index 71f318c..0000000 --- a/packages/contracts/lib/src/console/prompts_for_missing_input.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class PromptsForMissingInput { - // This is a placeholder for future methods. -} diff --git a/packages/contracts/lib/src/container/binding_resolution_exception.dart b/packages/contracts/lib/src/container/binding_resolution_exception.dart deleted file mode 100644 index 7798bbb..0000000 --- a/packages/contracts/lib/src/container/binding_resolution_exception.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:psr_container/psr_container.dart'; - -// TODO: find packages to replace missing imports. - -class BindingResolutionException implements Exception, ContainerException { - final String message; - - BindingResolutionException([this.message = '']); - - @override - String toString() => 'BindingResolutionException: $message'; -} diff --git a/packages/contracts/lib/src/container/circular_dependency_exception.dart b/packages/contracts/lib/src/container/circular_dependency_exception.dart deleted file mode 100644 index adeefd1..0000000 --- a/packages/contracts/lib/src/container/circular_dependency_exception.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:psr/psr.dart'; - -// TODO: Find packages to replace missing imports. - -class CircularDependencyException implements Exception, ContainerExceptionInterface { - final String message; - - CircularDependencyException([this.message = '']); - - @override - String toString() => 'CircularDependencyException: $message'; -} diff --git a/packages/contracts/lib/src/container/container.dart b/packages/contracts/lib/src/container/container.dart deleted file mode 100644 index f7b4225..0000000 --- a/packages/contracts/lib/src/container/container.dart +++ /dev/null @@ -1,174 +0,0 @@ -import 'contextual_binding_builder.dart'; -abstract class Container { - /// Determine if the given abstract type has been bound. - /// - /// @param String abstract - /// @return bool - bool bound(String abstract); - - /// Alias a type to a different name. - /// - /// @param String abstract - /// @param String alias - /// @return void - /// - /// @throws LogicException - void alias(String abstract, String alias); - - /// Assign a set of tags to a given binding. - /// - /// @param List|String abstracts - /// @param List|dynamic tags - /// @return void - void tag(dynamic abstracts, dynamic tags); - - /// Resolve all of the bindings for a given tag. - /// - /// @param String tag - /// @return Iterable - Iterable tagged(String tag); - - /// Register a binding with the container. - /// - /// @param String abstract - /// @param Function|String|null concrete - /// @param bool shared - /// @return void - void bind(String abstract, [dynamic concrete, bool shared = false]); - - /// Bind a callback to resolve with Container::call. - /// - /// @param List|String method - /// @param Function callback - /// @return void - void bindMethod(dynamic method, Function callback); - - /// Register a binding if it hasn't already been registered. - /// - /// @param String abstract - /// @param Function|String|null concrete - /// @param bool shared - /// @return void - void bindIf(String abstract, [dynamic concrete, bool shared = false]); - - /// Register a shared binding in the container. - /// - /// @param String abstract - /// @param Function|String|null concrete - /// @return void - void singleton(String abstract, [dynamic concrete]); - - /// Register a shared binding if it hasn't already been registered. - /// - /// @param String abstract - /// @param Function|String|null concrete - /// @return void - void singletonIf(String abstract, [dynamic concrete]); - - /// Register a scoped binding in the container. - /// - /// @param String abstract - /// @param Function|String|null concrete - /// @return void - void scoped(String abstract, [dynamic concrete]); - - /// Register a scoped binding if it hasn't already been registered. - /// - /// @param String abstract - /// @param Function|String|null concrete - /// @return void - void scopedIf(String abstract, [dynamic concrete]); - - /// "Extend" an abstract type in the container. - /// - /// @param String abstract - /// @param Function closure - /// @return void - /// - /// @throws InvalidArgumentException - void extend(String abstract, Function closure); - - /// Register an existing instance as shared in the container. - /// - /// @param String abstract - /// @param dynamic instance - /// @return dynamic - dynamic instance(String abstract, dynamic instance); - - /// Add a contextual binding to the container. - /// - /// @param String concrete - /// @param String abstract - /// @param Function|String implementation - /// @return void - void addContextualBinding(String concrete, String abstract, dynamic implementation); - - /// Define a contextual binding. - /// - /// @param String|List concrete - /// @return ContextualBindingBuilder - ContextualBindingBuilder when(dynamic concrete); - - /// Get a closure to resolve the given type from the container. - /// - /// @param String abstract - /// @return Function - Function factory(String abstract); - - /// Flush the container of all bindings and resolved instances. - /// - /// @return void - void flush(); - - /// Resolve the given type from the container. - /// - /// @param String abstract - /// @param Map parameters - /// @return dynamic - /// - /// @throws BindingResolutionException - dynamic make(String abstract, [Map parameters = const {}]); - - /// Call the given Function / class@method and inject its dependencies. - /// - /// @param dynamic callback - /// @param Map parameters - /// @param String|null defaultMethod - /// @return dynamic - dynamic call(dynamic callback, [Map parameters = const {}, String defaultMethod]); - - /// Determine if the given abstract type has been resolved. - /// - /// @param String abstract - /// @return bool - bool resolved(String abstract); - - /// Register a new before resolving callback. - /// - /// @param String|Function abstract - /// @param Function|null callback - /// @return void - void beforeResolving(dynamic abstract, [Function? callback]); - - /// Register a new resolving callback. - /// - /// @param String|Function abstract - /// @param Function|null callback - /// @return void - void resolving(dynamic abstract, [Function? callback]); - - /// Register a new after resolving callback. - /// - /// @param String|Function abstract - /// @param Function|null callback - /// @return void - void afterResolving(dynamic abstract, [Function? callback]); -} - -class InvalidArgumentException implements Exception { - // Implementation for InvalidArgumentException -} - -class LogicException implements Exception { - // Implementation for LogicException -} diff --git a/packages/contracts/lib/src/container/contextual_binding_builder.dart b/packages/contracts/lib/src/container/contextual_binding_builder.dart deleted file mode 100644 index 376bdb4..0000000 --- a/packages/contracts/lib/src/container/contextual_binding_builder.dart +++ /dev/null @@ -1,23 +0,0 @@ -abstract class ContextualBindingBuilder { - /// Define the abstract target that depends on the context. - /// - /// [abstract] The abstract target. - /// Returns the current instance. - ContextualBindingBuilder needs(String abstract); - - /// Define the implementation for the contextual binding. - /// - /// [implementation] The implementation which can be a Closure, String, or List. - void give(dynamic implementation); - - /// Define tagged services to be used as the implementation for the contextual binding. - /// - /// [tag] The tag to use. - void giveTagged(String tag); - - /// Specify the configuration item to bind as a primitive. - /// - /// [key] The configuration key. - /// [defaultValue] The default value. - void giveConfig(String key, [dynamic defaultValue]); -} diff --git a/packages/contracts/lib/src/cookie/factory.dart b/packages/contracts/lib/src/cookie/factory.dart deleted file mode 100644 index e2b2589..0000000 --- a/packages/contracts/lib/src/cookie/factory.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:symfony_http_foundation/symfony_http_foundation.dart'; - -// TODO: Replace missing import with dart equivelant. - -abstract class Factory { - /// Create a new cookie instance. - /// - /// @param String name - /// @param String value - /// @param int minutes - /// @param String? path - /// @param String? domain - /// @param bool? secure - /// @param bool httpOnly - /// @param bool raw - /// @param String? sameSite - /// @return Cookie - Cookie make(String name, String value, {int minutes = 0, String? path, String? domain, bool? secure, bool httpOnly = true, bool raw = false, String? sameSite}); - - /// Create a cookie that lasts "forever" (five years). - /// - /// @param String name - /// @param String value - /// @param String? path - /// @param String? domain - /// @param bool? secure - /// @param bool httpOnly - /// @param bool raw - /// @param String? sameSite - /// @return Cookie - Cookie forever(String name, String value, {String? path, String? domain, bool? secure, bool httpOnly = true, bool raw = false, String? sameSite}); - - /// Expire the given cookie. - /// - /// @param String name - /// @param String? path - /// @param String? domain - /// @return Cookie - Cookie forget(String name, {String? path, String? domain}); -} diff --git a/packages/contracts/lib/src/cookie/queueing_factory.dart b/packages/contracts/lib/src/cookie/queueing_factory.dart deleted file mode 100644 index 547ee7c..0000000 --- a/packages/contracts/lib/src/cookie/queueing_factory.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'factory.dart'; - -abstract class QueueingFactory extends Factory { - /// Queue a cookie to send with the next response. - void queue(List parameters); - - /// Remove a cookie from the queue. - void unqueue(String name, [String? path]); - - /// Get the cookies which have been queued for the next request. - List> getQueuedCookies(); -} diff --git a/packages/contracts/lib/src/database/eloquent/builder.dart b/packages/contracts/lib/src/database/eloquent/builder.dart deleted file mode 100644 index 76f8c21..0000000 --- a/packages/contracts/lib/src/database/eloquent/builder.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:illuminate_database/eloquent/builder.dart'; -import 'package:illuminate_database/query/builder.dart' as BaseContract; - -/// This interface is intentionally empty and exists to improve IDE support. -/// -/// @mixin Illuminate\Database\Eloquent\Builder -abstract class Builder implements BaseContract { - // Intentionally left empty -} diff --git a/packages/contracts/lib/src/database/eloquent/castable.dart b/packages/contracts/lib/src/database/eloquent/castable.dart deleted file mode 100644 index ea009d4..0000000 --- a/packages/contracts/lib/src/database/eloquent/castable.dart +++ /dev/null @@ -1,7 +0,0 @@ -abstract class Castable { - /// Get the name of the caster class to use when casting from / to this cast target. - /// - /// @param List arguments - /// @return Type - static Type castUsing(List arguments); -} diff --git a/packages/contracts/lib/src/database/eloquent/casts_attributes.dart b/packages/contracts/lib/src/database/eloquent/casts_attributes.dart deleted file mode 100644 index 8529899..0000000 --- a/packages/contracts/lib/src/database/eloquent/casts_attributes.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'model.dart'; - -/// A generic type parameter for the get method. -typedef TGet = dynamic; - -/// A generic type parameter for the set method. -typedef TSet = dynamic; - -/// An abstract class representing a contract for casting attributes. -abstract class CastsAttributes { - /// Transforms the attribute from the underlying model values. - /// - /// [model] - The model instance. - /// [key] - The attribute key. - /// [value] - The attribute value. - /// [attributes] - The attributes array. - /// - /// Returns the transformed attribute value. - TGet? get(Model model, String key, dynamic value, Map attributes); - - /// Transforms the attribute to its underlying model values. - /// - /// [model] - The model instance. - /// [key] - The attribute key. - /// [value] - The attribute value to be set. - /// [attributes] - The attributes array. - /// - /// Returns the transformed attribute value. - dynamic set(Model model, String key, TSet? value, Map attributes); -} diff --git a/packages/contracts/lib/src/database/eloquent/casts_inbound_attributes.dart b/packages/contracts/lib/src/database/eloquent/casts_inbound_attributes.dart deleted file mode 100644 index 0993b26..0000000 --- a/packages/contracts/lib/src/database/eloquent/casts_inbound_attributes.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:your_package/database/model.dart'; - -abstract class CastsInboundAttributes { - /// Transform the attribute to its underlying model values. - /// - /// @param Model model - /// @param String key - /// @param dynamic value - /// @param Map attributes - /// @return dynamic - dynamic set(Model model, String key, dynamic value, Map attributes); -} diff --git a/packages/contracts/lib/src/database/eloquent/deviates_castable_attributes.dart b/packages/contracts/lib/src/database/eloquent/deviates_castable_attributes.dart deleted file mode 100644 index 73bbe64..0000000 --- a/packages/contracts/lib/src/database/eloquent/deviates_castable_attributes.dart +++ /dev/null @@ -1,19 +0,0 @@ -abstract class DeviatesCastableAttributes { - /// Increment the attribute. - /// - /// @param Model model - /// @param String key - /// @param dynamic value - /// @param Map attributes - /// @return dynamic - dynamic increment(Model model, String key, dynamic value, Map attributes); - - /// Decrement the attribute. - /// - /// @param Model model - /// @param String key - /// @param dynamic value - /// @param Map attributes - /// @return dynamic - dynamic decrement(Model model, String key, dynamic value, Map attributes); -} diff --git a/packages/contracts/lib/src/database/eloquent/serializes_castable_attributes.dart b/packages/contracts/lib/src/database/eloquent/serializes_castable_attributes.dart deleted file mode 100644 index 8219a9e..0000000 --- a/packages/contracts/lib/src/database/eloquent/serializes_castable_attributes.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:your_package_name/eloquent/model.dart'; - -abstract class SerializesCastableAttributes { - /// Serialize the attribute when converting the model to an array. - /// - /// @param \Illuminate\Database\Eloquent\Model $model - /// @param string $key - /// @param mixed $value - /// @param array $attributes - /// @return mixed - dynamic serialize(Model model, String key, dynamic value, Map attributes); -} diff --git a/packages/contracts/lib/src/database/eloquent/supports_partial_relations.dart b/packages/contracts/lib/src/database/eloquent/supports_partial_relations.dart deleted file mode 100644 index f791390..0000000 --- a/packages/contracts/lib/src/database/eloquent/supports_partial_relations.dart +++ /dev/null @@ -1,24 +0,0 @@ -abstract class SupportsPartialRelations { - /// Indicate that the relation is a single result of a larger one-to-many relationship. - /// - /// [column] is the column to aggregate, defaults to 'id'. - /// [aggregate] is the aggregate function, defaults to 'MAX'. - /// [relation] is the relation name. - /// - /// Returns the instance of the class. - SupportsPartialRelations ofMany( - String? column = 'id', - dynamic aggregate = 'MAX', - String? relation, - ); - - /// Determine whether the relationship is a one-of-many relationship. - /// - /// Returns a boolean value indicating whether the relationship is one-of-many. - bool isOneOfMany(); - - /// Get the one of many inner join subselect query builder instance. - /// - /// Returns an instance of the query builder or null. - dynamic getOneOfManySubQuery(); -} diff --git a/packages/contracts/lib/src/database/events/migration_event.dart b/packages/contracts/lib/src/database/events/migration_event.dart deleted file mode 100644 index 9c04f25..0000000 --- a/packages/contracts/lib/src/database/events/migration_event.dart +++ /dev/null @@ -1,4 +0,0 @@ - -abstract class MigrationEvent { - // Add any common functionality or properties if needed -} diff --git a/packages/contracts/lib/src/database/model_identifier.dart b/packages/contracts/lib/src/database/model_identifier.dart deleted file mode 100644 index e935deb..0000000 --- a/packages/contracts/lib/src/database/model_identifier.dart +++ /dev/null @@ -1,32 +0,0 @@ -class ModelIdentifier { - /// The class name of the model. - final String className; - - /// The unique identifier of the model. - /// - /// This may be either a single ID or an array of IDs. - final dynamic id; - - /// The relationships loaded on the model. - final List relations; - - /// The connection name of the model. - final String? connection; - - /// The class name of the model collection. - String? collectionClass; - - /// Create a new model identifier. - ModelIdentifier({ - required this.className, - required this.id, - required this.relations, - this.connection, - }); - - /// Specify the collection class that should be used when serializing / restoring collections. - ModelIdentifier useCollectionClass(String? collectionClass) { - this.collectionClass = collectionClass; - return this; - } -} diff --git a/packages/contracts/lib/src/database/query/builder.dart b/packages/contracts/lib/src/database/query/builder.dart deleted file mode 100644 index 6048c34..0000000 --- a/packages/contracts/lib/src/database/query/builder.dart +++ /dev/null @@ -1,8 +0,0 @@ -//import 'package:laravel_framework/database/query/builder.dart'; - -/// This interface is intentionally empty and exists to improve IDE support. -/// -/// @mixin Builder -abstract class Builder { - // This is intentionally left empty to match the PHP interface. -} diff --git a/packages/contracts/lib/src/database/query/condition_expression.dart b/packages/contracts/lib/src/database/query/condition_expression.dart deleted file mode 100644 index 308e37b..0000000 --- a/packages/contracts/lib/src/database/query/condition_expression.dart +++ /dev/null @@ -1,6 +0,0 @@ -// lib/Illuminate/Contracts/Database/Query/ConditionExpression.dart - -import 'expression.dart'; - -abstract class ConditionExpression implements Expression { -} diff --git a/packages/contracts/lib/src/database/query/expression.dart b/packages/contracts/lib/src/database/query/expression.dart deleted file mode 100644 index 37995d7..0000000 --- a/packages/contracts/lib/src/database/query/expression.dart +++ /dev/null @@ -1,11 +0,0 @@ -// File path: lib/Illuminate/Contracts/Database/Query/expression.dart - -import 'package:your_project/Illuminate/Database/grammar.dart'; - -abstract class Expression { - /// Get the value of the expression. - /// - /// @param Grammar grammar - /// @return String|int|double - dynamic getValue(Grammar grammar); -} diff --git a/packages/contracts/lib/src/debug/exception_handler.dart b/packages/contracts/lib/src/debug/exception_handler.dart deleted file mode 100644 index 63b609b..0000000 --- a/packages/contracts/lib/src/debug/exception_handler.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'dart:async'; - -// TODO: Replace custom classes with dart equivalents. - -abstract class ExceptionHandler { - /// Report or log an exception. - /// - /// @param Throwable e - /// @return void - /// - /// @throws Throwable - Future report(Exception e); - - /// Determine if the exception should be reported. - /// - /// @param Throwable e - /// @return bool - bool shouldReport(Exception e); - - /// Render an exception into an HTTP response. - /// - /// @param Request request - /// @param Throwable e - /// @return Response - /// - /// @throws Throwable - Future render(Request request, Exception e); - - /// Render an exception to the console. - /// - /// @param OutputInterface output - /// @param Throwable e - /// @return void - /// - /// @internal This method is not meant to be used or overwritten outside the framework. - void renderForConsole(OutputInterface output, Exception e); -} - -class Request { - // Add your request properties and methods here. -} - -class Response { - // Add your response properties and methods here. -} - -class OutputInterface { - // Add your output interface properties and methods here. -} diff --git a/packages/contracts/lib/src/encryption/decrypt_exception.dart b/packages/contracts/lib/src/encryption/decrypt_exception.dart deleted file mode 100644 index 90e99e5..0000000 --- a/packages/contracts/lib/src/encryption/decrypt_exception.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'dart:core'; - -class DecryptException implements Exception { - final String message; - - DecryptException([this.message = '']); - - @override - String toString() { - return message.isEmpty ? 'DecryptException' : 'DecryptException: $message'; - } -} diff --git a/packages/contracts/lib/src/encryption/encrypt_exception.dart b/packages/contracts/lib/src/encryption/encrypt_exception.dart deleted file mode 100644 index 5e95ff9..0000000 --- a/packages/contracts/lib/src/encryption/encrypt_exception.dart +++ /dev/null @@ -1,9 +0,0 @@ - -class EncryptException implements Exception { - final String message; - - EncryptException([this.message = '']); - - @override - String toString() => 'EncryptException: $message'; -} diff --git a/packages/contracts/lib/src/encryption/encrypter.dart b/packages/contracts/lib/src/encryption/encrypter.dart deleted file mode 100644 index 6a87556..0000000 --- a/packages/contracts/lib/src/encryption/encrypter.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'dart:async'; - -abstract class Encrypter { - /// Encrypt the given value. - /// - /// [value]: The value to be encrypted. - /// [serialize]: Whether to serialize the value before encryption. - /// Returns a string representing the encrypted value. - /// Throws an EncryptException if encryption fails. - Future encrypt(dynamic value, {bool serialize = true}); - - /// Decrypt the given value. - /// - /// [payload]: The encrypted payload to be decrypted. - /// [unserialize]: Whether to unserialize the value after decryption. - /// Returns the decrypted value. - /// Throws a DecryptException if decryption fails. - Future decrypt(String payload, {bool unserialize = true}); - - /// Get the encryption key that the encrypter is currently using. - /// - /// Returns the current encryption key as a string. - String getKey(); - - /// Get the current encryption key and all previous encryption keys. - /// - /// Returns a list of all encryption keys. - List getAllKeys(); - - /// Get the previous encryption keys. - /// - /// Returns a list of previous encryption keys. - List getPreviousKeys(); -} diff --git a/packages/contracts/lib/src/encryption/string_encrypter.dart b/packages/contracts/lib/src/encryption/string_encrypter.dart deleted file mode 100644 index 2a90155..0000000 --- a/packages/contracts/lib/src/encryption/string_encrypter.dart +++ /dev/null @@ -1,18 +0,0 @@ - -abstract class StringEncrypter { - /// Encrypt a string without serialization. - /// - /// @param String value - /// @return String - /// - /// @throws EncryptException - String encryptString(String value); - - /// Decrypt the given string without unserialization. - /// - /// @param String payload - /// @return String - /// - /// @throws DecryptException - String decryptString(String payload); -} diff --git a/packages/contracts/lib/src/events/dispatcher.dart b/packages/contracts/lib/src/events/dispatcher.dart deleted file mode 100644 index 548c9b3..0000000 --- a/packages/contracts/lib/src/events/dispatcher.dart +++ /dev/null @@ -1,59 +0,0 @@ -abstract class Dispatcher { - /// Register an event listener with the dispatcher. - /// - /// @param Closure|string|array events - /// @param Closure|string|array|null listener - /// @return void - void listen(dynamic events, [dynamic listener]); - - /// Determine if a given event has listeners. - /// - /// @param string eventName - /// @return bool - bool hasListeners(String eventName); - - /// Register an event subscriber with the dispatcher. - /// - /// @param object|string subscriber - /// @return void - void subscribe(dynamic subscriber); - - /// Dispatch an event until the first non-null response is returned. - /// - /// @param string|object event - /// @param mixed payload - /// @return mixed - dynamic until(dynamic event, [dynamic payload]); - - /// Dispatch an event and call the listeners. - /// - /// @param string|object event - /// @param mixed payload - /// @param bool halt - /// @return List|null - List? dispatch(dynamic event, [dynamic payload, bool halt = false]); - - /// Register an event and payload to be fired later. - /// - /// @param string event - /// @param array payload - /// @return void - void push(String event, [List? payload]); - - /// Flush a set of pushed events. - /// - /// @param string event - /// @return void - void flush(String event); - - /// Remove a set of listeners from the dispatcher. - /// - /// @param string event - /// @return void - void forget(String event); - - /// Forget all of the queued listeners. - /// - /// @return void - void forgetPushed(); -} diff --git a/packages/contracts/lib/src/events/should_dispatch_after_commit.dart b/packages/contracts/lib/src/events/should_dispatch_after_commit.dart deleted file mode 100644 index bb12497..0000000 --- a/packages/contracts/lib/src/events/should_dispatch_after_commit.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class ShouldDispatchAfterCommit { - // Interface with no methods -} diff --git a/packages/contracts/lib/src/events/should_handle_events_after_commit.dart b/packages/contracts/lib/src/events/should_handle_events_after_commit.dart deleted file mode 100644 index cc98d34..0000000 --- a/packages/contracts/lib/src/events/should_handle_events_after_commit.dart +++ /dev/null @@ -1,4 +0,0 @@ - -abstract class ShouldHandleEventsAfterCommit { - // Add any method signatures if needed in the future -} diff --git a/packages/contracts/lib/src/filesystem/cloud.dart b/packages/contracts/lib/src/filesystem/cloud.dart deleted file mode 100644 index ad61e53..0000000 --- a/packages/contracts/lib/src/filesystem/cloud.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'filesystem.dart'; -abstract class Cloud implements Filesystem { - /// Get the URL for the file at the given path. - /// - /// @param String path - /// @return String - String url(String path); -} \ No newline at end of file diff --git a/packages/contracts/lib/src/filesystem/factory.dart b/packages/contracts/lib/src/filesystem/factory.dart deleted file mode 100644 index a57232e..0000000 --- a/packages/contracts/lib/src/filesystem/factory.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'filesystem.dart'; - -abstract class Factory { - /// Get a filesystem implementation. - /// - /// @param String? name - /// @return Filesystem - Filesystem disk([String? name]); -} diff --git a/packages/contracts/lib/src/filesystem/file_not_found_exception.dart b/packages/contracts/lib/src/filesystem/file_not_found_exception.dart deleted file mode 100644 index f47a60e..0000000 --- a/packages/contracts/lib/src/filesystem/file_not_found_exception.dart +++ /dev/null @@ -1,9 +0,0 @@ - -class FileNotFoundException implements Exception { - final String message; - - FileNotFoundException([this.message = 'File not found']); - - @override - String toString() => 'FileNotFoundException: $message'; -} diff --git a/packages/contracts/lib/src/filesystem/filesystem.dart b/packages/contracts/lib/src/filesystem/filesystem.dart deleted file mode 100644 index 3efacb8..0000000 --- a/packages/contracts/lib/src/filesystem/filesystem.dart +++ /dev/null @@ -1,164 +0,0 @@ -import 'dart:typed_data'; -import 'dart:io'; - -abstract class Filesystem { - /// The public visibility setting. - static const String VISIBILITY_PUBLIC = 'public'; - - /// The private visibility setting. - static const String VISIBILITY_PRIVATE = 'private'; - - /// Get the full path to the file that exists at the given relative path. - /// - /// @param String path - /// @return String - String path(String path); - - /// Determine if a file exists. - /// - /// @param String path - /// @return bool - bool exists(String path); - - /// Get the contents of a file. - /// - /// @param String path - /// @return Uint8List? (null if file doesn't exist) - Uint8List? get(String path); - - /// Get a resource to read the file. - /// - /// @param String path - /// @return Stream>? (null if file doesn't exist) - Stream>? readStream(String path); - - /// Write the contents of a file. - /// - /// @param String path - /// @param dynamic contents - /// @param Map? options - /// @return bool - bool put(String path, dynamic contents, [Map? options]); - - /// Store the uploaded file on the disk. - /// - /// @param String path - /// @param dynamic file - /// @param Map? options - /// @return String|false - dynamic putFile(String path, dynamic file, [Map? options]); - - /// Store the uploaded file on the disk with a given name. - /// - /// @param String path - /// @param dynamic file - /// @param String? name - /// @param Map? options - /// @return String|false - dynamic putFileAs(String path, dynamic file, [String? name, Map? options]); - - /// Write a new file using a stream. - /// - /// @param String path - /// @param Stream> resource - /// @param Map? options - /// @return bool - bool writeStream(String path, Stream> resource, [Map? options]); - - /// Get the visibility for the given path. - /// - /// @param String path - /// @return String - String getVisibility(String path); - - /// Set the visibility for the given path. - /// - /// @param String path - /// @param String visibility - /// @return bool - bool setVisibility(String path, String visibility); - - /// Prepend to a file. - /// - /// @param String path - /// @param String data - /// @return bool - bool prepend(String path, String data); - - /// Append to a file. - /// - /// @param String path - /// @param String data - /// @return bool - bool append(String path, String data); - - /// Delete the file at a given path. - /// - /// @param dynamic paths - /// @return bool - bool delete(dynamic paths); - - /// Copy a file to a new location. - /// - /// @param String from - /// @param String to - /// @return bool - bool copy(String from, String to); - - /// Move a file to a new location. - /// - /// @param String from - /// @param String to - /// @return bool - bool move(String from, String to); - - /// Get the file size of a given file. - /// - /// @param String path - /// @return int - int size(String path); - - /// Get the file's last modification time. - /// - /// @param String path - /// @return DateTime - DateTime lastModified(String path); - - /// Get an array of all files in a directory. - /// - /// @param String? directory - /// @param bool recursive - /// @return List - List files([String? directory, bool recursive = false]); - - /// Get all of the files from the given directory (recursive). - /// - /// @param String? directory - /// @return List - List allFiles([String? directory]); - - /// Get all of the directories within a given directory. - /// - /// @param String? directory - /// @param bool recursive - /// @return List - List directories([String? directory, bool recursive = false]); - - /// Get all (recursive) of the directories within a given directory. - /// - /// @param String? directory - /// @return List - List allDirectories([String? directory]); - - /// Create a directory. - /// - /// @param String path - /// @return bool - bool makeDirectory(String path); - - /// Recursively delete a directory. - /// - /// @param String directory - /// @return bool - bool deleteDirectory(String directory); -} diff --git a/packages/contracts/lib/src/filesystem/lock_timeout_exception.dart b/packages/contracts/lib/src/filesystem/lock_timeout_exception.dart deleted file mode 100644 index 66f80bd..0000000 --- a/packages/contracts/lib/src/filesystem/lock_timeout_exception.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'dart:io'; - -class LockTimeoutException implements IOException { - final String message; - - LockTimeoutException([this.message = '']); - - @override - String toString() { - return 'LockTimeoutException: $message'; - } -} diff --git a/packages/contracts/lib/src/foundation/application.dart b/packages/contracts/lib/src/foundation/application.dart deleted file mode 100644 index 791090c..0000000 --- a/packages/contracts/lib/src/foundation/application.dart +++ /dev/null @@ -1,102 +0,0 @@ -import 'container.dart'; // Assuming Container is defined in container.dart -import 'maintenance_mode.dart'; // Assuming MaintenanceMode is defined in maintenance_mode.dart - -// TODO: Replace missing imports with dar equivalents. - -abstract class Application extends Container { - /// Get the version number of the application. - String version(); - - /// Get the base path of the installation. - String basePath([String path = '']); - - /// Get the path to the bootstrap directory. - String bootstrapPath([String path = '']); - - /// Get the path to the application configuration files. - String configPath([String path = '']); - - /// Get the path to the database directory. - String databasePath([String path = '']); - - /// Get the path to the language files. - String langPath([String path = '']); - - /// Get the path to the public directory. - String publicPath([String path = '']); - - /// Get the path to the resources directory. - String resourcePath([String path = '']); - - /// Get the path to the storage directory. - String storagePath([String path = '']); - - /// Get or check the current application environment. - dynamic environment(List environments); - - /// Determine if the application is running in the console. - bool runningInConsole(); - - /// Determine if the application is running unit tests. - bool runningUnitTests(); - - /// Determine if the application is running with debug mode enabled. - bool hasDebugModeEnabled(); - - /// Get an instance of the maintenance mode manager implementation. - MaintenanceMode maintenanceMode(); - - /// Determine if the application is currently down for maintenance. - bool isDownForMaintenance(); - - /// Register all of the configured providers. - void registerConfiguredProviders(); - - /// Register a service provider with the application. - ServiceProvider register(dynamic provider, [bool force = false]); - - /// Register a deferred provider and service. - void registerDeferredProvider(String provider, [String? service]); - - /// Resolve a service provider instance from the class name. - ServiceProvider resolveProvider(String provider); - - /// Boot the application's service providers. - void boot(); - - /// Register a new boot listener. - void booting(Function callback); - - /// Register a new "booted" listener. - void booted(Function callback); - - /// Run the given array of bootstrap classes. - void bootstrapWith(List bootstrappers); - - /// Get the current application locale. - String getLocale(); - - /// Get the application namespace. - String getNamespace(); - - /// Get the registered service provider instances if any exist. - List getProviders(dynamic provider); - - /// Determine if the application has been bootstrapped before. - bool hasBeenBootstrapped(); - - /// Load and boot all of the remaining deferred providers. - void loadDeferredProviders(); - - /// Set the current application locale. - void setLocale(String locale); - - /// Determine if middleware has been disabled for the application. - bool shouldSkipMiddleware(); - - /// Register a terminating callback with the application. - Application terminating(dynamic callback); - - /// Terminate the application. - void terminate(); -} diff --git a/packages/contracts/lib/src/foundation/caches_configuration.dart b/packages/contracts/lib/src/foundation/caches_configuration.dart deleted file mode 100644 index 1075dfe..0000000 --- a/packages/contracts/lib/src/foundation/caches_configuration.dart +++ /dev/null @@ -1,17 +0,0 @@ - -abstract class CachesConfiguration { - /// Determine if the application configuration is cached. - /// - /// Returns a boolean indicating if the configuration is cached. - bool configurationIsCached(); - - /// Get the path to the configuration cache file. - /// - /// Returns a string representing the path to the configuration cache file. - String getCachedConfigPath(); - - /// Get the path to the cached services file. - /// - /// Returns a string representing the path to the cached services file. - String getCachedServicesPath(); -} diff --git a/packages/contracts/lib/src/foundation/caches_routes.dart b/packages/contracts/lib/src/foundation/caches_routes.dart deleted file mode 100644 index b81221a..0000000 --- a/packages/contracts/lib/src/foundation/caches_routes.dart +++ /dev/null @@ -1,11 +0,0 @@ -abstract class CachesRoutes { - /// Determine if the application routes are cached. - /// - /// @return bool - bool routesAreCached(); - - /// Get the path to the routes cache file. - /// - /// @return string - String getCachedRoutesPath(); -} diff --git a/packages/contracts/lib/src/foundation/exception_renderer.dart b/packages/contracts/lib/src/foundation/exception_renderer.dart deleted file mode 100644 index d30817b..0000000 --- a/packages/contracts/lib/src/foundation/exception_renderer.dart +++ /dev/null @@ -1,7 +0,0 @@ -abstract class ExceptionRenderer { - /// Renders the given exception as HTML. - /// - /// @param Exception throwable - /// @return String - String render(Exception throwable); -} diff --git a/packages/contracts/lib/src/foundation/maintenance_mode.dart b/packages/contracts/lib/src/foundation/maintenance_mode.dart deleted file mode 100644 index 00890d5..0000000 --- a/packages/contracts/lib/src/foundation/maintenance_mode.dart +++ /dev/null @@ -1,19 +0,0 @@ -abstract class MaintenanceMode { - /// Take the application down for maintenance. - /// - /// [payload] - The payload containing maintenance details. - void activate(Map payload); - - /// Take the application out of maintenance. - void deactivate(); - - /// Determine if the application is currently down for maintenance. - /// - /// Returns `true` if the application is in maintenance mode, `false` otherwise. - bool active(); - - /// Get the data map which was provided when the application was placed into maintenance. - /// - /// Returns a map containing maintenance data. - Map data(); -} diff --git a/packages/contracts/lib/src/hashing/hasher.dart b/packages/contracts/lib/src/hashing/hasher.dart deleted file mode 100644 index 66f3dc2..0000000 --- a/packages/contracts/lib/src/hashing/hasher.dart +++ /dev/null @@ -1,29 +0,0 @@ -abstract class Hasher { - /// Get information about the given hashed value. - /// - /// @param String hashedValue - /// @return Map - Map info(String hashedValue); - - /// Hash the given value. - /// - /// @param String value - /// @param Map options - /// @return String - String make(String value, {Map options = const {}}); - - /// Check the given plain value against a hash. - /// - /// @param String value - /// @param String hashedValue - /// @param Map options - /// @return bool - bool check(String value, String hashedValue, {Map options = const {}}); - - /// Check if the given hash has been hashed using the given options. - /// - /// @param String hashedValue - /// @param Map options - /// @return bool - bool needsRehash(String hashedValue, {Map options = const {}}); -} diff --git a/packages/contracts/lib/src/http/kernel.dart b/packages/contracts/lib/src/http/kernel.dart deleted file mode 100644 index ab92548..0000000 --- a/packages/contracts/lib/src/http/kernel.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:symfony_http/symfony_http.dart' as symfony; -import 'package:illuminate_foundation/illuminate_foundation.dart'; - -// TODO: Find replacements for missing imports. - -abstract class Kernel { - /// Bootstrap the application for HTTP requests. - void bootstrap(); - - /// Handle an incoming HTTP request. - /// - /// @param symfony.Request request - /// @return symfony.Response - symfony.Response handle(symfony.Request request); - - /// Perform any final actions for the request lifecycle. - /// - /// @param symfony.Request request - /// @param symfony.Response response - void terminate(symfony.Request request, symfony.Response response); - - /// Get the application instance. - /// - /// @return Application - Application getApplication(); -} diff --git a/packages/contracts/lib/src/mail/attachable.dart b/packages/contracts/lib/src/mail/attachable.dart deleted file mode 100644 index 62143dd..0000000 --- a/packages/contracts/lib/src/mail/attachable.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:your_project/attachment.dart'; - -// TODO: Check imports - -abstract class Attachable { - /// Get an attachment instance for this entity. - /// - /// @return Attachment - Attachment toMailAttachment(); -} diff --git a/packages/contracts/lib/src/mail/factory.dart b/packages/contracts/lib/src/mail/factory.dart deleted file mode 100644 index 2b07a1f..0000000 --- a/packages/contracts/lib/src/mail/factory.dart +++ /dev/null @@ -1,10 +0,0 @@ -// import statements for required packages -import 'mailer.dart'; - -abstract class Factory { - /// Get a mailer instance by name. - /// - /// @param [name] The name of the mailer instance. - /// @return An instance of [Mailer]. - Mailer mailer([String? name]); -} diff --git a/packages/contracts/lib/src/mail/mail_queue.dart b/packages/contracts/lib/src/mail/mail_queue.dart deleted file mode 100644 index 5b08ef3..0000000 --- a/packages/contracts/lib/src/mail/mail_queue.dart +++ /dev/null @@ -1,20 +0,0 @@ -// Import necessary libraries -import 'dart:async'; - -/// Represents the MailQueue interface. -abstract class MailQueue { - /// Queues a new e-mail message for sending. - /// - /// [view] can be a Mailable, String, or List. - /// [queue] is the optional queue name. - /// Returns a Future representing the queued result. - Future queue(dynamic view, {String? queue}); - - /// Queues a new e-mail message for sending after [delay]. - /// - /// [delay] can be a Duration, int (in seconds), or DateTime. - /// [view] can be a Mailable, String, or List. - /// [queue] is the optional queue name. - /// Returns a Future representing the queued result. - Future later(dynamic delay, dynamic view, {String? queue}); -} diff --git a/packages/contracts/lib/src/mail/mailable.dart b/packages/contracts/lib/src/mail/mailable.dart deleted file mode 100644 index c07851a..0000000 --- a/packages/contracts/lib/src/mail/mailable.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:some_package/queue.dart'; // Replace with actual queue package -import 'package:some_package/mail.dart'; // Replace with actual mail package - -// TODO: Check Imports. - -abstract class Mailable { - /// Send the message using the given mailer. - /// - /// @param Factory|Mailer $mailer - /// @return SentMessage|null - Future send(Mailer mailer); - - /// Queue the given message. - /// - /// @param Queue $queue - /// @return dynamic - Future queue(Queue queue); - - /// Deliver the queued message after (n) seconds. - /// - /// @param DateTimeInterface|Duration|int $delay - /// @param Queue $queue - /// @return dynamic - Future later(dynamic delay, Queue queue); - - /// Set the recipients of the message. - /// - /// @param dynamic $address - /// @param String? $name - /// @return self - Mailable cc(dynamic address, [String? name]); - - /// Set the recipients of the message. - /// - /// @param dynamic $address - /// @param String? $name - /// @return $this - Mailable bcc(dynamic address, [String? name]); - - /// Set the recipients of the message. - /// - /// @param dynamic $address - /// @param String? $name - /// @return $this - Mailable to(dynamic address, [String? name]); - - /// Set the locale of the message. - /// - /// @param String $locale - /// @return $this - Mailable locale(String locale); - - /// Set the name of the mailer that should be used to send the message. - /// - /// @param String $mailer - /// @return $this - Mailable mailer(String mailer); -} diff --git a/packages/contracts/lib/src/mail/mailer.dart b/packages/contracts/lib/src/mail/mailer.dart deleted file mode 100644 index 5bf90ad..0000000 --- a/packages/contracts/lib/src/mail/mailer.dart +++ /dev/null @@ -1,44 +0,0 @@ -abstract class Mailer { - /// Begin the process of mailing a mailable class instance. - /// - /// [users] can be of any type. - /// Returns a PendingMail instance. - PendingMail to(dynamic users); - - /// Begin the process of mailing a mailable class instance. - /// - /// [users] can be of any type. - /// Returns a PendingMail instance. - PendingMail bcc(dynamic users); - - /// Send a new message with only a raw text part. - /// - /// [text] is the raw text message. - /// [callback] can be of any type. - /// Returns a SentMessage instance or null. - SentMessage? raw(String text, dynamic callback); - - /// Send a new message using a view. - /// - /// [view] can be of type Mailable, String, or List. - /// [data] is a map of data to pass to the view. - /// [callback] is a function or null. - /// Returns a SentMessage instance or null. - SentMessage? send(dynamic view, {Map data = const {}, dynamic callback}); - - /// Send a new message synchronously using a view. - /// - /// [mailable] can be of type Mailable, String, or List. - /// [data] is a map of data to pass to the view. - /// [callback] is a function or null. - /// Returns a SentMessage instance or null. - SentMessage? sendNow(dynamic mailable, {Map data = const {}, dynamic callback}); -} - -class PendingMail { - // Implementation of PendingMail class -} - -class SentMessage { - // Implementation of SentMessage class -} diff --git a/packages/contracts/lib/src/notifications/dispatcher.dart b/packages/contracts/lib/src/notifications/dispatcher.dart deleted file mode 100644 index 93ce7f6..0000000 --- a/packages/contracts/lib/src/notifications/dispatcher.dart +++ /dev/null @@ -1,16 +0,0 @@ -abstract class Dispatcher { - /// Send the given notification to the given notifiable entities. - /// - /// @param List|dynamic notifiables - /// @param dynamic notification - /// @return void - void send(dynamic notifiables, dynamic notification); - - /// Send the given notification immediately. - /// - /// @param List|dynamic notifiables - /// @param dynamic notification - /// @param List? channels - /// @return void - void sendNow(dynamic notifiables, dynamic notification, List? channels); -} diff --git a/packages/contracts/lib/src/notifications/factory.dart b/packages/contracts/lib/src/notifications/factory.dart deleted file mode 100644 index 69337ea..0000000 --- a/packages/contracts/lib/src/notifications/factory.dart +++ /dev/null @@ -1,30 +0,0 @@ -// Define the namespace (this would be part of the file structure in Dart) -//library illuminate.contracts.notifications; - -// TODO: Check imports - Check for way to do namespaces - -// Import necessary Dart packages -import 'package:collection/collection.dart'; - -// Define the Factory interface -abstract class Factory { - /// Get a channel instance by name. - /// - /// @param String? name - /// @return dynamic - dynamic channel(String? name); - - /// Send the given notification to the given notifiable entities. - /// - /// @param dynamic notifiables - /// @param dynamic notification - /// @return void - void send(dynamic notifiables, dynamic notification); - - /// Send the given notification immediately. - /// - /// @param dynamic notifiables - /// @param dynamic notification - /// @return void - void sendNow(dynamic notifiables, dynamic notification); -} diff --git a/packages/contracts/lib/src/pagination/cursor_paginator.dart b/packages/contracts/lib/src/pagination/cursor_paginator.dart deleted file mode 100644 index 7137152..0000000 --- a/packages/contracts/lib/src/pagination/cursor_paginator.dart +++ /dev/null @@ -1,87 +0,0 @@ -abstract class CursorPaginator { - /// Get the URL for a given cursor. - /// - /// @param Cursor? cursor - /// @return String - String url(Cursor? cursor); - - /// Add a set of query string values to the paginator. - /// - /// @param List? key - /// @param String? value - /// @return $this - CursorPaginator appends(dynamic key, [String? value]); - - /// Get / set the URL fragment to be appended to URLs. - /// - /// @param String? fragment - /// @return $this|String? - dynamic fragment([String? fragment]); - - /// Add all current query string values to the paginator. - /// - /// @return $this - CursorPaginator withQueryString(); - - /// Get the URL for the previous page, or null. - /// - /// @return String? - String? previousPageUrl(); - - /// The URL for the next page, or null. - /// - /// @return String? - String? nextPageUrl(); - - /// Get all of the items being paginated. - /// - /// @return List - List items(); - - /// Get the "cursor" of the previous set of items. - /// - /// @return Cursor? - Cursor? previousCursor(); - - /// Get the "cursor" of the next set of items. - /// - /// @return Cursor? - Cursor? nextCursor(); - - /// Determine how many items are being shown per page. - /// - /// @return int - int perPage(); - - /// Get the current cursor being paginated. - /// - /// @return Cursor? - Cursor? cursor(); - - /// Determine if there are enough items to split into multiple pages. - /// - /// @return bool - bool hasPages(); - - /// Get the base path for paginator generated URLs. - /// - /// @return String? - String? path(); - - /// Determine if the list of items is empty or not. - /// - /// @return bool - bool isEmpty(); - - /// Determine if the list of items is not empty. - /// - /// @return bool - bool isNotEmpty(); - - /// Render the paginator using a given view. - /// - /// @param String? view - /// @param Map data - /// @return String - String render([String? view, Map data = const {}]); -} diff --git a/packages/contracts/lib/src/pagination/length_aware_paginator.dart b/packages/contracts/lib/src/pagination/length_aware_paginator.dart deleted file mode 100644 index b5de7de..0000000 --- a/packages/contracts/lib/src/pagination/length_aware_paginator.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'paginator.dart'; - -abstract class LengthAwarePaginator extends Paginator { - /// Create a range of pagination URLs. - /// - /// @param int start - /// @param int end - /// @return List - List getUrlRange(int start, int end); - - /// Determine the total number of items in the data store. - /// - /// @return int - int total(); - - /// Get the page number of the last available page. - /// - /// @return int - int lastPage(); -} diff --git a/packages/contracts/lib/src/pagination/paginator.dart b/packages/contracts/lib/src/pagination/paginator.dart deleted file mode 100644 index 01655f5..0000000 --- a/packages/contracts/lib/src/pagination/paginator.dart +++ /dev/null @@ -1,87 +0,0 @@ -abstract class Paginator { - /// Get the URL for a given page. - /// - /// @param int $page - /// @return string - String url(int page); - - /// Add a set of query string values to the paginator. - /// - /// @param array|string|null $key - /// @param string|null $value - /// @return $this - Paginator appends(dynamic key, [String? value]); - - /// Get / set the URL fragment to be appended to URLs. - /// - /// @param string|null $fragment - /// @return $this|string|null - dynamic fragment([String? fragment]); - - /// The URL for the next page, or null. - /// - /// @return string|null - String? nextPageUrl(); - - /// Get the URL for the previous page, or null. - /// - /// @return string|null - String? previousPageUrl(); - - /// Get all of the items being paginated. - /// - /// @return array - List items(); - - /// Get the "index" of the first item being paginated. - /// - /// @return int|null - int? firstItem(); - - /// Get the "index" of the last item being paginated. - /// - /// @return int|null - int? lastItem(); - - /// Determine how many items are being shown per page. - /// - /// @return int - int perPage(); - - /// Determine the current page being paginated. - /// - /// @return int - int currentPage(); - - /// Determine if there are enough items to split into multiple pages. - /// - /// @return bool - bool hasPages(); - - /// Determine if there are more items in the data store. - /// - /// @return bool - bool hasMorePages(); - - /// Get the base path for paginator generated URLs. - /// - /// @return string|null - String? path(); - - /// Determine if the list of items is empty or not. - /// - /// @return bool - bool isEmpty(); - - /// Determine if the list of items is not empty. - /// - /// @return bool - bool isNotEmpty(); - - /// Render the paginator using a given view. - /// - /// @param string|null $view - /// @param array $data - /// @return string - String render([String? view, Map data = const {}]); -} diff --git a/packages/contracts/lib/src/pipeline/hub.dart b/packages/contracts/lib/src/pipeline/hub.dart deleted file mode 100644 index 36b5148..0000000 --- a/packages/contracts/lib/src/pipeline/hub.dart +++ /dev/null @@ -1,10 +0,0 @@ -// Define a Dart interface for Hub - -abstract class Hub { - /// Send an object through one of the available pipelines. - /// - /// @param object The object to be piped. - /// @param pipeline The name of the pipeline, or null to use the default. - /// @return The processed object. - dynamic pipe(dynamic object, [String? pipeline]); -} diff --git a/packages/contracts/lib/src/pipeline/pipeline.dart b/packages/contracts/lib/src/pipeline/pipeline.dart deleted file mode 100644 index 7991d3d..0000000 --- a/packages/contracts/lib/src/pipeline/pipeline.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'dart:async'; - -abstract class Pipeline { - /// Set the traveler object being sent on the pipeline. - Pipeline send(dynamic traveler); - - /// Set the stops of the pipeline. - Pipeline through(dynamic stops); - - /// Set the method to call on the stops. - Pipeline via(String method); - - /// Run the pipeline with a final destination callback. - FutureOr then(FutureOr Function() destination); -} diff --git a/packages/contracts/lib/src/process/invoked_process.dart b/packages/contracts/lib/src/process/invoked_process.dart deleted file mode 100644 index 65edfbc..0000000 --- a/packages/contracts/lib/src/process/invoked_process.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'process_result.dart'; -abstract class InvokedProcess { - /// Get the process ID if the process is still running. - /// - /// Returns an integer or null. - int? id(); - - /// Send a signal to the process. - /// - /// Takes an integer [signal] and returns the current instance. - InvokedProcess signal(int signal); - - /// Determine if the process is still running. - /// - /// Returns a boolean. - bool running(); - - /// Get the standard output for the process. - /// - /// Returns a string. - String output(); - - /// Get the error output for the process. - /// - /// Returns a string. - String errorOutput(); - - /// Get the latest standard output for the process. - /// - /// Returns a string. - String latestOutput(); - - /// Get the latest error output for the process. - /// - /// Returns a string. - String latestErrorOutput(); - - /// Wait for the process to finish. - /// - /// Takes an optional [output] callback and returns a ProcessResult instance. - Future wait([Future Function()? output]); -} diff --git a/packages/contracts/lib/src/process/process_result.dart b/packages/contracts/lib/src/process/process_result.dart deleted file mode 100644 index 82cd974..0000000 --- a/packages/contracts/lib/src/process/process_result.dart +++ /dev/null @@ -1,56 +0,0 @@ -abstract class ProcessResult { - /// Get the original command executed by the process. - /// - /// @return String - String command(); - - /// Determine if the process was successful. - /// - /// @return bool - bool successful(); - - /// Determine if the process failed. - /// - /// @return bool - bool failed(); - - /// Get the exit code of the process. - /// - /// @return int|null - int? exitCode(); - - /// Get the standard output of the process. - /// - /// @return String - String output(); - - /// Determine if the output contains the given string. - /// - /// @param String output - /// @return bool - bool seeInOutput(String output); - - /// Get the error output of the process. - /// - /// @return String - String errorOutput(); - - /// Determine if the error output contains the given string. - /// - /// @param String output - /// @return bool - bool seeInErrorOutput(String output); - - /// Throw an exception if the process failed. - /// - /// @param Function? callback - /// @return ProcessResult - ProcessResult throwException([Function? callback]); - - /// Throw an exception if the process failed and the given condition is true. - /// - /// @param bool condition - /// @param Function? callback - /// @return ProcessResult - ProcessResult throwIf(bool condition, [Function? callback]); -} diff --git a/packages/contracts/lib/src/queue/clearable_queue.dart b/packages/contracts/lib/src/queue/clearable_queue.dart deleted file mode 100644 index d6a6b12..0000000 --- a/packages/contracts/lib/src/queue/clearable_queue.dart +++ /dev/null @@ -1,7 +0,0 @@ -abstract class ClearableQueue { - /// Delete all of the jobs from the queue. - /// - /// @param String queue - /// @return int - int clear(String queue); -} diff --git a/packages/contracts/lib/src/queue/entity_not_found_exception.dart b/packages/contracts/lib/src/queue/entity_not_found_exception.dart deleted file mode 100644 index 025749e..0000000 --- a/packages/contracts/lib/src/queue/entity_not_found_exception.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'dart:core'; - -class EntityNotFoundException implements Exception { - final String message; - - EntityNotFoundException(String type, dynamic id) - : message = "Queueable entity [$type] not found for ID [${id.toString()}]."; - - @override - String toString() => 'EntityNotFoundException: $message'; -} diff --git a/packages/contracts/lib/src/queue/entity_resolver.dart b/packages/contracts/lib/src/queue/entity_resolver.dart deleted file mode 100644 index cf5c1aa..0000000 --- a/packages/contracts/lib/src/queue/entity_resolver.dart +++ /dev/null @@ -1,8 +0,0 @@ -abstract class EntityResolver { - /// Resolve the entity for the given ID. - /// - /// @param String type - /// @param dynamic id - /// @return dynamic - dynamic resolve(String type, dynamic id); -} diff --git a/packages/contracts/lib/src/queue/factory.dart b/packages/contracts/lib/src/queue/factory.dart deleted file mode 100644 index 0a7ef20..0000000 --- a/packages/contracts/lib/src/queue/factory.dart +++ /dev/null @@ -1,12 +0,0 @@ - -import 'queue.dart'; - -// TODO: Fix Imports - -abstract class Factory { - /// Resolve a queue connection instance. - /// - /// @param String? name - /// @return Queue - Queue connection([String? name]); -} diff --git a/packages/contracts/lib/src/queue/job.dart b/packages/contracts/lib/src/queue/job.dart deleted file mode 100644 index d194db9..0000000 --- a/packages/contracts/lib/src/queue/job.dart +++ /dev/null @@ -1,67 +0,0 @@ -abstract class Job { - /// Get the UUID of the job. - String? uuid(); - - /// Get the job identifier. - String getJobId(); - - /// Get the decoded body of the job. - Map payload(); - - /// Fire the job. - void fire(); - - /// Release the job back into the queue after [delay] seconds. - void release(int delay); - - /// Determine if the job was released back into the queue. - bool isReleased(); - - /// Delete the job from the queue. - void delete(); - - /// Determine if the job has been deleted. - bool isDeleted(); - - /// Determine if the job has been deleted or released. - bool isDeletedOrReleased(); - - /// Get the number of times the job has been attempted. - int attempts(); - - /// Determine if the job has been marked as a failure. - bool hasFailed(); - - /// Mark the job as "failed". - void markAsFailed(); - - /// Delete the job, call the "failed" method, and raise the failed job event. - void fail([Exception? e]); - - /// Get the number of times to attempt a job. - int? maxTries(); - - /// Get the maximum number of exceptions allowed, regardless of attempts. - int? maxExceptions(); - - /// Get the number of seconds the job can run. - int? timeout(); - - /// Get the timestamp indicating when the job should timeout. - int? retryUntil(); - - /// Get the name of the queued job class. - String getName(); - - /// Get the resolved name of the queued job class. - String resolveName(); - - /// Get the name of the connection the job belongs to. - String getConnectionName(); - - /// Get the name of the queue the job belongs to. - String getQueue(); - - /// Get the raw body string for the job. - String getRawBody(); -} diff --git a/packages/contracts/lib/src/queue/monitor.dart b/packages/contracts/lib/src/queue/monitor.dart deleted file mode 100644 index 15178a1..0000000 --- a/packages/contracts/lib/src/queue/monitor.dart +++ /dev/null @@ -1,19 +0,0 @@ -abstract class Monitor { - /// Register a callback to be executed on every iteration through the queue loop. - /// - /// @param Function callback - /// @return void - void looping(Function callback); - - /// Register a callback to be executed when a job fails after the maximum number of retries. - /// - /// @param Function callback - /// @return void - void failing(Function callback); - - /// Register a callback to be executed when a daemon queue is stopping. - /// - /// @param Function callback - /// @return void - void stopping(Function callback); -} diff --git a/packages/contracts/lib/src/queue/queue.dart b/packages/contracts/lib/src/queue/queue.dart deleted file mode 100644 index cae309b..0000000 --- a/packages/contracts/lib/src/queue/queue.dart +++ /dev/null @@ -1,75 +0,0 @@ -import "job.dart"; -abstract class Queue { - /// Get the size of the queue. - /// - /// @param String? queue - /// @return int - int size(String? queue); - - /// Push a new job onto the queue. - /// - /// @param String job - /// @param dynamic data - /// @param String? queue - /// @return dynamic - dynamic push(dynamic job, {dynamic data = '', String? queue}); - - /// Push a new job onto the queue. - /// - /// @param String queue - /// @param String job - /// @param dynamic data - /// @return dynamic - dynamic pushOn(String queue, dynamic job, {dynamic data = ''}); - - /// Push a raw payload onto the queue. - /// - /// @param String payload - /// @param String? queue - /// @param Map options - /// @return dynamic - dynamic pushRaw(String payload, {String? queue, Map options = const {}}); - - /// Push a new job onto the queue after (n) seconds. - /// - /// @param dynamic delay - /// @param dynamic job - /// @param dynamic data - /// @param String? queue - /// @return dynamic - dynamic later(dynamic delay, dynamic job, {dynamic data = '', String? queue}); - - /// Push a new job onto a specific queue after (n) seconds. - /// - /// @param String queue - /// @param dynamic delay - /// @param dynamic job - /// @param dynamic data - /// @return dynamic - dynamic laterOn(String queue, dynamic delay, dynamic job, {dynamic data = ''}); - - /// Push an array of jobs onto the queue. - /// - /// @param List jobs - /// @param dynamic data - /// @param String? queue - /// @return dynamic - dynamic bulk(List jobs, {dynamic data = '', String? queue}); - - /// Pop the next job off of the queue. - /// - /// @param String? queue - /// @return Job? - Job? pop(String? queue); - - /// Get the connection name for the queue. - /// - /// @return String - String getConnectionName(); - - /// Set the connection name for the queue. - /// - /// @param String name - /// @return this - Queue setConnectionName(String name); -} diff --git a/packages/contracts/lib/src/queue/queueable_collection.dart b/packages/contracts/lib/src/queue/queueable_collection.dart deleted file mode 100644 index e17d882..0000000 --- a/packages/contracts/lib/src/queue/queueable_collection.dart +++ /dev/null @@ -1,21 +0,0 @@ -abstract class QueueableCollection { - /// Get the type of the entities being queued. - /// - /// @return String|null - String? getQueueableClass(); - - /// Get the identifiers for all of the entities. - /// - /// @return List - List getQueueableIds(); - - /// Get the relationships of the entities being queued. - /// - /// @return List - List getQueueableRelations(); - - /// Get the connection of the entities being queued. - /// - /// @return String|null - String? getQueueableConnection(); -} diff --git a/packages/contracts/lib/src/queue/queueable_entity.dart b/packages/contracts/lib/src/queue/queueable_entity.dart deleted file mode 100644 index 86e95f3..0000000 --- a/packages/contracts/lib/src/queue/queueable_entity.dart +++ /dev/null @@ -1,16 +0,0 @@ -abstract class QueueableEntity { - /// Get the queueable identity for the entity. - /// - /// @return dynamic - dynamic getQueueableId(); - - /// Get the relationships for the entity. - /// - /// @return List - List getQueueableRelations(); - - /// Get the connection of the entity. - /// - /// @return String? - String? getQueueableConnection(); -} diff --git a/packages/contracts/lib/src/queue/should_be_encrypted.dart b/packages/contracts/lib/src/queue/should_be_encrypted.dart deleted file mode 100644 index a8c602d..0000000 --- a/packages/contracts/lib/src/queue/should_be_encrypted.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class ShouldBeEncrypted { - // Add any necessary methods or properties here -} diff --git a/packages/contracts/lib/src/queue/should_be_unique.dart b/packages/contracts/lib/src/queue/should_be_unique.dart deleted file mode 100644 index 4a570c9..0000000 --- a/packages/contracts/lib/src/queue/should_be_unique.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class ShouldBeUnique { - // This is an abstract class that serves as a marker interface. -} diff --git a/packages/contracts/lib/src/queue/should_be_unique_until_processing.dart b/packages/contracts/lib/src/queue/should_be_unique_until_processing.dart deleted file mode 100644 index fcefd6e..0000000 --- a/packages/contracts/lib/src/queue/should_be_unique_until_processing.dart +++ /dev/null @@ -1,8 +0,0 @@ -// File: illuminate/contracts/queue/should_be_unique_until_processing.dart - -import 'should_be_unique.dart'; - -abstract class ShouldBeUniqueUntilProcessing implements ShouldBeUnique { - // This interface can include any additional methods or properties if needed - // Currently, it's just extending ShouldBeUnique -} diff --git a/packages/contracts/lib/src/queue/should_queue.dart b/packages/contracts/lib/src/queue/should_queue.dart deleted file mode 100644 index f283cef..0000000 --- a/packages/contracts/lib/src/queue/should_queue.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class ShouldQueue { - // Interface with no methods defined -} diff --git a/packages/contracts/lib/src/queue/should_queue_after_commit.dart b/packages/contracts/lib/src/queue/should_queue_after_commit.dart deleted file mode 100644 index dec46c1..0000000 --- a/packages/contracts/lib/src/queue/should_queue_after_commit.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'should_queue.dart'; -abstract class ShouldQueueAfterCommit implements ShouldQueue { - // Additional functionalities can be added here if needed -} diff --git a/packages/contracts/lib/src/redis/connection.dart b/packages/contracts/lib/src/redis/connection.dart deleted file mode 100644 index 8adbf13..0000000 --- a/packages/contracts/lib/src/redis/connection.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'dart:async'; - -abstract class Connection { - /// Subscribe to a set of given channels for messages. - /// - /// @param List channels - /// @param void Function(dynamic) callback - /// @return void - void subscribe(List channels, void Function(dynamic) callback); - - /// Subscribe to a set of given channels with wildcards. - /// - /// @param List channels - /// @param void Function(dynamic) callback - /// @return void - void psubscribe(List channels, void Function(dynamic) callback); - - /// Run a command against the Redis database. - /// - /// @param String method - /// @param List parameters - /// @return Future - Future command(String method, [List parameters = const []]); -} diff --git a/packages/contracts/lib/src/redis/connector.dart b/packages/contracts/lib/src/redis/connector.dart deleted file mode 100644 index bfba9da..0000000 --- a/packages/contracts/lib/src/redis/connector.dart +++ /dev/null @@ -1,19 +0,0 @@ - -import 'connection.dart'; - -abstract class Connector { - /// Create a connection to a Redis cluster. - /// - /// @param config - /// @param options - /// @return Connection - Connection connect(Map config, Map options); - - /// Create a connection to a Redis instance. - /// - /// @param config - /// @param clusterOptions - /// @param options - /// @return Connection - Connection connectToCluster(Map config, Map clusterOptions, Map options); -} diff --git a/packages/contracts/lib/src/redis/factory.dart b/packages/contracts/lib/src/redis/factory.dart deleted file mode 100644 index ca9521c..0000000 --- a/packages/contracts/lib/src/redis/factory.dart +++ /dev/null @@ -1,11 +0,0 @@ -// file: lib/src/contracts/redis/factory.dart - -import 'connection.dart'; - -abstract class Factory { - /// Get a Redis connection by name. - /// - /// @param [String] name - /// @return [Connection] - Connection connection([String? name]); -} diff --git a/packages/contracts/lib/src/redis/limiter_timeout_exception.dart b/packages/contracts/lib/src/redis/limiter_timeout_exception.dart deleted file mode 100644 index 71ec3b3..0000000 --- a/packages/contracts/lib/src/redis/limiter_timeout_exception.dart +++ /dev/null @@ -1,10 +0,0 @@ -//import 'package:redis/redis.dart'; - -class LimiterTimeoutException implements Exception { - final String message; - - LimiterTimeoutException([this.message = '']); - - @override - String toString() => message.isEmpty ? 'LimiterTimeoutException' : 'LimiterTimeoutException: $message'; -} diff --git a/packages/contracts/lib/src/routing/binding_registrar.dart b/packages/contracts/lib/src/routing/binding_registrar.dart deleted file mode 100644 index f7af5c1..0000000 --- a/packages/contracts/lib/src/routing/binding_registrar.dart +++ /dev/null @@ -1,14 +0,0 @@ -abstract class BindingRegistrar { - /// Add a new route parameter binder. - /// - /// @param String key - /// @param String or Function binder - /// @return void - void bind(String key, dynamic binder); - - /// Get the binding callback for a given binding. - /// - /// @param String key - /// @return Function - Function getBindingCallback(String key); -} diff --git a/packages/contracts/lib/src/routing/registrar.dart b/packages/contracts/lib/src/routing/registrar.dart deleted file mode 100644 index 1aeedac..0000000 --- a/packages/contracts/lib/src/routing/registrar.dart +++ /dev/null @@ -1,82 +0,0 @@ -import 'route.dart'; - -// TODO: Fix Imports. - -abstract class Registrar { - /// Register a new GET route with the router. - /// - /// @param string $uri - /// @param array|string|callable $action - /// @return \Illuminate\Routing\Route - Route get(String uri, dynamic action); - - /// Register a new POST route with the router. - /// - /// @param string $uri - /// @param array|string|callable $action - /// @return \Illuminate\Routing\Route - Route post(String uri, dynamic action); - - /// Register a new PUT route with the router. - /// - /// @param string $uri - /// @param array|string|callable $action - /// @return \Illuminate\Routing\Route - Route put(String uri, dynamic action); - - /// Register a new DELETE route with the router. - /// - /// @param string $uri - /// @param array|string|callable $action - /// @return \Illuminate\Routing\Route - Route delete(String uri, dynamic action); - - /// Register a new PATCH route with the router. - /// - /// @param string $uri - /// @param array|string|callable $action - /// @return \Illuminate\Routing\Route - Route patch(String uri, dynamic action); - - /// Register a new OPTIONS route with the router. - /// - /// @param string $uri - /// @param array|string|callable $action - /// @return \Illuminate\Routing\Route - Route options(String uri, dynamic action); - - /// Register a new route with the given verbs. - /// - /// @param array|string $methods - /// @param string $uri - /// @param array|string|callable $action - /// @return \Illuminate\Routing\Route - Route match(dynamic methods, String uri, dynamic action); - - /// Route a resource to a controller. - /// - /// @param string $name - /// @param string $controller - /// @param array $options - /// @return \Illuminate\Routing\PendingResourceRegistration - PendingResourceRegistration resource(String name, String controller, [Map? options]); - - /// Create a route group with shared attributes. - /// - /// @param array $attributes - /// @param \Closure|string $routes - /// @return void - void group(Map attributes, dynamic routes); - - /// Substitute the route bindings onto the route. - /// - /// @param \Illuminate\Routing\Route $route - /// @return \Illuminate\Routing\Route - Route substituteBindings(Route route); - - /// Substitute the implicit Eloquent model bindings for the route. - /// - /// @param \Illuminate\Routing\Route $route - /// @return void - void substituteImplicitBindings(Route route); -} diff --git a/packages/contracts/lib/src/routing/response_factory.dart b/packages/contracts/lib/src/routing/response_factory.dart deleted file mode 100644 index 8d310c7..0000000 --- a/packages/contracts/lib/src/routing/response_factory.dart +++ /dev/null @@ -1,124 +0,0 @@ -import 'dart:io'; - -abstract class ResponseFactory { - /// Create a new response instance. - /// - /// [content] can be an array or a string. - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// Returns a Response object. - HttpResponse make(dynamic content, {int status = 200, Map headers = const {}}); - - /// Create a new "no content" response. - /// - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// Returns a Response object. - HttpResponse noContent({int status = 204, Map headers = const {}}); - - /// Create a new response for a given view. - /// - /// [view] can be a string or an array. - /// [data] is the data to be passed to the view. - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// Returns a Response object. - HttpResponse view(dynamic view, {Map data = const {}, int status = 200, Map headers = const {}}); - - /// Create a new JSON response instance. - /// - /// [data] is the data to be returned as JSON. - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// [options] are the JSON options. - /// Returns a JsonResponse object. - HttpResponse json(dynamic data, {int status = 200, Map headers = const {}, int options = 0}); - - /// Create a new JSONP response instance. - /// - /// [callback] is the JSONP callback name. - /// [data] is the data to be returned as JSONP. - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// [options] are the JSON options. - /// Returns a JsonResponse object. - HttpResponse jsonp(String callback, dynamic data, {int status = 200, Map headers = const {}, int options = 0}); - - /// Create a new streamed response instance. - /// - /// [callback] is the callback function for streaming. - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// Returns a StreamedResponse object. - HttpResponse stream(Function callback, {int status = 200, Map headers = const {}}); - - /// Create a new streamed response instance as a file download. - /// - /// [callback] is the callback function for streaming. - /// [name] is the name of the file. - /// [headers] are the HTTP headers. - /// [disposition] is the content disposition. - /// Returns a StreamedResponse object. - HttpResponse streamDownload(Function callback, {String? name, Map headers = const {}, String disposition = 'attachment'}); - - /// Create a new file download response. - /// - /// [file] is the file to be downloaded. - /// [name] is the name of the file. - /// [headers] are the HTTP headers. - /// [disposition] is the content disposition. - /// Returns a BinaryFileResponse object. - HttpResponse download(dynamic file, {String? name, Map headers = const {}, String disposition = 'attachment'}); - - /// Return the raw contents of a binary file. - /// - /// [file] is the file to be returned. - /// [headers] are the HTTP headers. - /// Returns a BinaryFileResponse object. - HttpResponse file(dynamic file, {Map headers = const {}}); - - /// Create a new redirect response to the given path. - /// - /// [path] is the path to redirect to. - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// [secure] indicates if the redirection should be secure. - /// Returns a RedirectResponse object. - HttpResponse redirectTo(String path, {int status = 302, Map headers = const {}, bool? secure}); - - /// Create a new redirect response to a named route. - /// - /// [route] is the name of the route. - /// [parameters] are the parameters for the route. - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// Returns a RedirectResponse object. - HttpResponse redirectToRoute(String route, {dynamic parameters = const {}, int status = 302, Map headers = const {}}); - - /// Create a new redirect response to a controller action. - /// - /// [action] is the action name. - /// [parameters] are the parameters for the action. - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// Returns a RedirectResponse object. - HttpResponse redirectToAction(dynamic action, {dynamic parameters = const {}, int status = 302, Map headers = const {}}); - - /// Create a new redirect response, while putting the current URL in the session. - /// - /// [path] is the path to redirect to. - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// [secure] indicates if the redirection should be secure. - /// Returns a RedirectResponse object. - HttpResponse redirectGuest(String path, {int status = 302, Map headers = const {}, bool? secure}); - - /// Create a new redirect response to the previously intended location. - /// - /// [defaultPath] is the default path if no intended location is found. - /// [status] is the HTTP status code. - /// [headers] are the HTTP headers. - /// [secure] indicates if the redirection should be secure. - /// Returns a RedirectResponse object. - HttpResponse redirectToIntended({String defaultPath = '/', int status = 302, Map headers = const {}, bool? secure}); -} diff --git a/packages/contracts/lib/src/routing/url_generator.dart b/packages/contracts/lib/src/routing/url_generator.dart deleted file mode 100644 index a3fb6e7..0000000 --- a/packages/contracts/lib/src/routing/url_generator.dart +++ /dev/null @@ -1,38 +0,0 @@ -abstract class UrlGenerator { - /// Get the current URL for the request. - String current(); - - /// Get the URL for the previous request. - String previous([dynamic fallback = false]); - - /// Generate an absolute URL to the given path. - String to(String path, [dynamic extra = const [], bool? secure]); - - /// Generate a secure, absolute URL to the given path. - String secure(String path, [Map parameters = const {}]); - - /// Generate the URL to an application asset. - String asset(String path, [bool? secure]); - - /// Get the URL to a named route. - /// - /// Throws [ArgumentError] if an invalid argument is provided. - String route(String name, [dynamic parameters = const [], bool absolute = true]); - - /// Create a signed route URL for a named route. - /// - /// Throws [ArgumentError] if an invalid argument is provided. - String signedRoute(String name, [dynamic parameters = const [], dynamic expiration, bool absolute = true]); - - /// Create a temporary signed route URL for a named route. - String temporarySignedRoute(String name, dynamic expiration, [Map parameters = const {}, bool absolute = true]); - - /// Get the URL to a controller action. - String action(dynamic action, [dynamic parameters = const [], bool absolute = true]); - - /// Get the root controller namespace. - String getRootControllerNamespace(); - - /// Set the root controller namespace. - UrlGenerator setRootControllerNamespace(String rootNamespace); -} diff --git a/packages/contracts/lib/src/routing/url_routable.dart b/packages/contracts/lib/src/routing/url_routable.dart deleted file mode 100644 index 2084412..0000000 --- a/packages/contracts/lib/src/routing/url_routable.dart +++ /dev/null @@ -1,31 +0,0 @@ -abstract class UrlRoutable { - /// Get the value of the model's route key. - /// - /// @return dynamic - dynamic getRouteKey(); - - /// Get the route key for the model. - /// - /// @return String - String getRouteKeyName(); - - /// Retrieve the model for a bound value. - /// - /// @param dynamic value - /// @param String? field - /// @return Model? - Model? resolveRouteBinding(dynamic value, [String? field]); - - /// Retrieve the child model for a bound value. - /// - /// @param String childType - /// @param dynamic value - /// @param String? field - /// @return Model? - Model? resolveChildRouteBinding(String childType, dynamic value, [String? field]); -} - -// TODO: Fix Imports -class Model { - // This class is a placeholder for the actual Eloquent model implementation. -} diff --git a/packages/contracts/lib/src/session/middleware/authenticates_sessions.dart b/packages/contracts/lib/src/session/middleware/authenticates_sessions.dart deleted file mode 100644 index 63d01ff..0000000 --- a/packages/contracts/lib/src/session/middleware/authenticates_sessions.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class AuthenticatesSessions { - // Add any methods or properties that are needed here -} diff --git a/packages/contracts/lib/src/session/session.dart b/packages/contracts/lib/src/session/session.dart deleted file mode 100644 index 7fbdc8d..0000000 --- a/packages/contracts/lib/src/session/session.dart +++ /dev/null @@ -1,88 +0,0 @@ -abstract class Session { - /// Get the name of the session. - String getName(); - - /// Set the name of the session. - void setName(String name); - - /// Get the current session ID. - String getId(); - - /// Set the session ID. - void setId(String id); - - /// Start the session, reading the data from a handler. - bool start(); - - /// Save the session data to storage. - void save(); - - /// Get all of the session data. - Map all(); - - /// Checks if a key exists. - bool exists(dynamic key); - - /// Checks if a key is present and not null. - bool has(dynamic key); - - /// Get an item from the session. - dynamic get(String key, [dynamic defaultValue]); - - /// Get the value of a given key and then forget it. - dynamic pull(String key, [dynamic defaultValue]); - - /// Put a key / value pair or array of key / value pairs in the session. - void put(dynamic key, [dynamic value]); - - /// Get the CSRF token value. - String token(); - - /// Regenerate the CSRF token value. - void regenerateToken(); - - /// Remove an item from the session, returning its value. - dynamic remove(String key); - - /// Remove one or many items from the session. - void forget(dynamic keys); - - /// Remove all of the items from the session. - void flush(); - - /// Flush the session data and regenerate the ID. - bool invalidate(); - - /// Generate a new session identifier. - bool regenerate([bool destroy = false]); - - /// Generate a new session ID for the session. - bool migrate([bool destroy = false]); - - /// Determine if the session has been started. - bool isStarted(); - - /// Get the previous URL from the session. - String? previousUrl(); - - /// Set the "previous" URL in the session. - void setPreviousUrl(String url); - - /// Get the session handler instance. - SessionHandlerInterface getHandler(); - - /// Determine if the session handler needs a request. - bool handlerNeedsRequest(); - - /// Set the request on the handler instance. - void setRequestOnHandler(Request request); -} - -// TODO: Fix Imports -abstract class SessionHandlerInterface { - // Define the necessary methods for SessionHandlerInterface -} - -class Request { - // Define the necessary methods and properties for Request -} diff --git a/packages/contracts/lib/src/support/arrayable.dart b/packages/contracts/lib/src/support/arrayable.dart deleted file mode 100644 index 0996ee9..0000000 --- a/packages/contracts/lib/src/support/arrayable.dart +++ /dev/null @@ -1,6 +0,0 @@ -abstract class Arrayable { - /// Get the instance as an array. - /// - /// @return Map - Map toArray(); -} diff --git a/packages/contracts/lib/src/support/can_be_escaped_when_cast_to_string.dart b/packages/contracts/lib/src/support/can_be_escaped_when_cast_to_string.dart deleted file mode 100644 index 8f7b9ee..0000000 --- a/packages/contracts/lib/src/support/can_be_escaped_when_cast_to_string.dart +++ /dev/null @@ -1,7 +0,0 @@ -abstract class CanBeEscapedWhenCastToString { - /// Indicate that the object's string representation should be escaped when toString is invoked. - /// - /// @param bool escape - /// @return this - CanBeEscapedWhenCastToString escapeWhenCastingToString(bool escape); -} diff --git a/packages/contracts/lib/src/support/deferrable_provider.dart b/packages/contracts/lib/src/support/deferrable_provider.dart deleted file mode 100644 index a95711e..0000000 --- a/packages/contracts/lib/src/support/deferrable_provider.dart +++ /dev/null @@ -1,6 +0,0 @@ -abstract class DeferrableProvider { - /// Get the services provided by the provider. - /// - /// @return List - List provides(); -} diff --git a/packages/contracts/lib/src/support/deferring_displayable_value.dart b/packages/contracts/lib/src/support/deferring_displayable_value.dart deleted file mode 100644 index 401a835..0000000 --- a/packages/contracts/lib/src/support/deferring_displayable_value.dart +++ /dev/null @@ -1,8 +0,0 @@ -//import 'package:your_package_name/htmlable.dart'; - -abstract class DeferringDisplayableValue { - /// Resolve the displayable value that the class is deferring. - /// - /// @return Htmlable or String - dynamic resolveDisplayableValue(); // Return type is dynamic to allow Htmlable or String -} diff --git a/packages/contracts/lib/src/support/htmlable.dart b/packages/contracts/lib/src/support/htmlable.dart deleted file mode 100644 index 5ba796b..0000000 --- a/packages/contracts/lib/src/support/htmlable.dart +++ /dev/null @@ -1,6 +0,0 @@ -abstract class Htmlable { - /// Get content as a string of HTML. - /// - /// @return String - String toHtml(); -} diff --git a/packages/contracts/lib/src/support/jsonable.dart b/packages/contracts/lib/src/support/jsonable.dart deleted file mode 100644 index 04d64cc..0000000 --- a/packages/contracts/lib/src/support/jsonable.dart +++ /dev/null @@ -1,7 +0,0 @@ -abstract class Jsonable { - /// Convert the object to its JSON representation. - /// - /// [options] Optional argument for JSON encoding options. - /// Returns the JSON representation of the object as a String. - String toJson({int options = 0}); -} diff --git a/packages/contracts/lib/src/support/message_bag.dart b/packages/contracts/lib/src/support/message_bag.dart deleted file mode 100644 index 3a8676e..0000000 --- a/packages/contracts/lib/src/support/message_bag.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'arrayable.dart'; -import 'countable.dart'; - -// TODO: Fix Imports. - -abstract class MessageBag implements Arrayable, Countable { - /// Get the keys present in the message bag. - List keys(); - - /// Add a message to the bag. - /// - /// Returns this instance for chaining. - MessageBag add(String key, String message); - - /// Merge a new array of messages into the bag. - /// - /// Returns this instance for chaining. - MessageBag merge(dynamic messages); - - /// Determine if messages exist for a given key. - bool has(dynamic key); - - /// Get the first message from the bag for a given key. - String first([String? key, String? format]); - - /// Get all of the messages from the bag for a given key. - List get(String key, [String? format]); - - /// Get all of the messages for every key in the bag. - List all([String? format]); - - /// Remove a message from the bag. - /// - /// Returns this instance for chaining. - MessageBag forget(String key); - - /// Get the raw messages in the container. - List getMessages(); - - /// Get the default message format. - String getFormat(); - - /// Set the default message format. - /// - /// Returns this instance for chaining. - MessageBag setFormat([String format = ':message']); - - /// Determine if the message bag has any messages. - bool isEmpty(); - - /// Determine if the message bag has any messages. - bool isNotEmpty(); -} diff --git a/packages/contracts/lib/src/support/message_provider.dart b/packages/contracts/lib/src/support/message_provider.dart deleted file mode 100644 index 5ea9379..0000000 --- a/packages/contracts/lib/src/support/message_provider.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'message_bag.dart'; - -abstract class MessageProvider { - /// Get the messages for the instance. - /// - /// @return MessageBag - MessageBag getMessageBag(); -} diff --git a/packages/contracts/lib/src/support/renderable.dart b/packages/contracts/lib/src/support/renderable.dart deleted file mode 100644 index ed95264..0000000 --- a/packages/contracts/lib/src/support/renderable.dart +++ /dev/null @@ -1,6 +0,0 @@ -abstract class Renderable { - /// Get the evaluated contents of the object. - /// - /// Returns a string representation of the contents. - String render(); -} diff --git a/packages/contracts/lib/src/support/responsable.dart b/packages/contracts/lib/src/support/responsable.dart deleted file mode 100644 index 7fb5bf3..0000000 --- a/packages/contracts/lib/src/support/responsable.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:symfony_http_foundation/response.dart'; -import 'request.dart'; - -// TODO: Fix Imports. -abstract class Responsable { - /// Create an HTTP response that represents the object. - /// - /// @param Request request - /// @return Response - Response toResponse(Request request); -} diff --git a/packages/contracts/lib/src/support/validate_data.dart b/packages/contracts/lib/src/support/validate_data.dart deleted file mode 100644 index 1e62af3..0000000 --- a/packages/contracts/lib/src/support/validate_data.dart +++ /dev/null @@ -1,7 +0,0 @@ -//import 'dart:collection'; -import 'arrayable.dart'; - -abstract class ValidatedData implements Arrayable, Map { - @override - Iterator> get iterator => entries.iterator; -} diff --git a/packages/contracts/lib/src/translation/has_local_preferences.dart b/packages/contracts/lib/src/translation/has_local_preferences.dart deleted file mode 100644 index 6a1b236..0000000 --- a/packages/contracts/lib/src/translation/has_local_preferences.dart +++ /dev/null @@ -1,6 +0,0 @@ -abstract class HasLocalePreference { - /// Get the preferred locale of the entity. - /// - /// Returns a [String] representing the preferred locale or null if none is set. - String? preferredLocale(); -} diff --git a/packages/contracts/lib/src/translation/loader.dart b/packages/contracts/lib/src/translation/loader.dart deleted file mode 100644 index b942d84..0000000 --- a/packages/contracts/lib/src/translation/loader.dart +++ /dev/null @@ -1,25 +0,0 @@ -abstract class Loader { - /// Load the messages for the given locale. - /// - /// [locale] is the locale to load messages for. - /// [group] is the message group to load. - /// [namespace] is the optional namespace to load messages from. - /// Returns a list of messages. - List load(String locale, String group, [String? namespace]); - - /// Add a new namespace to the loader. - /// - /// [namespace] is the name of the namespace. - /// [hint] is the path hint for the namespace. - void addNamespace(String namespace, String hint); - - /// Add a new JSON path to the loader. - /// - /// [path] is the path to the JSON file. - void addJsonPath(String path); - - /// Get an array of all the registered namespaces. - /// - /// Returns a map of all registered namespaces and their hints. - Map namespaces(); -} diff --git a/packages/contracts/lib/src/translation/translator.dart b/packages/contracts/lib/src/translation/translator.dart deleted file mode 100644 index db0869b..0000000 --- a/packages/contracts/lib/src/translation/translator.dart +++ /dev/null @@ -1,29 +0,0 @@ -abstract class Translator { - /// Get the translation for a given key. - /// - /// @param String key - /// @param Map replace - /// @param String? locale - /// @return dynamic - dynamic get(String key, {Map replace = const {}, String? locale}); - - /// Get a translation according to an integer value. - /// - /// @param String key - /// @param dynamic number (Countable, int, double, or List) - /// @param Map replace - /// @param String? locale - /// @return String - String choice(String key, dynamic number, {Map replace = const {}, String? locale}); - - /// Get the default locale being used. - /// - /// @return String - String getLocale(); - - /// Set the default locale. - /// - /// @param String locale - /// @return void - void setLocale(String locale); -} diff --git a/packages/contracts/lib/src/validation/data_aware_rule.dart b/packages/contracts/lib/src/validation/data_aware_rule.dart deleted file mode 100644 index db29bb1..0000000 --- a/packages/contracts/lib/src/validation/data_aware_rule.dart +++ /dev/null @@ -1,7 +0,0 @@ -abstract class DataAwareRule { - /// Sets the data under validation. - /// - /// @param Map data - The data to be validated. - /// @return DataAwareRule - The instance of the implementing class. - DataAwareRule setData(Map data); -} diff --git a/packages/contracts/lib/src/validation/factory.dart b/packages/contracts/lib/src/validation/factory.dart deleted file mode 100644 index 1ede50a..0000000 --- a/packages/contracts/lib/src/validation/factory.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'validator.dart'; -abstract class Factory { - /// Create a new Validator instance. - /// - /// @param Map data - /// @param Map rules - /// @param Map messages - /// @param Map attributes - /// @return Validator - Validator make( - Map data, - Map rules, - [Map messages = const {}, - Map attributes = const {}]); - - /// Register a custom validator extension. - /// - /// @param String rule - /// @param Function|string extension - /// @param String|null message - /// @return void - void extend(String rule, dynamic extension, [String? message]); - - /// Register a custom implicit validator extension. - /// - /// @param String rule - /// @param Function|string extension - /// @param String|null message - /// @return void - void extendImplicit(String rule, dynamic extension, [String? message]); - - /// Register a custom implicit validator message replacer. - /// - /// @param String rule - /// @param Function|string replacer - /// @return void - void replacer(String rule, dynamic replacer); -} diff --git a/packages/contracts/lib/src/validation/implicit_rule.dart b/packages/contracts/lib/src/validation/implicit_rule.dart deleted file mode 100644 index 38cbc1b..0000000 --- a/packages/contracts/lib/src/validation/implicit_rule.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Import the necessary file where the Rule interface is defined -import 'rule.dart'; - -/// @deprecated see ValidationRule -abstract class ImplicitRule implements Rule { - // Empty abstract class to follow the structure of the original interface -} diff --git a/packages/contracts/lib/src/validation/invokable_rule.dart b/packages/contracts/lib/src/validation/invokable_rule.dart deleted file mode 100644 index 6935fc1..0000000 --- a/packages/contracts/lib/src/validation/invokable_rule.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Import necessary libraries -import 'dart:core'; - -// Define a type alias for the fail function closure -typedef FailFunction = void Function(String); - -// Define the InvokableRule interface -///@deprecated see ValidateRule -abstract class InvokableRule { - /// Run the validation rule. - /// - /// @param attribute The attribute being validated. - /// @param value The value of the attribute. - /// @param fail A function that will be called if the validation fails. - void call(String attribute, dynamic value, FailFunction fail); -} diff --git a/packages/contracts/lib/src/validation/rule.dart b/packages/contracts/lib/src/validation/rule.dart deleted file mode 100644 index d3fbcff..0000000 --- a/packages/contracts/lib/src/validation/rule.dart +++ /dev/null @@ -1,14 +0,0 @@ -/// @deprecated see ValidationRule -abstract class Rule { - /// Determine if the validation rule passes. - /// - /// @param attribute The name of the attribute. - /// @param value The value of the attribute. - /// @return True if the validation rule passes, false otherwise. - bool passes(String attribute, dynamic value); - - /// Get the validation error message. - /// - /// @return The validation error message as a string or list of strings. - dynamic message(); -} diff --git a/packages/contracts/lib/src/validation/uncompromised_verifier.dart b/packages/contracts/lib/src/validation/uncompromised_verifier.dart deleted file mode 100644 index 826fb78..0000000 --- a/packages/contracts/lib/src/validation/uncompromised_verifier.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:meta/meta.dart'; - -abstract class UncompromisedVerifier { - /// Verify that the given data has not been compromised in data leaks. - /// - /// @param List data - /// @return bool - bool verify(List data); -} diff --git a/packages/contracts/lib/src/validation/validates_when_resolved.dart b/packages/contracts/lib/src/validation/validates_when_resolved.dart deleted file mode 100644 index 624e90c..0000000 --- a/packages/contracts/lib/src/validation/validates_when_resolved.dart +++ /dev/null @@ -1,6 +0,0 @@ -abstract class ValidatesWhenResolved { - /// Validate the given class instance. - /// - /// This method should be overridden to implement the validation logic. - void validateResolved(); -} diff --git a/packages/contracts/lib/src/validation/validation_rule.dart b/packages/contracts/lib/src/validation/validation_rule.dart deleted file mode 100644 index 5c3e923..0000000 --- a/packages/contracts/lib/src/validation/validation_rule.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:meta/meta.dart'; - -typedef FailCallback = void Function(String message); - -abstract class ValidationRule { - /// Run the validation rule. - /// - /// @param attribute The name of the attribute being validated. - /// @param value The value of the attribute. - /// @param fail A callback function that accepts a failure message. - void validate(String attribute, dynamic value, FailCallback fail); -} diff --git a/packages/contracts/lib/src/validation/validator.dart b/packages/contracts/lib/src/validation/validator.dart deleted file mode 100644 index e373783..0000000 --- a/packages/contracts/lib/src/validation/validator.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'message_provider.dart'; -import 'validation_exception.dart'; -import 'message_bag.dart'; - -// TODO: Fix Imports. - -abstract class Validator implements MessageProvider { - /// Run the validator's rules against its data. - /// - /// Throws a [ValidationException] if validation fails. - /// - /// Returns a map of validated data. - Map validate(); - - /// Get the attributes and values that were validated. - /// - /// Throws a [ValidationException] if validation fails. - /// - /// Returns a map of validated data. - Map validated(); - - /// Determine if the data fails the validation rules. - /// - /// Returns true if validation fails, false otherwise. - bool fails(); - - /// Get the failed validation rules. - /// - /// Returns a map of failed validation rules. - Map failed(); - - /// Add conditions to a given field based on a callback. - /// - /// Takes an [attribute], [rules], and a [callback] function. - /// - /// Returns the current instance of [Validator]. - Validator sometimes(dynamic attribute, dynamic rules, Function callback); - - /// Add an after validation callback. - /// - /// Takes a [callback] function. - /// - /// Returns the current instance of [Validator]. - Validator after(Function callback); - - /// Get all of the validation error messages. - /// - /// Returns a [MessageBag] containing the error messages. - MessageBag errors(); -} diff --git a/packages/contracts/lib/src/validation/validator_aware_rule.dart b/packages/contracts/lib/src/validation/validator_aware_rule.dart deleted file mode 100644 index c30aab9..0000000 --- a/packages/contracts/lib/src/validation/validator_aware_rule.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'validator.dart'; // Assume this is the correct import for the Validator class - -abstract class ValidatorAwareRule { - /// Set the current validator. - /// - /// @param Validator validator - /// @return ValidatorAwareRule - ValidatorAwareRule setValidator(Validator validator); -} diff --git a/packages/contracts/lib/src/view/engine.dart b/packages/contracts/lib/src/view/engine.dart deleted file mode 100644 index f701dad..0000000 --- a/packages/contracts/lib/src/view/engine.dart +++ /dev/null @@ -1,8 +0,0 @@ -abstract class Engine { - /// Get the evaluated contents of the view. - /// - /// @param String path - /// @param Map data - /// @return String - String get(String path, {Map data = const {}}); -} diff --git a/packages/contracts/lib/src/view/factory.dart b/packages/contracts/lib/src/view/factory.dart deleted file mode 100644 index aa1e558..0000000 --- a/packages/contracts/lib/src/view/factory.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'view.dart'; - -abstract class Factory { - /// Determine if a given view exists. - /// - /// @param String view - /// @return bool - bool exists(String view); - - /// Get the evaluated view contents for the given path. - /// - /// @param String path - /// @param Map data - /// @param Map mergeData - /// @return View - View file(String path, {Map? data, Map? mergeData}); - - /// Get the evaluated view contents for the given view. - /// - /// @param String view - /// @param Map data - /// @param Map mergeData - /// @return View - View make(String view, {Map? data, Map? mergeData}); - - /// Add a piece of shared data to the environment. - /// - /// @param dynamic key - /// @param dynamic value - /// @return dynamic - dynamic share(dynamic key, {dynamic value}); - - /// Register a view composer event. - /// - /// @param dynamic views - /// @param dynamic callback - /// @return List - List composer(dynamic views, dynamic callback); - - /// Register a view creator event. - /// - /// @param dynamic views - /// @param dynamic callback - /// @return List - List creator(dynamic views, dynamic callback); - - /// Add a new namespace to the loader. - /// - /// @param String namespace - /// @param dynamic hints - /// @return Factory - Factory addNamespace(String namespace, dynamic hints); - - /// Replace the namespace hints for the given namespace. - /// - /// @param String namespace - /// @param dynamic hints - /// @return Factory - Factory replaceNamespace(String namespace, dynamic hints); -} diff --git a/packages/contracts/lib/src/view/view.dart b/packages/contracts/lib/src/view/view.dart deleted file mode 100644 index 2b644ab..0000000 --- a/packages/contracts/lib/src/view/view.dart +++ /dev/null @@ -1,17 +0,0 @@ - -import "package:protevus_contracts/support.dart"; - -abstract class View extends Renderable { - /// Get the name of the view. - String name(); - - /// Add a piece of data to the view. - /// - /// @param String|Map key - /// @param dynamic value - /// @return View - View with(dynamic key, [dynamic value]); - - /// Get the array of view data. - Map getData(); -} diff --git a/packages/contracts/lib/src/view/view_compilation_exception.dart b/packages/contracts/lib/src/view/view_compilation_exception.dart deleted file mode 100644 index 9257301..0000000 --- a/packages/contracts/lib/src/view/view_compilation_exception.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:meta/meta.dart'; - -class ViewCompilationException implements Exception { - final String? message; - - ViewCompilationException([this.message]); - - @override - String toString() { - return message ?? 'ViewCompilationException'; - } -} diff --git a/packages/contracts/lib/support.dart b/packages/contracts/lib/support.dart deleted file mode 100644 index d450f3b..0000000 --- a/packages/contracts/lib/support.dart +++ /dev/null @@ -1,17 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Support Contracts -export 'src/support/arrayable.dart'; -export 'src/support/can_be_escaped_when_cast_to_string.dart'; -export 'src/support/deferrable_provider.dart'; -export 'src/support/deferring_displayable_value.dart'; -export 'src/support/htmlable.dart'; -export 'src/support/jsonable.dart'; -export 'src/support/message_bag.dart'; -export 'src/support/message_provider.dart'; -export 'src/support/renderable.dart'; -export 'src/support/responsable.dart'; -export 'src/support/validate_data.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/translation.dart b/packages/contracts/lib/translation.dart deleted file mode 100644 index 9e4b8c6..0000000 --- a/packages/contracts/lib/translation.dart +++ /dev/null @@ -1,9 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Translation Contracts -export 'src/translation/has_local_preferences.dart'; -export 'src/translation/loader.dart'; -export 'src/translation/translator.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/validation.dart b/packages/contracts/lib/validation.dart deleted file mode 100644 index 5ccfed8..0000000 --- a/packages/contracts/lib/validation.dart +++ /dev/null @@ -1,16 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// Validation Contracts -export 'src/validation/data_aware_rule.dart'; -export 'src/validation/factory.dart'; -export 'src/validation/implicit_rule.dart'; -export 'src/validation/invokable_rule.dart'; -export 'src/validation/rule.dart'; -export 'src/validation/uncompromised_verifier.dart'; -export 'src/validation/validates_when_resolved.dart'; -export 'src/validation/validation_rule.dart'; -export 'src/validation/validator.dart'; -export 'src/validation/validator_aware_rule.dart'; \ No newline at end of file diff --git a/packages/contracts/lib/view.dart b/packages/contracts/lib/view.dart deleted file mode 100644 index dd9c5fa..0000000 --- a/packages/contracts/lib/view.dart +++ /dev/null @@ -1,10 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -// View Contracts -export 'src/view/engine.dart'; -export 'src/view/factory.dart'; -export 'src/view/view.dart'; -export 'src/view/view_compilation_exception.dart'; \ No newline at end of file diff --git a/packages/http/lib/foundation.dart b/packages/http/lib/foundation.dart deleted file mode 100644 index 193266d..0000000 --- a/packages/http/lib/foundation.dart +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/// This library exports various foundation classes and utilities for web-related operations. -/// -/// Exports: -/// - [CountableInterface] from 'src/foundation/countable_interface.dart' -/// - [StringableInterface] from 'src/foundation/stringable_interface.dart' -/// - [AcceptHeaderItem] from 'src/foundation/accept_header_item.dart' -/// - [AcceptHeader] from 'src/foundation/accept_header.dart' -/// - [Filter] from 'src/foundation/filter.dart' -/// - [Cookie] from 'src/foundation/cookie.dart' -/// - [HeaderUtils] from 'src/foundation/header_utils.dart' -/// - [HeaderBag] from 'src/foundation/header_bag.dart' -/// - [ParameterBagBase] from 'src/foundation/parameter_bag_base.dart' -/// - [ParameterBag] from 'src/foundation/parameter_bag.dart' -/// - [InputBag] from 'src/foundation/input_bag.dart' -/// - [ResponseHeaderBag] from 'src/foundation/response_header_bag.dart' -/// - [ServerBag] from 'src/foundation/server_bag.dart' -/// -/// These exports provide a comprehensive set of tools for handling various aspects of web development, -/// including countable objects, string manipulation, HTTP headers, filtering, cookies, request parameters, -/// input handling, response headers, and server-related functionality. -library; - -export 'src/foundation/countable_interface.dart'; -export 'src/foundation/stringable_interface.dart'; -export 'src/foundation/accept_header_item.dart'; -export 'src/foundation/accept_header.dart'; -export 'src/foundation/filter.dart'; -export 'src/foundation/cookie.dart'; -export 'src/foundation/header_utils.dart'; -export 'src/foundation/header_bag.dart'; -export 'src/foundation/parameter_bag_base.dart'; -export 'src/foundation/parameter_bag.dart'; -export 'src/foundation/input_bag.dart'; -export 'src/foundation/response_header_bag.dart'; -export 'src/foundation/server_bag.dart'; diff --git a/packages/http/lib/foundation_exception.dart b/packages/http/lib/foundation_exception.dart deleted file mode 100644 index aa34626..0000000 --- a/packages/http/lib/foundation_exception.dart +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/// This library exports various exception classes and interfaces. -/// -/// The exported classes include: -/// - `BadRequestException`: Used for handling bad HTTP requests. -/// - `RequestExceptionInterface`: An interface for request-related exceptions. -/// - `UnexpectedValueException`: Used when an unexpected value is encountered. -/// -/// These exports allow other parts of the application to use these -/// exception classes and interfaces without needing to import them directly. -library; - -export 'src/foundation/exception/bad_request_exception.dart'; -export 'src/foundation/exception/request_exception_interface.dart'; -export 'src/foundation/exception/unexpected_value_exception.dart'; \ No newline at end of file diff --git a/packages/http/lib/foundation_file.dart b/packages/http/lib/foundation_file.dart deleted file mode 100644 index 43a7c7e..0000000 --- a/packages/http/lib/foundation_file.dart +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -library; - -export "src/foundation/file/file.dart"; -export 'src/foundation/file/upload_file.dart'; diff --git a/packages/http/lib/foundation_file_exception.dart b/packages/http/lib/foundation_file_exception.dart deleted file mode 100644 index d473df1..0000000 --- a/packages/http/lib/foundation_file_exception.dart +++ /dev/null @@ -1,20 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -library; - -export 'src/foundation/file/exception/file_exception.dart'; -export 'src/foundation/file/exception/cannot_write_file_exception.dart'; -export 'src/foundation/file/exception/extension_file_exception.dart'; -export 'src/foundation/file/exception/file_not_found_exception.dart'; -export 'src/foundation/file/exception/form_size_file_exception.dart'; -export 'src/foundation/file/exception/ini_size_file_exception.dart'; -export 'src/foundation/file/exception/no_file_exception.dart'; -export 'src/foundation/file/exception/no_tmp_dir_file_exception.dart'; -export 'src/foundation/file/exception/partial_file_exception.dart'; diff --git a/packages/http/lib/foundation_session.dart b/packages/http/lib/foundation_session.dart deleted file mode 100644 index 069793e..0000000 --- a/packages/http/lib/foundation_session.dart +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -library; - -export 'src/foundation/session/session_bag_interface.dart'; -export 'src/foundation/session/session_interface.dart'; diff --git a/packages/http/lib/foundation_storage.dart b/packages/http/lib/foundation_storage.dart deleted file mode 100644 index dda4f18..0000000 --- a/packages/http/lib/foundation_storage.dart +++ /dev/null @@ -1,12 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -library; - -export 'src/foundation/storage/meta_data_bag.dart'; diff --git a/packages/mime/test/.gitkeep b/packages/http/lib/src/.gitkeep similarity index 100% rename from packages/mime/test/.gitkeep rename to packages/http/lib/src/.gitkeep diff --git a/packages/http/lib/src/foundation/accept_header.dart b/packages/http/lib/src/foundation/accept_header.dart deleted file mode 100644 index 34818ce..0000000 --- a/packages/http/lib/src/foundation/accept_header.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'package:protevus_http/foundation.dart'; - -/// Represents an Accept-* header. -/// -/// An accept header is compound with a list of items, -/// sorted by descending quality. -class AcceptHeader { - /// The list of AcceptHeaderItem objects. - final Map _items = {}; - - /// Indicates whether the items are sorted. - bool _sorted = true; - - /// Constructs an AcceptHeader with the given items. - AcceptHeader(List items) { - for (var item in items) { - add(item); - } - } - - /// Builds an AcceptHeader instance from a string. - static AcceptHeader fromString(String? headerValue) { - var parts = HeaderUtils.split(headerValue ?? '', ',;='); - var index = 0; - - return AcceptHeader(parts.map((subParts) { - var part = subParts.isNotEmpty ? subParts[0] : ''; - - // Convert subParts.sublist(1) to List> - var restParts = subParts.sublist(1).map((item) => [item]).toList(); - var attributes = HeaderUtils.combine(restParts); - - var item = AcceptHeaderItem( - part, - Map.from( - attributes.map((key, value) => MapEntry(key, value.toString()))), - ); - item.setIndex(index++); - return item; - }).toList()); - } - - /// Returns header value's string representation. - @override - String toString() { - return _items.values.join(','); - } - - /// Tests if header has given value. - bool has(String value) { - return _items.containsKey(value); - } - - /// Returns given value's item, if exists. - AcceptHeaderItem? get(String value) { - return _items[value] ?? - _items['${value.split('/')[0]}/*'] ?? - _items['*/*'] ?? - _items['*']; - } - - /// Adds an item. - AcceptHeader add(AcceptHeaderItem item) { - _items[item.getValue()] = item; - _sorted = false; - return this; - } - - /// Returns all items. - List all() { - _sort(); - return _items.values.toList(); - } - - /// Filters items on their value using given regex. - AcceptHeader filter(String pattern) { - var regex = RegExp(pattern); - return AcceptHeader(_items.values - .where((item) => regex.hasMatch(item.getValue())) - .toList()); - } - - /// Returns first item. - AcceptHeaderItem? first() { - _sort(); - return _items.isNotEmpty ? _items.values.first : null; - } - - /// Sorts items by descending quality. - void _sort() { - if (!_sorted) { - var sortedItems = _items.values.toList() - ..sort((a, b) { - var qA = a.getQuality(); - var qB = b.getQuality(); - - if (qA == qB) { - return a.getIndex().compareTo(b.getIndex()); - } - - return qB.compareTo(qA); - }); - - _items.clear(); - for (var item in sortedItems) { - _items[item.getValue()] = item; - } - - _sorted = true; - } - } -} diff --git a/packages/http/lib/src/foundation/accept_header_item.dart b/packages/http/lib/src/foundation/accept_header_item.dart deleted file mode 100644 index 5032813..0000000 --- a/packages/http/lib/src/foundation/accept_header_item.dart +++ /dev/null @@ -1,93 +0,0 @@ -import 'package:protevus_http/foundation.dart'; - -/// Represents an Accept-* header item. -class AcceptHeaderItem { - String _value; - double _quality = 1.0; - int _index = 0; - final Map _attributes = {}; - - /// Constructs an AcceptHeaderItem with a value and optional attributes. - AcceptHeaderItem(this._value, [Map? attributes]) { - if (attributes != null) { - attributes.forEach((name, value) { - setAttribute(name, value); - }); - } - } - - /// Builds an AcceptHeaderItem instance from a string. - static AcceptHeaderItem fromString(String? itemValue) { - final parts = HeaderUtils.split(itemValue ?? '', ';='); - - if (parts.isEmpty) { - throw ArgumentError('Invalid header value'); - } - - final value = parts[0][0]; - final attributes = HeaderUtils.combine(parts.sublist(1)); - - return AcceptHeaderItem(value, attributes.cast()); - } - - /// Returns header value's string representation. - @override - String toString() { - final attributes = Map.from(_attributes); - if (_quality < 1) { - attributes['q'] = _quality.toString(); - } - return _value + - (attributes.isNotEmpty - ? '; ${HeaderUtils.headerToString(attributes, ';')}' - : ''); - } - - /// Set the item value. - AcceptHeaderItem setValue(String value) { - _value = value; - return this; - } - - /// Returns the item value. - String getValue() => _value; - - /// Set the item quality. - AcceptHeaderItem setQuality(double quality) { - _quality = quality; - return this; - } - - /// Returns the item quality. - double getQuality() => _quality; - - /// Set the item index. - AcceptHeaderItem setIndex(int index) { - _index = index; - return this; - } - - /// Returns the item index. - int getIndex() => _index; - - /// Tests if an attribute exists. - bool hasAttribute(String name) => _attributes.containsKey(name); - - /// Returns an attribute by its name. - dynamic getAttribute(String name, {dynamic defaultValue}) { - return _attributes[name] ?? defaultValue; - } - - /// Returns all attributes. - Map getAttributes() => Map.from(_attributes); - - /// Set an attribute. - AcceptHeaderItem setAttribute(String name, String value) { - if (name == 'q') { - _quality = double.parse(value); - } else { - _attributes[name] = value; - } - return this; - } -} diff --git a/packages/http/lib/src/foundation/cookie.dart b/packages/http/lib/src/foundation/cookie.dart deleted file mode 100644 index 3a53a7d..0000000 --- a/packages/http/lib/src/foundation/cookie.dart +++ /dev/null @@ -1,733 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the symfony Cookie.php class to Dart - * - * (C) Protevus - * (C) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'dart:math'; -import 'package:protevus_http/foundation.dart'; - -/// Represents an HTTP cookie. -/// -/// This class encapsulates all the attributes and behaviors of an HTTP cookie, -/// including its name, value, expiration, path, domain, security settings, -/// and other properties like SameSite and Partitioned. -/// -/// It provides methods to create, modify, and inspect cookie properties, -/// as well as to convert cookies to their string representation for use -/// in HTTP headers. -/// -/// The Cookie class supports various cookie attributes and security features, -/// allowing for fine-grained control over cookie behavior in web applications. -class Cookie { - -/// Constant representing the 'None' value for the SameSite cookie attribute. -/// -/// When set to 'none', the cookie will be sent with all cross-site requests, -/// including both cross-site reading and cross-site writing. This setting -/// requires the 'Secure' flag to be set in modern browsers. -/// -/// Note: Using 'none' may have security implications and should be used -/// carefully, as it allows the cookie to be sent in all contexts. - static const String SAMESITE_NONE = 'none'; - -/// Constant representing the 'Lax' value for the SameSite cookie attribute. -/// -/// When set to 'lax', the cookie will be sent with top-level navigations and -/// will be sent along with GET requests initiated by third party websites. -/// This is less restrictive than 'Strict' but provides some protection against -/// CSRF attacks while allowing the cookie to be sent in more scenarios. -/// -/// This is often used as a balance between security and functionality. - static const String SAMESITE_LAX = 'lax'; - -/// Constant representing the 'Strict' value for the SameSite cookie attribute. -/// -/// When set to 'strict', the cookie will only be sent for same-site requests. -/// This is the most restrictive setting and provides the highest level of protection -/// against cross-site request forgery (CSRF) attacks. -/// -/// With this setting, the cookie will not be sent with any cross-site requests, -/// including when a user follows a link from an external site. This can enhance -/// security but may impact functionality in some cases where cross-site cookie -/// access is required. - static const String SAMESITE_STRICT = 'strict'; - -/// The name of the cookie. -/// -/// This property represents the name of the cookie, which is used to identify -/// the cookie when it's sent between the server and the client. The name is -/// a required field for any cookie and must be set when the cookie is created. -/// -/// The 'late' keyword indicates that this property will be initialized before -/// it's used, but not necessarily at the point of declaration. - late String name; - -/// The value of the cookie. -/// -/// This property represents the actual data stored in the cookie. It can be null -/// if the cookie is used for deletion (setting an expired cookie) or if it's a -/// flag-type cookie where the presence of the cookie itself is meaningful. -/// -/// The value is typically a string, but it's declared as nullable (String?) to -/// allow for cases where a cookie might be set without a value or to represent -/// a not-yet-initialized state. - String? value; - -/// The domain that the cookie is available to. -/// -/// This property represents the domain attribute of the cookie. When set, it specifies -/// which hosts are allowed to receive the cookie. It's important for controlling -/// the scope of the cookie, especially in scenarios involving subdomains. -/// -/// If null, the cookie will only be sent to the host that set the cookie. -/// -/// Note: The domain must be a valid domain string. Setting this incorrectly can -/// lead to security vulnerabilities or the cookie not being sent as expected. - String? domain; - -/// The expiration time of the cookie. -/// -/// This property represents the time at which the cookie should expire, stored as a Unix timestamp -/// (seconds since the Unix epoch). When this time is reached, the cookie is considered expired -/// and should be discarded by the client. -/// -/// The 'late' keyword indicates that this property will be initialized before it's used, -/// but not necessarily at the point of declaration. This allows for flexible initialization -/// patterns, such as setting the expiration time in a constructor or method after the object -/// is created. -/// -/// A value of 0 typically indicates that the cookie does not have a specific expiration time -/// and should be treated as a session cookie (expires when the browsing session ends). - late int expire; - -/// The path on the server where the cookie will be available. -/// -/// This property represents the path attribute of the cookie. It specifies the -/// subset of URLs in a domain for which the cookie is valid. When a cookie has a -/// path set, it will only be sent to the server for requests to that path and -/// its subdirectories. -/// -/// The 'late' keyword indicates that this property will be initialized before -/// it's used, but not necessarily at the point of declaration. Typically, it's -/// set in the constructor or a method that initializes the cookie. -/// -/// If not explicitly set, the default path is usually '/'. - late String path; - -/// Indicates whether the cookie should only be transmitted over a secure HTTPS connection. -/// -/// This property is nullable: -/// - If set to true, the cookie will only be sent over secure connections. -/// - If set to false, the cookie can be sent over any connection. -/// - If null, the default secure setting (secureDefault) will be used. -/// -/// The actual security behavior is determined by the [isSecure] method, -/// which considers both this property and the [secureDefault] value. - bool? secure; - -/// Indicates whether the cookie should be accessible only through the HTTP protocol. -/// -/// When set to true, the cookie is not accessible to client-side scripts (such as JavaScript), -/// which helps mitigate cross-site scripting (XSS) attacks. -/// -/// The 'late' keyword indicates that this property will be initialized before it's used, -/// but not necessarily at the point of declaration. - late bool httpOnly; - -/// Indicates whether the cookie should be sent with no URL encoding. -/// -/// When set to true, the cookie name and value will not be URL-encoded when the cookie -/// is converted to a string representation. This can be useful in situations where -/// the cookie value contains characters that don't need to be encoded or when working -/// with systems that expect raw cookie values. -/// -/// The 'late' keyword indicates that this property will be initialized before it's used, -/// but not necessarily at the point of declaration. - late bool raw; - -/// The SameSite attribute of the cookie. -/// -/// This property represents the SameSite attribute for the cookie, which controls how the cookie is sent with cross-site requests. -/// It can have one of three values: -/// - 'strict': The cookie is only sent for same-site requests. -/// - 'lax': The cookie is sent for same-site requests and top-level navigation from external sites. -/// - 'none': The cookie is sent for all cross-site requests. -/// - null: If the SameSite attribute is not set. -/// -/// The SameSite attribute helps protect against cross-site request forgery (CSRF) attacks. - String? sameSite; - -/// Indicates whether the cookie should be tied to the top-level site in cross-site context. -/// -/// When set to true, the cookie will be partitioned, meaning it will be associated with -/// the top-level site in cross-site contexts. This can enhance privacy and security by -/// preventing tracking across different sites. -/// -/// The 'late' keyword indicates that this property will be initialized before it's used, -/// but not necessarily at the point of declaration. - late bool partitioned; - -/// Indicates the default value for the "secure" flag when it's not explicitly set. -/// -/// This property determines whether cookies should be marked as secure by default -/// when the [secure] property is null. If set to true, cookies will be treated -/// as secure unless explicitly set otherwise. -/// -/// The 'late' keyword indicates that this property will be initialized before -/// it's used, but not necessarily at the point of declaration. - late bool secureDefault; - -/// A string containing characters that are reserved and cannot be used in cookie names. -/// -/// This constant defines a list of characters that are considered reserved in the context of cookies. -/// These characters have special meanings in cookie syntax and therefore cannot be used directly -/// in cookie names, especially when the 'raw' flag is set to true. -/// -/// The reserved characters are: -/// - '=': Used to separate cookie name and value -/// - ',': Used to separate multiple cookies -/// - ';': Used to separate cookie attributes -/// - ' ': Space character -/// - '\t': Tab character -/// - '\r': Carriage return -/// - '\n': Line feed -/// - '\v': Vertical tab -/// - '\f': Form feed -/// -/// This constant is used in validation checks to ensure cookie names do not contain these characters -/// when creating or manipulating cookies with the 'raw' option enabled. - static const String RESERVED_CHARS_LIST = "=,; \t\r\n\v\f"; - -/// A list of reserved characters in their original form. -/// -/// This constant defines a list of characters that are considered reserved in the context of cookies. -/// These characters have special meanings in cookie syntax and therefore need to be encoded -/// when used in cookie names or values. -/// -/// The reserved characters are: -/// - '=': Used to separate cookie name and value -/// - ',': Used to separate multiple cookies -/// - ';': Used to separate cookie attributes -/// - ' ': Space character -/// - '\t': Tab character -/// - '\r': Carriage return -/// - '\n': Line feed -/// - '\v': Vertical tab -/// - '\f': Form feed -/// -/// This list is typically used in conjunction with RESERVED_CHARS_TO for encoding/decoding -/// cookie names and values to ensure proper handling of these special characters. - static const List RESERVED_CHARS_FROM = ['=', ',', ';', ' ', "\t", "\r", "\n", "\v", "\f"]; - -/// A list of URL-encoded representations of reserved characters. -/// -/// This constant defines a list of URL-encoded versions of characters that are considered -/// reserved in the context of cookies. These encoded versions correspond to the characters -/// in RESERVED_CHARS_FROM. -/// -/// The encoded characters are: -/// - '%3D': Encoded form of '=' (equals sign) -/// - '%2C': Encoded form of ',' (comma) -/// - '%3B': Encoded form of ';' (semicolon) -/// - '%20': Encoded form of ' ' (space) -/// - '%09': Encoded form of '\t' (tab) -/// - '%0D': Encoded form of '\r' (carriage return) -/// - '%0A': Encoded form of '\n' (line feed) -/// - '%0B': Encoded form of '\v' (vertical tab) -/// - '%0C': Encoded form of '\f' (form feed) -/// -/// This list is typically used in conjunction with RESERVED_CHARS_FROM for encoding/decoding -/// cookie names and values to ensure proper handling of these special characters. - static const List RESERVED_CHARS_TO = ['%3D', '%2C', '%3B', '%20', '%09', '%0D', '%0A', '%0B', '%0C']; - -/// Creates a Cookie object from a string representation of a cookie. -/// -/// This static method parses a cookie string and creates a corresponding Cookie object. -/// -/// Parameters: -/// - [cookie]: A string representation of the cookie. -/// - [decode]: A boolean flag indicating whether to decode the cookie name and value (default is false). -/// -/// Returns: -/// A Cookie object created from the parsed cookie string. -/// -/// The method performs the following steps: -/// 1. Initializes default values for cookie attributes. -/// 2. Splits the cookie string into parts. -/// 3. Extracts the cookie name and value. -/// 4. Parses additional cookie attributes. -/// 5. Handles the 'expires' and 'max-age' attributes. -/// 6. Creates and returns a new Cookie object with the parsed attributes. -static Cookie fromString(String cookie, {bool decode = false}) { - final data = { - 'expires': 0, - 'path': '/', - 'domain': null, - 'secure': false, - 'httponly': false, - 'raw': !decode, - 'samesite': null, - 'partitioned': false, - }; - - final parts = HeaderUtils.split(cookie, ';='); - final part = parts.removeAt(0); - - final name = decode ? Uri.decodeComponent(part[0]) : part[0]; - final value = part.length > 1 ? (decode ? Uri.decodeComponent(part[1]) : part[1]) : null; - - data.addAll(HeaderUtils.combine(parts)); - data['expires'] = _expiresTimestamp(data['expires']); - - if (data.containsKey('max-age') && data['max-age'] != null && data['expires'] != null) { - if ((data['max-age'] as int) > 0 || (data['expires'] as int) > DateTime.now().millisecondsSinceEpoch) { - data['expires'] = DateTime.now().millisecondsSinceEpoch + (data['max-age'] as int); - } - } - - return Cookie._internal( - name, - value, - data['expires'] as int, - data['path'] as String, - data['domain'] as String?, - data['secure'] as bool, - data['httponly'] as bool, - data['raw'] as bool, - data['samesite'] as String?, - data['partitioned'] as bool, - ); -} - - /// Creates a new Cookie instance with the specified parameters. - /// - /// Parameters: - /// - [name]: The name of the cookie (required). - /// - [value]: The value of the cookie (optional). - /// - [expire]: The expiration time of the cookie (default: 0). - /// - [path]: The path on the server where the cookie will be available (default: '/'). - /// - [domain]: The domain that the cookie is available to (optional). - /// - [secure]: Whether the cookie should only be transmitted over secure HTTPS (optional). - /// - [httpOnly]: Whether the cookie should be accessible only through HTTP protocol (default: true). - /// - [raw]: Whether the cookie should use no URL encoding (default: false). - /// - [sameSite]: The SameSite attribute of the cookie (default: SAMESITE_LAX). - /// - [partitioned]: Whether the cookie should be tied to the top-level site in cross-site context (default: false). - /// - /// Returns a new Cookie instance with the specified attributes. - factory Cookie.create(String name, {String? value, dynamic expire = 0, String? path = '/', String? domain, bool? secure, bool httpOnly = true, bool raw = false, String? sameSite = SAMESITE_LAX, bool partitioned = false}) { - return Cookie._internal(name, value, expire, path, domain, secure, httpOnly, raw, sameSite, partitioned); - } - - /// Internal constructor for creating a Cookie instance. - /// - /// This constructor initializes a Cookie object with the provided parameters. - /// It performs validation checks on the cookie name and sets default values for certain attributes. - /// - /// Parameters: - /// - [name]: The name of the cookie. - /// - [value]: The value of the cookie. - /// - [expire]: The expiration time of the cookie (can be DateTime, int, or String). - /// - [path]: The path on the server where the cookie will be available (default is '/'). - /// - [domain]: The domain that the cookie is available to. - /// - [secure]: Whether the cookie should only be transmitted over secure HTTPS. - /// - [httpOnly]: Whether the cookie should be accessible only through HTTP protocol. - /// - [raw]: Whether the cookie should use no URL encoding. - /// - [sameSite]: The SameSite attribute of the cookie. - /// - [partitioned]: Whether the cookie should be tied to the top-level site in cross-site context. - /// - /// Throws: - /// - [ArgumentError] if the cookie name contains invalid characters when [raw] is true. - /// - [ArgumentError] if the cookie name is empty. - Cookie._internal(this.name, this.value, dynamic expire, String? path, this.domain, this.secure, this.httpOnly, this.raw, this.sameSite, this.partitioned) { - if (raw && name.contains(RegExp(r'[' + RESERVED_CHARS_LIST + r']'))) { - throw ArgumentError('The cookie name "$name" contains invalid characters.'); - } - - if (name.isEmpty) { - throw ArgumentError('The cookie name cannot be empty.'); - } - - this.expire = _expiresTimestamp(expire); - this.path = path ?? '/'; - this.secureDefault = false; - } - - /// Creates a cookie copy with a new value. - /// - /// This method returns a new Cookie instance with the same attributes as the current cookie, - /// but with the provided [value]. All other attributes remain unchanged. - /// - /// Parameters: - /// - [value]: The new value to set for the cookie. Can be null to create a cookie without a value. - /// - /// Returns: - /// A new Cookie instance with the updated value. - Cookie withValue(String? value) { - return Cookie._internal(name, value, expire, path, domain, secure, httpOnly, raw, sameSite, partitioned); - } - - /// Creates a cookie copy with a new domain that the cookie is available to. - /// - /// This method returns a new Cookie instance with the same attributes as the current cookie, - /// but with the provided [domain]. All other attributes remain unchanged. - /// - /// Parameters: - /// - [domain]: The new domain to set for the cookie. Can be null to remove the domain restriction. - /// - /// Returns: - /// A new Cookie instance with the updated domain. - Cookie withDomain(String? domain) { - return Cookie._internal(name, value, expire, path, domain, secure, httpOnly, raw, sameSite, partitioned); - } - - /// Creates a cookie copy with a new time the cookie expires. - /// - /// This method returns a new Cookie instance with the same attributes as the current cookie, - /// but with the provided [expire] time. All other attributes remain unchanged. - /// - /// Parameters: - /// - [expire]: The new expiration time for the cookie. Can be a DateTime, int (Unix timestamp), - /// or String (parseable date format). - /// - /// Returns: - /// A new Cookie instance with the updated expiration time. - /// - /// Throws: - /// - [ArgumentError] if the provided [expire] value is not a valid expiration time format. - Cookie withExpires(dynamic expire) { - return Cookie._internal(name, value, _expiresTimestamp(expire), path, domain, secure, httpOnly, raw, sameSite, partitioned); - } - -/// Converts various expiration time formats to a Unix timestamp. -/// -/// This method takes a dynamic [expire] parameter and converts it to a Unix timestamp -/// (seconds since the Unix epoch). It supports the following input types: -/// -/// - [DateTime]: Converts the DateTime to a Unix timestamp. -/// - [int]: Assumes the input is already a Unix timestamp and returns it as-is. -/// - [String]: Parses the string as a DateTime and converts it to a Unix timestamp. -/// -/// If the input doesn't match any of these types, an [ArgumentError] is thrown. -/// -/// Parameters: -/// - [expire]: The expiration time in one of the supported formats. -/// -/// Returns: -/// An integer representing the expiration time as a Unix timestamp. -/// -/// Throws: -/// - [ArgumentError] if the input format is not recognized or cannot be parsed. - static int _expiresTimestamp(dynamic expire) { - if (expire is DateTime) { - return expire.millisecondsSinceEpoch ~/ 1000; - } else if (expire is int) { - return expire; - } else if (expire is String) { - return DateTime.parse(expire).millisecondsSinceEpoch ~/ 1000; - } else { - throw ArgumentError('The cookie expiration time is not valid.'); - } - } - - /// Creates a cookie copy with a new path on the server where the cookie will be available. - /// - /// This method returns a new Cookie instance with the same attributes as the current cookie, - /// but with the provided [path]. All other attributes remain unchanged. - /// - /// Parameters: - /// - [path]: The new path to set for the cookie. If an empty string is provided, it defaults to '/'. - /// - /// Returns: - /// A new Cookie instance with the updated path. - Cookie withPath(String path) { - return Cookie._internal(name, value, expire, path.isEmpty ? '/' : path, domain, secure, httpOnly, raw, sameSite, partitioned); - } - - /// Creates a cookie copy that can only be transmitted over a secure HTTPS connection from the client. - /// - /// This method returns a new Cookie instance with the same attributes as the current cookie, - /// but with the provided [secure] flag. All other attributes remain unchanged. - /// - /// Parameters: - /// - [secure]: A boolean value indicating whether the cookie should only be transmitted over HTTPS. - /// If true, the cookie will only be sent over secure connections. - /// - /// Returns: - /// A new Cookie instance with the updated secure flag. - Cookie withSecure(bool secure) { - return Cookie._internal(name, value, expire, path, domain, secure, httpOnly, raw, sameSite, partitioned); - } - - /// Creates a cookie copy that can be accessible only through the HTTP protocol. - /// - /// This method returns a new Cookie instance with the same attributes as the current cookie, - /// but with the provided [httpOnly] flag. All other attributes remain unchanged. - /// - /// Parameters: - /// - [httpOnly]: A boolean value indicating whether the cookie should be accessible only through - /// the HTTP protocol. If true, the cookie will not be accessible through client-side scripts. - /// - /// Returns: - /// A new Cookie instance with the updated httpOnly flag. - Cookie withHttpOnly(bool httpOnly) { - return Cookie._internal(name, value, expire, path, domain, secure, httpOnly, raw, sameSite, partitioned); - } - - /// Creates a cookie copy that uses no URL encoding. - /// - /// This method returns a new Cookie instance with the same attributes as the current cookie, - /// but with the provided [raw] flag. All other attributes remain unchanged. - /// - /// Parameters: - /// - [raw]: A boolean value indicating whether the cookie should use no URL encoding. - /// If true, the cookie name and value will not be URL-encoded. - /// - /// Returns: - /// A new Cookie instance with the updated raw flag. - /// - /// Throws: - /// - [ArgumentError] if [raw] is set to true and the cookie name contains invalid characters. - Cookie withRaw(bool raw) { - if (raw && name.contains(RegExp(r'[' + RESERVED_CHARS_LIST + r']'))) { - throw ArgumentError('The cookie name "$name" contains invalid characters.'); - } - return Cookie._internal(name, value, expire, path, domain, secure, httpOnly, raw, sameSite, partitioned); - } - - /// Creates a cookie copy with a new SameSite attribute. - /// - /// This method returns a new Cookie instance with the same attributes as the current cookie, - /// but with the provided [sameSite] value. All other attributes remain unchanged. - /// - /// Parameters: - /// - [sameSite]: The new SameSite attribute value for the cookie. Valid values are: - /// - [SAMESITE_LAX]: Cookies are not sent on normal cross-site subrequests but are sent when a user navigates to the origin site. - /// - [SAMESITE_STRICT]: Cookies are only sent in a first-party context and not sent along with requests initiated by third party websites. - /// - [SAMESITE_NONE]: Cookies are sent in all contexts, i.e., in responses to both first-party and cross-origin requests. - /// - null: The SameSite attribute is not set. - /// - /// Returns: - /// A new Cookie instance with the updated SameSite attribute. - /// - /// Throws: - /// - [ArgumentError] if the provided [sameSite] value is not one of the valid options. - Cookie withSameSite(String? sameSite) { - final validSameSite = [SAMESITE_LAX, SAMESITE_STRICT, SAMESITE_NONE, null]; - if (!validSameSite.contains(sameSite?.toLowerCase())) { - throw ArgumentError('The "sameSite" parameter value is not valid.'); - } - return Cookie._internal(name, value, expire, path, domain, secure, httpOnly, raw, sameSite?.toLowerCase(), partitioned); - } - - /// Creates a cookie copy that is tied to the top-level site in cross-site context. - /// - /// This method returns a new Cookie instance with the same attributes as the current cookie, - /// but with the provided [partitioned] flag. All other attributes remain unchanged. - /// - /// Parameters: - /// - [partitioned]: A boolean value indicating whether the cookie should be tied to the top-level site - /// in cross-site context. If true, the cookie will be partitioned. - /// - /// Returns: - /// A new Cookie instance with the updated partitioned flag. - Cookie withPartitioned(bool partitioned) { - return Cookie._internal(name, value, expire, path, domain, secure, httpOnly, raw, sameSite, partitioned); - } - - /// Converts the cookie to its string representation. - /// - /// This method generates a string that represents the cookie in the format used in HTTP headers. - /// It includes all the cookie's attributes such as name, value, expiration, path, domain, secure flag, - /// HTTP-only flag, SameSite attribute, and partitioned flag. - /// - /// The method handles the following cases: - /// - If the cookie is raw, the name and value are not URL-encoded. - /// - If the value is null or empty, the cookie is treated as deleted with immediate expiration. - /// - If an expiration time is set, it's included in both 'expires' and 'Max-Age' attributes. - /// - All other attributes (path, domain, secure, httpOnly, sameSite, partitioned) are added if set. - /// - /// Returns: - /// A string representation of the cookie suitable for use in an HTTP header. - @override - String toString() { - final buffer = StringBuffer(); - - if (raw) { - buffer.write(name); - } else { - buffer.write(Uri.encodeComponent(name)); - } - - buffer.write('='); - - if (value == null || value!.isEmpty) { - buffer.write('deleted; expires=${DateTime.fromMillisecondsSinceEpoch(DateTime.now().millisecondsSinceEpoch - 31536001).toUtc().toIso8601String()}; Max-Age=0'); - } else { - buffer.write(raw ? value : Uri.encodeComponent(value!)); - - if (expire != 0) { - buffer.write('; expires=${DateTime.fromMillisecondsSinceEpoch(expire * 1000).toUtc().toIso8601String()}; Max-Age=${getMaxAge()}'); - } - } - - if (path.isNotEmpty) { - buffer.write('; path=$path'); - } - - if (domain != null && domain!.isNotEmpty) { - buffer.write('; domain=$domain'); - } - - if (isSecure()) { - buffer.write('; secure'); - } - - if (httpOnly) { - buffer.write('; httponly'); - } - - if (sameSite != null) { - buffer.write('; samesite=$sameSite'); - } - - if (partitioned) { - buffer.write('; partitioned'); - } - - return buffer.toString(); - } - - /// Gets the name of the cookie. - /// - /// Returns: - /// A string representing the name of the cookie. - String getName() => name; - - /// Gets the value of the cookie. - /// - /// Returns: - /// A string representing the value of the cookie, or null if the cookie has no value. - String? getValue() => value; - - /// Gets the domain that the cookie is available to. - /// - /// Returns: - /// A string representing the domain of the cookie, or null if no domain is set. - String? getDomain() => domain; - - /// Gets the expiration time of the cookie. - /// - /// Returns: - /// An integer representing the expiration time of the cookie as a Unix timestamp. - /// If the cookie doesn't have an expiration time set, it returns 0. - int getExpiresTime() => expire; - - /// Calculates and returns the Max-Age attribute value for the cookie. - /// - /// This method computes the number of seconds until the cookie expires. - /// It does this by subtracting the current Unix timestamp from the cookie's - /// expiration timestamp. The result is always non-negative, with a minimum - /// value of 0. - /// - /// Returns: - /// An integer representing the number of seconds until the cookie expires. - /// If the cookie has already expired, it returns 0. - int getMaxAge() { - final maxAge = expire - (DateTime.now().millisecondsSinceEpoch ~/ 1000); - return max(0, maxAge); - } - - /// Gets the path on the server where the cookie will be available. - /// - /// This method returns the path attribute of the cookie, which specifies the - /// subset of URLs in a domain for which the cookie is valid. - /// - /// Returns: - /// A string representing the path of the cookie. - String getPath() => path; - - /// Checks whether the cookie should only be transmitted over a secure HTTPS connection from the client. - /// - /// This method returns the value of the 'secure' flag for the cookie. If the 'secure' flag - /// is explicitly set (either true or false), it returns that value. If 'secure' is null, - /// it falls back to the default secure setting (secureDefault). - /// - /// Returns: - /// A boolean value: true if the cookie should only be sent over secure connections, - /// false otherwise. - bool isSecure() => secure ?? secureDefault; - - /// Checks whether the cookie is accessible only through the HTTP protocol. - /// - /// This method returns the value of the 'httpOnly' flag for the cookie. - /// If true, the cookie is inaccessible to client-side scripts like JavaScript, - /// which helps mitigate cross-site scripting (XSS) attacks. - /// - /// Returns: - /// A boolean value: true if the cookie is HTTP-only, false otherwise. - bool isHttpOnly() => httpOnly; - - /// Checks if the cookie has been cleared or has expired. - /// - /// This method determines whether the cookie is considered cleared by checking two conditions: - /// 1. The cookie has an expiration time set (expire != 0). - /// 2. The expiration time is in the past (earlier than the current time). - /// - /// Returns: - /// A boolean value: true if the cookie has been cleared or has expired, false otherwise. - bool isCleared() => expire != 0 && expire < (DateTime.now().millisecondsSinceEpoch ~/ 1000); - - /// Checks if the cookie value should be sent with no URL encoding. - /// - /// This method returns the value of the 'raw' flag for the cookie. - /// If true, the cookie name and value will not be URL-encoded when the cookie is converted to a string. - /// - /// Returns: - /// A boolean value: true if the cookie should be sent raw (without URL encoding), false otherwise. - bool isRaw() => raw; - - /// Checks whether the cookie should be tied to the top-level site in cross-site context. - /// - /// This method returns the value of the 'partitioned' flag for the cookie. - /// If true, the cookie will be partitioned, meaning it will be tied to the top-level site - /// in cross-site contexts, which can help improve privacy and security. - /// - /// Returns: - /// A boolean value: true if the cookie is partitioned, false otherwise. - bool isPartitioned() => partitioned; - - /// Gets the SameSite attribute of the cookie. - /// - /// This method returns the value of the SameSite attribute for the cookie. - /// The SameSite attribute is used to control how cookies are sent with cross-site requests. - /// - /// Returns: - /// A string representing the SameSite attribute of the cookie, which can be: - /// - 'strict': The cookie is only sent for same-site requests. - /// - 'lax': The cookie is sent for same-site requests and top-level navigation from external sites. - /// - 'none': The cookie is sent for all cross-site requests. - /// - null: If the SameSite attribute is not set. - String? getSameSite() => sameSite; - - /// Sets the default value for the "secure" flag when it is not explicitly set. - /// - /// This method allows you to specify a default value for the "secure" flag - /// that will be used when the secure property of the cookie is null. - /// - /// Parameters: - /// - [defaultSecure]: A boolean value indicating whether cookies should be - /// secure by default. If true, cookies will be marked as secure by default - /// when the secure property is not explicitly set. - /// - /// This setting affects the behavior of the [isSecure] method when the - /// secure property is null. - void setSecureDefault(bool defaultSecure) { - secureDefault = defaultSecure; - } -} diff --git a/packages/http/lib/src/foundation/countable_interface.dart b/packages/http/lib/src/foundation/countable_interface.dart deleted file mode 100644 index 3935314..0000000 --- a/packages/http/lib/src/foundation/countable_interface.dart +++ /dev/null @@ -1,17 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the PHP CountableInterface.php class to Dart - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/// An abstract class representing objects that can be counted. -/// -/// Classes that implement this interface must provide a [count] getter -/// that returns the current count of the object. -abstract class Countable { - int get count; -} diff --git a/packages/http/lib/src/foundation/exception/bad_request_exception.dart b/packages/http/lib/src/foundation/exception/bad_request_exception.dart deleted file mode 100644 index b8523b8..0000000 --- a/packages/http/lib/src/foundation/exception/bad_request_exception.dart +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the symfony BadRequestException.php class to Dart - * - * (C) Protevus - * (C) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'package:protevus_http/foundation_exception.dart'; - -/// Exception thrown when a user sends a malformed request. -/// -/// This exception is used to indicate that the client's request was invalid or -/// could not be served. It extends [UnexpectedValueException] and implements -/// [RequestExceptionInterface]. -/// -/// Example usage: -/// ```dart -/// throw BadRequestException('Invalid parameter: id must be a positive integer'); -/// ``` -class BadRequestException extends UnexpectedValueException implements RequestExceptionInterface { - /// Creates a new [BadRequestException] with an optional error message. - /// - /// The [message] parameter is passed to the superclass constructor. - /// If not provided, the exception will be created with an empty message. - /// - /// Example: - /// ```dart - /// throw BadRequestException('Invalid input'); - /// ``` - BadRequestException([super.message]); - - /// Returns a string representation of the [BadRequestException]. - /// - /// If the exception message is empty, it returns 'BadRequestException'. - /// Otherwise, it returns 'BadRequestException: ' followed by the exception message. - /// - /// Example: - /// ```dart - /// var exception = BadRequestException('Invalid input'); - /// print(exception.toString()); // Output: BadRequestException: Invalid input - /// ``` - @override - String toString() { - return message.isEmpty ? 'BadRequestException' : 'BadRequestException: $message'; - } -} - diff --git a/packages/http/lib/src/foundation/exception/conflicting_headers_exception.dart b/packages/http/lib/src/foundation/exception/conflicting_headers_exception.dart deleted file mode 100644 index f8fc609..0000000 --- a/packages/http/lib/src/foundation/exception/conflicting_headers_exception.dart +++ /dev/null @@ -1,18 +0,0 @@ -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 -class ConflictingHeadersException extends UnexpectedValueException - implements RequestExceptionInterface { - /// Creates a new instance of [ConflictingHeadersException]. - ConflictingHeadersException([super.message]); -} diff --git a/packages/http/lib/src/foundation/exception/json_exception.dart b/packages/http/lib/src/foundation/exception/json_exception.dart deleted file mode 100644 index 7d05247..0000000 --- a/packages/http/lib/src/foundation/exception/json_exception.dart +++ /dev/null @@ -1,20 +0,0 @@ -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 -class JsonException extends UnexpectedValueException - implements RequestExceptionInterface { - /// Creates a new instance of [JsonException]. - JsonException([super.message]); -} diff --git a/packages/http/lib/src/foundation/exception/request_exception_interface.dart b/packages/http/lib/src/foundation/exception/request_exception_interface.dart deleted file mode 100644 index 0a883fc..0000000 --- a/packages/http/lib/src/foundation/exception/request_exception_interface.dart +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the symfony RequestExceptionInterface.php class to Dart - * - * (C) Protevus - * (C) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/// An interface for exceptions related to HTTP requests. -/// -/// Implementations of this interface are intended to be used for exceptions -/// that should trigger an HTTP 400 (Bad Request) response in the application. -/// -/// This interface doesn't declare any methods, but serves as a marker -/// to identify exceptions specifically related to request handling. -abstract class RequestExceptionInterface { - -} - diff --git a/packages/http/lib/src/foundation/exception/session_not_found_exception.dart b/packages/http/lib/src/foundation/exception/session_not_found_exception.dart deleted file mode 100644 index 746f87a..0000000 --- a/packages/http/lib/src/foundation/exception/session_not_found_exception.dart +++ /dev/null @@ -1,15 +0,0 @@ -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); -} diff --git a/packages/http/lib/src/foundation/exception/suspicious_operation_exception.dart b/packages/http/lib/src/foundation/exception/suspicious_operation_exception.dart deleted file mode 100644 index bc913e3..0000000 --- a/packages/http/lib/src/foundation/exception/suspicious_operation_exception.dart +++ /dev/null @@ -1,19 +0,0 @@ -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 -class SuspiciousOperationException extends UnexpectedValueException - implements RequestExceptionInterface { - /// Creates a new instance of [ConflictingHeadersException]. - SuspiciousOperationException([super.message]); -} diff --git a/packages/http/lib/src/foundation/exception/unexpected_value_exception.dart b/packages/http/lib/src/foundation/exception/unexpected_value_exception.dart deleted file mode 100644 index fd155c7..0000000 --- a/packages/http/lib/src/foundation/exception/unexpected_value_exception.dart +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the symfony UnexpectedValueException.php class to Dart - * - * (C) Protevus - * (C) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'dart:core'; - -/// Exception thrown if a value does not match with a set of values. -/// -/// Typically this happens when a function calls another function and expects -/// the return value to be of a certain type or value not including arithmetic -/// or buffer related errors. -class UnexpectedValueException implements Exception { - /// The error message associated with this exception. - /// - /// This is a final String that stores the descriptive message for the - /// UnexpectedValueException. It provides details about why the exception - /// was thrown and can be used for logging or displaying error information. - final String message; - - /// Constructor for UnexpectedValueException. - /// - /// Creates a new instance of UnexpectedValueException with an optional error message. - /// - /// @param message The error message for this exception. Defaults to an empty string. - UnexpectedValueException([this.message = '']); - - /// Returns a string representation of the UnexpectedValueException. - /// - /// This method overrides the default toString() method to provide a more - /// descriptive string representation of the exception. If the exception - /// message is empty, it returns just the exception name. Otherwise, it - /// returns the exception name followed by a colon and the error message. - /// - /// @return A string representation of the UnexpectedValueException. - @override - String toString() => message.isEmpty ? 'UnexpectedValueException' : 'UnexpectedValueException: $message'; -} diff --git a/packages/http/lib/src/foundation/file/exception/cannot_write_file_exception.dart b/packages/http/lib/src/foundation/file/exception/cannot_write_file_exception.dart deleted file mode 100644 index 44df614..0000000 --- a/packages/http/lib/src/foundation/file/exception/cannot_write_file_exception.dart +++ /dev/null @@ -1,16 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -import 'package:protevus_http/foundation_file_exception.dart'; - -/// Thrown when an UPLOAD_ERR_CANT_WRITE error occurred with UploadedFile. -/// -/// @author Florent Mata -class CannotWriteFileException extends FileException { - /// Creates a new [CannotWriteFileException] with the given [message]. - CannotWriteFileException([super.message]); -} diff --git a/packages/http/lib/src/foundation/file/exception/extension_file_exception.dart b/packages/http/lib/src/foundation/file/exception/extension_file_exception.dart deleted file mode 100644 index 17abe11..0000000 --- a/packages/http/lib/src/foundation/file/exception/extension_file_exception.dart +++ /dev/null @@ -1,16 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -import 'package:protevus_http/foundation_file_exception.dart'; - -/// Thrown when an UPLOAD_ERR_EXTENSION error occurred with UploadedFile. -/// -/// @author Florent Mata -class ExtensionFileException extends FileException { - // The constructor is empty as it inherits from FileException - ExtensionFileException([super.message]); -} diff --git a/packages/http/lib/src/foundation/file/exception/file_exception.dart b/packages/http/lib/src/foundation/file/exception/file_exception.dart deleted file mode 100644 index ea6e84f..0000000 --- a/packages/http/lib/src/foundation/file/exception/file_exception.dart +++ /dev/null @@ -1,32 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -import 'dart:core'; - -/// Exception thrown when an error occurs during file operations. -/// -/// This exception is used to handle various file-related errors in the component File. -/// -/// Example usage: -/// ```dart -/// try { -/// // File operation that may throw an exception -/// } catch (e) { -/// if (e is FileException) { -/// print('A file error occurred: ${e.message}'); -/// } -/// } -/// ``` -class FileException implements Exception { - final String message; - - /// Creates a new [FileException] with the given [message]. - FileException([this.message = '']); - - @override - String toString() => 'FileException: $message'; -} diff --git a/packages/http/lib/src/foundation/file/exception/file_not_found_exception.dart b/packages/http/lib/src/foundation/file/exception/file_not_found_exception.dart deleted file mode 100644 index 7d019c1..0000000 --- a/packages/http/lib/src/foundation/file/exception/file_not_found_exception.dart +++ /dev/null @@ -1,18 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -import 'package:protevus_http/foundation_file_exception.dart'; - -/// Thrown when a file was not found. -/// -/// @author Bernhard Schussek -class FileNotFoundException extends FileException { - /// Creates a new [FileNotFoundException] with the given file path. - /// - /// [path] The path to the file that was not found. - FileNotFoundException(String path) : super('The file "$path" does not exist'); -} diff --git a/packages/http/lib/src/foundation/file/exception/form_size_file_exception.dart b/packages/http/lib/src/foundation/file/exception/form_size_file_exception.dart deleted file mode 100644 index cd1490d..0000000 --- a/packages/http/lib/src/foundation/file/exception/form_size_file_exception.dart +++ /dev/null @@ -1,15 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -import 'package:protevus_http/foundation_file_exception.dart'; - -/// Thrown when an UPLOAD_ERR_FORM_SIZE error occurred with UploadedFile. -/// -/// @author Florent Mata -class FormSizeFileException extends FileException { - FormSizeFileException([super.message]); -} diff --git a/packages/http/lib/src/foundation/file/exception/ini_size_file_exception.dart b/packages/http/lib/src/foundation/file/exception/ini_size_file_exception.dart deleted file mode 100644 index 3a7802d..0000000 --- a/packages/http/lib/src/foundation/file/exception/ini_size_file_exception.dart +++ /dev/null @@ -1,15 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -import 'package:protevus_http/foundation_file_exception.dart'; - -/// Thrown when an UPLOAD_ERR_INI_SIZE error occurred with UploadedFile. -/// -/// @author Florent Mata -class IniSizeFileException extends FileException { - IniSizeFileException(super.message); -} diff --git a/packages/http/lib/src/foundation/file/exception/no_file_exception.dart b/packages/http/lib/src/foundation/file/exception/no_file_exception.dart deleted file mode 100644 index 4683ac2..0000000 --- a/packages/http/lib/src/foundation/file/exception/no_file_exception.dart +++ /dev/null @@ -1,15 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -import 'package:protevus_http/foundation_file_exception.dart'; - -/// Thrown when an UPLOAD_ERR_NO_FILE error occurred with UploadedFile. -/// -/// @author Florent Mata -class NoFileException extends FileException { - NoFileException(super.message); -} diff --git a/packages/http/lib/src/foundation/file/exception/no_tmp_dir_file_exception.dart b/packages/http/lib/src/foundation/file/exception/no_tmp_dir_file_exception.dart deleted file mode 100644 index c796066..0000000 --- a/packages/http/lib/src/foundation/file/exception/no_tmp_dir_file_exception.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:protevus_http/foundation_file_exception.dart'; - -/// Thrown when an UPLOAD_ERR_NO_TMP_DIR error occurred with UploadedFile. -/// -/// @author Florent Mata -class NoTmpDirFileException extends FileException { - NoTmpDirFileException(super.message); -} diff --git a/packages/http/lib/src/foundation/file/exception/partial_file_exception.dart b/packages/http/lib/src/foundation/file/exception/partial_file_exception.dart deleted file mode 100644 index c31d406..0000000 --- a/packages/http/lib/src/foundation/file/exception/partial_file_exception.dart +++ /dev/null @@ -1,18 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -// Note: In Dart, we don't need to explicitly declare namespaces like in PHP. -// The package structure in Dart serves a similar purpose. - -import 'package:protevus_http/foundation_file_exception.dart'; - -/// Thrown when an UPLOAD_ERR_PARTIAL error occurred with UploadedFile. -/// -/// @author Florent Mata -class PartialFileException extends FileException { - PartialFileException(super.message); -} diff --git a/packages/http/lib/src/foundation/file/file.dart b/packages/http/lib/src/foundation/file/file.dart deleted file mode 100644 index 9eab7ca..0000000 --- a/packages/http/lib/src/foundation/file/file.dart +++ /dev/null @@ -1,174 +0,0 @@ -import 'dart:io' as io; -import 'package:path/path.dart' as p; -import 'package:protevus_http/foundation_file_exception.dart'; -import 'package:protevus_mime/mime.dart'; - -/// A file in the file system. -class File extends io.FileSystemEntity { - late final io.File _dartFile; - @override - final String path; - - /// Constructs a new file from the given path. - /// - /// [path] The path to the file - /// [checkPath] Whether to check the path or not - /// - /// Throws [FileNotFoundException] If the given path is not a file - File(this.path, {bool checkPath = true}) { - if (checkPath && !io.FileSystemEntity.isFileSync(path)) { - throw FileNotFoundException(path); - } - _dartFile = io.File(path); - } - - /// Returns the extension based on the mime type. - /// - /// If the mime type is unknown, returns null. - /// - /// This method uses the mime type as guessed by getMimeType() - /// to guess the file extension. - Future guessExtension() async { - final mimeType = await getMimeType(); - if (mimeType == null) return null; - - final extensions = MimeTypes.getDefault().getExtensions(mimeType); - return extensions.isNotEmpty ? extensions.first : null; - } - - /// Returns the mime type of the file. - /// - /// The mime type is guessed using the MimeTypes class. - Future getMimeType() { - return MimeTypes.getDefault().guessMimeType(path); - } - - /// Moves the file to a new location. - /// - /// Throws [FileException] if the target file could not be created - File move(String directory, [String? name]) { - final target = getTargetFile(directory, name); - - try { - final newPath = target.path; - _dartFile.renameSync(newPath); - chmod(newPath, '0666'); - return target; - } catch (e) { - throw FileException( - 'Could not move the file "$path" to "${target.path}" ($e).'); - } - } - - /// Returns the content of the file. - String getContent() { - try { - return _dartFile.readAsStringSync(); - } catch (e) { - throw FileException('Could not get the content of the file "$path".'); - } - } - - /// Returns the target file for a move operation. - File getTargetFile(String directory, [String? name]) { - final dir = io.Directory(directory); - if (!dir.existsSync()) { - try { - dir.createSync(recursive: true); - } catch (e) { - throw FileException('Unable to create the "$directory" directory.'); - } - } else if (!dir.statSync().modeString().contains('w')) { - throw FileException('Unable to write in the "$directory" directory.'); - } - - final targetPath = p.join(directory, name ?? p.basename(path)); - return File(targetPath, checkPath: false); - } - - /// Returns locale independent base name of the given path. - String getName(String name) { - final normalizedName = name.replaceAll('\\', '/'); - final pos = normalizedName.lastIndexOf('/'); - return pos == -1 ? normalizedName : normalizedName.substring(pos + 1); - } - - /// Changes the file permissions. - /// - /// [filePath] is the path to the file whose permissions should be changed. - /// [mode] should be an octal string like '0644' for Unix-like systems. - /// For Windows, use 'read' for read-only, 'write' for read/write, or 'full' for full control. - static Future chmod(String filePath, String mode) async { - if (io.Platform.isWindows) { - await _chmodWindows(filePath, mode); - } else { - await _chmodUnix(filePath, mode); - } - } - - static Future _chmodUnix(String filePath, String mode) async { - try { - final result = await io.Process.run('chmod', [mode, filePath]); - if (result.exitCode != 0) { - throw FileException( - 'Failed to change permissions for $filePath: ${result.stderr}'); - } - } catch (e) { - if (e.toString().contains('Permission denied')) { - // Optionally, you could try with sudo here, but that requires user interaction - throw FileException( - 'Permission denied. You may need to run this with elevated privileges.'); - } else { - throw FileException('Failed to change permissions for $filePath: $e'); - } - } - } - - static Future _chmodWindows(String filePath, String mode) async { - String permission; - switch (mode.toLowerCase()) { - case 'read': - permission = '(R)'; - break; - case 'write': - permission = '(R,W)'; - break; - case 'full': - permission = '(F)'; - break; - default: - throw ArgumentError( - 'Invalid mode for Windows. Use "read", "write", or "full".'); - } - - final result = await io.Process.run( - 'icacls', [filePath, '/grant', '*S-1-1-0:$permission']); - if (result.exitCode != 0) { - throw FileException( - 'Failed to change permissions for $filePath: ${result.stderr}'); - } - } - - @override - io.FileSystemEntity get absolute => throw UnimplementedError(); - - @override - Future exists() { - throw UnimplementedError(); - } - - @override - bool existsSync() { - throw UnimplementedError(); - } - - @override - Future rename(String newPath) { - throw UnimplementedError(); - } - - @override - io.FileSystemEntity renameSync(String newPath) { - throw UnimplementedError(); - } -} diff --git a/packages/http/lib/src/foundation/file/upload_file.dart b/packages/http/lib/src/foundation/file/upload_file.dart deleted file mode 100644 index 4f8a134..0000000 --- a/packages/http/lib/src/foundation/file/upload_file.dart +++ /dev/null @@ -1,131 +0,0 @@ -import 'package:path/path.dart' as p; - -import 'package:protevus_http/foundation_file_exception.dart'; -import 'package:protevus_http/foundation_file.dart'; -import 'package:protevus_mime/mime.dart'; - -/// A file uploaded through a form. -class UploadedFile extends File { - late String _originalName; - late String _mimeType; - late int _error; - late String _originalPath; - late bool _test; - - UploadedFile( - super.path, - String originalName, - String? mimeType, - int? error, - bool test, - ) { - _originalName = _getName(originalName); - _originalPath = originalName.replaceAll('\\', '/'); - _mimeType = mimeType ?? 'application/octet-stream'; - _error = error ?? 0; // UPLOAD_ERR_OK - _test = test; - } - - String getClientOriginalName() { - return _originalName; - } - - String getClientOriginalExtension() { - return p.extension(_originalName); - } - - String getClientOriginalPath() { - return _originalPath; - } - - String getClientMimeType() => _mimeType; - - String? guessClientExtension() { - try { - List extensions = - MimeTypes.getDefault().getExtensions(getClientMimeType()); - return extensions.isNotEmpty ? extensions[0] : null; - } catch (e) { - return null; - } - } - - int getError() { - return _error; - } - - bool isValid() { - bool isOk = _error == 0; // UPLOAD_ERR_OK - return _test ? isOk : isOk && File(path).existsSync(); - } - - @override - File move(String directory, [String? name]) { - if (isValid()) { - if (_test) { - return File(p.join(directory, name ?? p.basename(path))); - } - - File target = _getTargetFile(directory, name); - try { - return super.move(target.path); - } catch (e) { - throw FileException( - 'Could not move the file "$path" to "${target.path}" ($e).'); - } - } - - switch (_error) { - case 1: // UPLOAD_ERR_INI_SIZE - throw IniSizeFileException(_getErrorMessage()); - case 2: // UPLOAD_ERR_FORM_SIZE - throw FormSizeFileException(_getErrorMessage()); - case 3: // UPLOAD_ERR_PARTIAL - throw PartialFileException(_getErrorMessage()); - case 4: // UPLOAD_ERR_NO_FILE - throw NoFileException(_getErrorMessage()); - case 6: // UPLOAD_ERR_NO_TMP_DIR - throw NoTmpDirFileException(_getErrorMessage()); - case 7: // UPLOAD_ERR_CANT_WRITE - throw CannotWriteFileException(_getErrorMessage()); - case 8: // UPLOAD_ERR_EXTENSION - throw ExtensionFileException(_getErrorMessage()); - default: - throw FileException(_getErrorMessage()); - } - } - - static int getMaxFilesize() { - // Note: This is a placeholder. Implement according to your needs. - return 2 * 1024 * 1024; // 2MB as an example - } - - String _getErrorMessage() { - Map errors = { - 1: 'The file "%s" exceeds your upload_max_filesize ini directive (limit is %d KiB).', - 2: 'The file "%s" exceeds the upload limit defined in your form.', - 3: 'The file "%s" was only partially uploaded.', - 4: 'No file was uploaded.', - 6: 'File could not be uploaded: missing temporary directory.', - 7: 'The file "%s" could not be written on disk.', - 8: 'File upload was stopped by a PHP extension.', - }; - - int maxFilesize = _error == 1 ? getMaxFilesize() ~/ 1024 : 0; - String message = errors[_error] ?? - 'The file "%s" was not uploaded due to an unknown error.'; - - return message - .replaceAll('%s', _originalName) - .replaceAll('%d', maxFilesize.toString()); - } - - String _getName(String name) { - return p.basename(name); - } - - File _getTargetFile(String directory, String? name) { - name ??= p.basename(path); - return File(p.join(directory, name)); - } -} diff --git a/packages/http/lib/src/foundation/file_bag.dart b/packages/http/lib/src/foundation/file_bag.dart deleted file mode 100644 index a75b4f0..0000000 --- a/packages/http/lib/src/foundation/file_bag.dart +++ /dev/null @@ -1,130 +0,0 @@ -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> { - static const List _fileKeys = [ - 'error', - 'full_path', - 'name', - 'size', - 'tmp_name', - 'type' - ]; - - /// Constructs a FileBag instance. - /// - /// [parameters] is an array of HTTP files. - FileBag([Map parameters = const {}]) { - replace(parameters); - } - - /// Replaces the current files with a new set. - @override - void replace(Map files) { - parameters.clear(); - add(files); - } - - /// Sets a file in the bag. - @override - void set(String key, dynamic value) { - if (value is! Map && 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 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) { - file = _fixDartFilesMap(file); - List 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) { - 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 _fixDartFilesMap(Map data) { - List keys = (data.keys.toList()..add('full_path'))..sort(); - - if (!listEquals(_fileKeys, keys) || - !data.containsKey('name') || - data['name'] is! Map) { - return data; - } - - Map 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(List a, List 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; -} diff --git a/packages/http/lib/src/foundation/filter.dart b/packages/http/lib/src/foundation/filter.dart deleted file mode 100644 index e3b4eb8..0000000 --- a/packages/http/lib/src/foundation/filter.dart +++ /dev/null @@ -1,792 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'dart:core'; -import 'dart:io'; -import 'package:sanitize_html/sanitize_html.dart'; -import 'package:email_validator/email_validator.dart'; -import 'package:validator_dart/validator_dart.dart'; - -/// A class that provides various filtering and validation methods for input data. -/// -/// This class is designed to replicate the functionality of PHP's filter_var functions in Dart. -/// It includes methods for validating and sanitizing different types of data such as -/// integers, floats, booleans, emails, URLs, and IP addresses. -/// -/// The class contains several constant values that are used as flags and filter types, -/// mirroring the constants used in PHP's filter_var functions. -/// -/// Key methods: -/// - [filterHasVar]: Checks if a variable of a specified type exists. -/// - [filterId]: Returns the filter ID corresponding to a named filter. -/// - [filterVar]: Filters a variable with a specified filter and options. -/// -/// The class also includes several private helper methods for specific filtering tasks. -/// -/// Usage example: -/// ```dart -/// var result = Filter.filterVar('test@example.com', Filter.FILTER_VALIDATE_EMAIL); -/// print(result); // Outputs: test@example.com -/// ``` -/// -/// Note: This class is intended to be used as a direct replacement for PHP's filter_var -/// functions in Dart applications, particularly useful for porting PHP code to Dart. -class Filter { - // Constants - static const int INPUT_POST = 0; - static const int INPUT_GET = 1; - static const int INPUT_COOKIE = 2; - static const int INPUT_ENV = 4; - static const int INPUT_SERVER = 5; - static const int INPUT_SESSION = 6; - static const int INPUT_REQUEST = 99; - static const int FILTER_FLAG_NONE = 0; - static const int FILTER_REQUIRE_SCALAR = 33554432; - static const int FILTER_REQUIRE_ARRAY = 16777216; - static const int FILTER_FORCE_ARRAY = 67108864; - static const int FILTER_NULL_ON_FAILURE = 134217728; - static const int FILTER_VALIDATE_INT = 257; - static const int FILTER_VALIDATE_BOOLEAN = 258; - static const int FILTER_VALIDATE_FLOAT = 259; - static const int FILTER_VALIDATE_REGEXP = 272; - static const int FILTER_VALIDATE_URL = 273; - static const int FILTER_VALIDATE_EMAIL = 274; - static const int FILTER_VALIDATE_IP = 275; - static const int FILTER_DEFAULT = 516; - static const int FILTER_UNSAFE_RAW = 516; - static const int FILTER_SANITIZE_STRING = 513; - static const int FILTER_SANITIZE_STRIPPED = 513; - static const int FILTER_SANITIZE_ENCODED = 514; - static const int FILTER_SANITIZE_SPECIAL_CHARS = 515; - static const int FILTER_SANITIZE_EMAIL = 517; - static const int FILTER_SANITIZE_URL = 518; - static const int FILTER_SANITIZE_NUMBER_INT = 519; - static const int FILTER_SANITIZE_NUMBER_FLOAT = 520; - static const int FILTER_SANITIZE_MAGIC_QUOTES = 521; - static const int FILTER_CALLBACK = 1024; - static const int FILTER_FLAG_ALLOW_OCTAL = 1; - static const int FILTER_FLAG_ALLOW_HEX = 2; - static const int FILTER_FLAG_STRIP_LOW = 4; - static const int FILTER_FLAG_STRIP_HIGH = 8; - static const int FILTER_FLAG_ENCODE_LOW = 16; - static const int FILTER_FLAG_ENCODE_HIGH = 32; - static const int FILTER_FLAG_ENCODE_AMP = 64; - static const int FILTER_FLAG_NO_ENCODE_QUOTES = 128; - static const int FILTER_FLAG_EMPTY_STRING_NULL = 256; - static const int FILTER_FLAG_ALLOW_FRACTION = 4096; - static const int FILTER_FLAG_ALLOW_THOUSAND = 8192; - static const int FILTER_FLAG_ALLOW_SCIENTIFIC = 16384; - static const int FILTER_FLAG_PATH_REQUIRED = 262144; - static const int FILTER_FLAG_QUERY_REQUIRED = 524288; - static const int FILTER_FLAG_IPV4 = 1048576; - static const int FILTER_FLAG_IPV6 = 2097152; - static const int FILTER_FLAG_NO_RES_RANGE = 4194304; - static const int FILTER_FLAG_NO_PRIV_RANGE = 8388608; - - /// Checks if a variable of the specified type exists. - /// - /// This method determines whether a variable with the given [variableName] - /// exists for the specified input [type]. The input types are defined by - /// constants in the Filter class (e.g., INPUT_GET, INPUT_POST, etc.). - /// - /// Parameters: - /// - [type]: An integer representing the input type to check. - /// - [variableName]: The name of the variable to check for existence. - /// - /// Returns: - /// - [bool]: true if the variable exists for the given input type, false otherwise. - /// - /// Note: - /// - For INPUT_POST and INPUT_COOKIE, the implementation is not yet complete. - /// - For INPUT_GET, INPUT_SERVER, and INPUT_ENV, it checks the Platform.environment. - /// - For other input types, it always returns false. - static bool filterHasVar(int type, String variableName) { - switch (type) { - case INPUT_GET: - return Platform.environment.containsKey(variableName); - case INPUT_POST: - // TODO: Implement POST variable check - return false; - case INPUT_COOKIE: - // TODO: Implement COOKIE variable check - return false; - case INPUT_SERVER: - return Platform.environment.containsKey(variableName); - case INPUT_ENV: - return Platform.environment.containsKey(variableName); - default: - return false; - } - } - - /// Returns the filter ID corresponding to a named filter. - /// - /// This method takes a [filterName] as input and returns the corresponding - /// filter constant value. If no matching filter is found, it returns null. - /// - /// Parameters: - /// - [filterName]: A string representing the name of the filter. - /// - /// Returns: - /// - An integer representing the filter constant, or null if no match is found. - /// - /// Example: - /// ```dart - /// int? emailFilterId = Filter.filterId('validate_email'); - /// print(emailFilterId); // Outputs: 274 (FILTER_VALIDATE_EMAIL) - /// ``` - static int? filterId(String filterName) { - switch (filterName) { - case 'int': - return FILTER_VALIDATE_INT; - case 'boolean': - return FILTER_VALIDATE_BOOLEAN; - case 'float': - return FILTER_VALIDATE_FLOAT; - case 'validate_regexp': - return FILTER_VALIDATE_REGEXP; - case 'validate_url': - return FILTER_VALIDATE_URL; - case 'validate_email': - return FILTER_VALIDATE_EMAIL; - case 'validate_ip': - return FILTER_VALIDATE_IP; - case 'string': - return FILTER_SANITIZE_STRING; - case 'stripped': - return FILTER_SANITIZE_STRIPPED; - case 'encoded': - return FILTER_SANITIZE_ENCODED; - case 'special_chars': - return FILTER_SANITIZE_SPECIAL_CHARS; - case 'unsafe_raw': - return FILTER_UNSAFE_RAW; - case 'email': - return FILTER_SANITIZE_EMAIL; - case 'url': - return FILTER_SANITIZE_URL; - case 'number_int': - return FILTER_SANITIZE_NUMBER_INT; - case 'number_float': - return FILTER_SANITIZE_NUMBER_FLOAT; - case 'magic_quotes': - return FILTER_SANITIZE_MAGIC_QUOTES; - case 'callback': - return FILTER_CALLBACK; - default: - return null; - } - } - - /// Filters a variable with a specified filter and options. - /// - /// This method applies various filtering and validation techniques to the input [variable] - /// based on the specified [filter] and [options]. It supports both scalar and array inputs, - /// and can handle different types of filters such as validation and sanitization. - /// - /// Parameters: - /// - [variable]: The input to be filtered. Can be a scalar value or an array. - /// - [filter]: An integer constant representing the filter to be applied. Defaults to [FILTER_DEFAULT]. - /// - [options]: Additional options for the filter. Can be an integer (flags) or a Map containing 'flags' and 'options'. - /// - /// Returns: - /// - The filtered variable if successful. - /// - `false` if the filter fails and [FILTER_NULL_ON_FAILURE] is not set. - /// - `null` if the filter fails and [FILTER_NULL_ON_FAILURE] is set. - /// - An array of filtered values if the input is an array and [FILTER_REQUIRE_ARRAY] or [FILTER_FORCE_ARRAY] is set. - /// - /// This method supports various filter types including boolean validation, email validation, - /// float and integer validation, IP and URL validation, regular expression matching, - /// and various sanitization filters for emails, URLs, numbers, and special characters. - /// - /// The behavior of the filter can be modified using flags such as [FILTER_REQUIRE_ARRAY], - /// [FILTER_FORCE_ARRAY], [FILTER_NULL_ON_FAILURE], among others. - static dynamic filterVar(dynamic variable, - [int filter = FILTER_DEFAULT, dynamic options = 0]) { - int flags = 0; - Map opts = {}; - - if (!((filter >= 0x0200 && filter <= 0x020a) || - (filter >= 0x0100 && filter <= 0x0114) || - filter == FILTER_CALLBACK)) { - return false; - } - - if (options is Map) { - if (options.containsKey('flags')) { - flags = options['flags'] as int; - } - if (options.containsKey('options')) { - opts = options['options'] as Map; - } - } else { - flags = options as int; - } - - if (variable is List) { - if (!(flags & FILTER_REQUIRE_ARRAY != 0 || - flags & FILTER_FORCE_ARRAY != 0) || - flags & FILTER_REQUIRE_SCALAR != 0) { - return (flags & FILTER_NULL_ON_FAILURE != 0) ? null : false; - } - - int subFlags = flags; - if (subFlags & FILTER_FORCE_ARRAY != 0) { - subFlags ^= FILTER_FORCE_ARRAY; - } - if (subFlags & FILTER_REQUIRE_ARRAY != 0) { - subFlags ^= FILTER_REQUIRE_ARRAY; - } - - for (int i = 0; i < variable.length; i++) { - variable[i] = filterVar( - variable[i], filter, {'flags': subFlags, 'options': opts}); - } - - return variable; - } - - if (flags & FILTER_REQUIRE_ARRAY != 0) { - return (flags & FILTER_NULL_ON_FAILURE != 0) ? null : false; - } - - if (variable is! String) { - return (flags & FILTER_FORCE_ARRAY != 0) ? [false] : false; - } - - String variableString = variable; - - switch (filter) { - case FILTER_VALIDATE_BOOLEAN: - return _filterBoolean(variableString, flags); - case FILTER_VALIDATE_EMAIL: - return _filterEmail(variableString, flags); - case FILTER_VALIDATE_FLOAT: - return _filterFloat(variableString, flags); - case FILTER_VALIDATE_INT: - return _filterInt(variableString, flags, opts); - case FILTER_VALIDATE_IP: - return _filterIp(variableString, flags); - case FILTER_VALIDATE_URL: - return _filterUrl(variableString, flags); - case FILTER_VALIDATE_REGEXP: - return _filterRegexp(variableString, flags, opts); - case FILTER_SANITIZE_EMAIL: - return _sanitizeEmail(variableString); - case FILTER_SANITIZE_ENCODED: - return Uri.encodeComponent(variableString); - case FILTER_SANITIZE_MAGIC_QUOTES: - return variableString - .replaceAll("'", "\\'") - .replaceAll('"', '\\"') - .replaceAll('\\', '\\\\'); - case FILTER_SANITIZE_NUMBER_FLOAT: - return _sanitizeNumberFloat(variableString, flags); - case FILTER_SANITIZE_NUMBER_INT: - return variableString.replaceAll(RegExp(r'[^\d-]'), ''); - case FILTER_SANITIZE_SPECIAL_CHARS: - return _sanitizeSpecialChars(variableString, flags); - // FILTER_SANITIZE_STRING and FILTER_SANITIZE_STRIPPED are equivalent - case FILTER_SANITIZE_STRIPPED: - return sanitizeHtml(variableString); - case FILTER_SANITIZE_URL: - return _sanitizeUrl(variableString); - case FILTER_UNSAFE_RAW: - default: - return variableString; - } - } - - /// Filters a string variable to determine its boolean value. - /// - /// This method takes a string [variable] and optional [flags] as input. It - /// checks if the string represents a valid boolean value using the - /// [Validator.isBoolean] method. If the string is a valid boolean, it returns - /// `true` for values like 'true', '1', 'on', or 'yes' (case-insensitive), and - /// `false` otherwise. If the string is not a valid boolean and the - /// [FILTER_NULL_ON_FAILURE] flag is set, it returns `null`. If the flag is not - /// set, it returns `false`. - /// - /// Parameters: - /// - [variable]: The string variable to filter as a boolean. - /// - [flags]: Optional flags to modify the behavior of the filter. - /// - /// Returns: - /// - [bool]: The boolean value of the string, or `null` if the string is not a - /// valid boolean and the [FILTER_NULL_ON_FAILURE] flag is set. - static dynamic _filterBoolean(String variable, int flags) { - if (Validator.isBoolean(variable)) { - return ['true', '1', 'on', 'yes'].contains(variable.toLowerCase()); - } else if (flags & FILTER_NULL_ON_FAILURE != 0) { - return null; - } else { - return false; - } - } - - /// Filters and validates an email address string. - /// - /// This method takes a string [variable] representing an email address and - /// optional [flags] as input. It uses the [EmailValidator] to check if the - /// provided string is a valid email address. - /// - /// Parameters: - /// - [variable]: The string to be validated as an email address. - /// - [flags]: Optional flags to modify the behavior of the filter. - /// - /// Returns: - /// - If the email is valid, it returns the original [variable]. - /// - If the email is invalid and the [FILTER_NULL_ON_FAILURE] flag is set, - /// it returns `null`. - /// - If the email is invalid and the [FILTER_NULL_ON_FAILURE] flag is not set, - /// it returns `false`. - /// - /// The method uses the [EmailValidator.validate] function to perform the - /// email validation. - static dynamic _filterEmail(String variable, int flags) { - if (EmailValidator.validate(variable)) { - return variable; - } else if (flags & FILTER_NULL_ON_FAILURE != 0) { - return null; - } else { - return false; - } - } - - /// Filters and validates a string variable as a float. - /// - /// This method takes a string [variable] and optional [flags] as input. - /// It attempts to parse the string as a float value, considering the - /// provided flags. - /// - /// Parameters: - /// - [variable]: The string to be filtered and validated as a float. - /// - [flags]: Optional flags to modify the behavior of the filter. - /// - /// Returns: - /// - If the string is a valid float, it returns the parsed [double] value. - /// - If the string is not a valid float and the [FILTER_NULL_ON_FAILURE] flag - /// is set, it returns `null`. - /// - If the string is not a valid float and the [FILTER_NULL_ON_FAILURE] flag - /// is not set, it returns `false`. - /// - /// The method trims the input string and, if [FILTER_FLAG_ALLOW_THOUSAND] is set, - /// removes commas from the string before parsing. It uses [Validator.isFloat] - /// to check if the string represents a valid float. - static dynamic _filterFloat(String variable, int flags) { - variable = variable.trim(); - if (flags & FILTER_FLAG_ALLOW_THOUSAND != 0) { - variable = variable.replaceAll(',', ''); - } - if (Validator.isFloat(variable)) { - return double.parse(variable); - } else if (flags & FILTER_NULL_ON_FAILURE != 0) { - return null; - } else { - return false; - } - } - - /// Filters and validates a string variable as an integer. - /// - /// This method takes a string [variable], optional [flags], and [opts] as input. - /// It attempts to parse the string as an integer value, considering the - /// provided flags and options. - /// - /// Parameters: - /// - [variable]: The string to be filtered and validated as an integer. - /// - [flags]: Optional flags to modify the behavior of the filter. - /// - [opts]: A map of additional options, such as 'min_range' and 'max_range'. - /// - /// Returns: - /// - If the string is a valid integer within the specified range (if any), - /// it returns the parsed [int] value. - /// - If the string is not a valid integer or is out of the specified range, - /// and the [FILTER_NULL_ON_FAILURE] flag is set, it returns `null`. - /// - If the string is not a valid integer or is out of the specified range, - /// and the [FILTER_NULL_ON_FAILURE] flag is not set, it returns `false`. - /// - /// The method supports parsing hexadecimal (with '0x' prefix) and octal - /// (with '0' prefix) numbers if the corresponding flags are set. - static dynamic _filterInt( - String variable, int flags, Map opts) { - variable = variable.trim(); - int? value; - - if (flags & FILTER_FLAG_ALLOW_HEX != 0 && - RegExp(r'^0x[0-9a-f]+$', caseSensitive: false).hasMatch(variable)) { - value = int.tryParse(variable.substring(2), radix: 16); - } else if (flags & FILTER_FLAG_ALLOW_OCTAL != 0 && - RegExp(r'^0[0-7]+$').hasMatch(variable)) { - value = int.tryParse(variable.substring(1), radix: 8); - } else { - value = int.tryParse(variable); - } - - if (value != null) { - if (opts.containsKey('min_range') && value < opts['min_range']) { - return (flags & FILTER_NULL_ON_FAILURE != 0) ? null : false; - } - if (opts.containsKey('max_range') && value > opts['max_range']) { - return (flags & FILTER_NULL_ON_FAILURE != 0) ? null : false; - } - return value; - } else if (flags & FILTER_NULL_ON_FAILURE != 0) { - return null; - } else { - return false; - } - } - - /// Filters and validates an IP address string. - /// - /// This method takes a string [variable] representing an IP address and - /// [flags] as input. It validates the IP address based on the provided flags - /// and returns the result. - /// - /// Parameters: - /// - [variable]: The string to be validated as an IP address. - /// - [flags]: Flags to modify the behavior of the filter. - /// - /// Returns: - /// - If the IP is valid and passes all flag checks, it returns the original [variable]. - /// - If the IP is invalid or fails flag checks, and the [FILTER_NULL_ON_FAILURE] flag is set, - /// it returns `null`. - /// - If the IP is invalid or fails flag checks, and the [FILTER_NULL_ON_FAILURE] flag is not set, - /// it returns `false`. - /// - /// The method supports IPv4 and IPv6 validation, and can check for private and reserved IP ranges. - /// Use [FILTER_FLAG_IPV4] and [FILTER_FLAG_IPV6] flags to specify IP version(s) to validate. - /// Use [FILTER_FLAG_NO_PRIV_RANGE] to disallow private IP ranges. - /// Use [FILTER_FLAG_NO_RES_RANGE] to disallow reserved IP ranges. - static dynamic _filterIp(String variable, int flags) { - bool isIPv4 = flags & FILTER_FLAG_IPV4 != 0; - bool isIPv6 = flags & FILTER_FLAG_IPV6 != 0; - - if ((isIPv4 && _isIPv4(variable)) || (isIPv6 && _isIPv6(variable))) { - if (flags & FILTER_FLAG_NO_PRIV_RANGE != 0 && _isPrivateIP(variable)) { - return (flags & FILTER_NULL_ON_FAILURE != 0) ? null : false; - } - if (flags & FILTER_FLAG_NO_RES_RANGE != 0 && _isReservedIP(variable)) { - return (flags & FILTER_NULL_ON_FAILURE != 0) ? null : false; - } - return variable; - } else if (flags & FILTER_NULL_ON_FAILURE != 0) { - return null; - } else { - return false; - } - } - - /// Checks if the given string is a valid IPv4 address. - /// - /// This method uses the [Validator.isIP] function to validate the IP address - /// and additionally checks if it contains a dot (.) to ensure it's IPv4. - /// - /// Parameters: - /// - [ip]: A string representing the IP address to check. - /// - /// Returns: - /// - [bool]: true if the string is a valid IPv4 address, false otherwise. - static bool _isIPv4(String ip) { - return Validator.isIP(ip) && ip.contains('.'); - } - - /// Checks if the given string is a valid IPv6 address. - /// - /// This method uses the [Validator.isIP] function to validate the IP address - /// and additionally checks if it contains a colon (:) to ensure it's IPv6. - /// - /// Parameters: - /// - [ip]: A string representing the IP address to check. - /// - /// Returns: - /// - [bool]: true if the string is a valid IPv6 address, false otherwise. - static bool _isIPv6(String ip) { - return Validator.isIP(ip) && ip.contains(':'); - } - - /// Checks if the given IP address is a private IP address. - /// - /// This method determines whether the provided IP address falls within - /// the ranges reserved for private networks as defined by RFC 1918 for IPv4 - /// and RFC 4193 for IPv6. - /// - /// For IPv4, it checks the following private ranges: - /// - 10.0.0.0 to 10.255.255.255 - /// - 172.16.0.0 to 172.31.255.255 - /// - 192.168.0.0 to 192.168.255.255 - /// - /// For IPv6, it checks if the address starts with 'FD' or 'FC' (case-insensitive), - /// which indicates a Unique Local Address (ULA). - /// - /// Parameters: - /// - [ip]: A string representing the IP address to check. - /// - /// Returns: - /// - [bool]: true if the IP address is private, false otherwise. - /// - /// Note: This method assumes that the input has already been validated as a - /// valid IP address using [_isIPv4] or [_isIPv6]. - static bool _isPrivateIP(String ip) { - if (_isIPv4(ip)) { - List octets = ip.split('.'); - int first = int.parse(octets[0]); - int second = int.parse(octets[1]); - return (first == 10) || - (first == 172 && second >= 16 && second <= 31) || - (first == 192 && second == 168); - } else if (_isIPv6(ip)) { - // For IPv6, we'll check if it starts with FD or FC - return ip.toLowerCase().startsWith('fd') || - ip.toLowerCase().startsWith('fc'); - } - return false; - } - - /// Checks if the given IP address is a reserved IP address. - /// - /// This method determines whether the provided IP address falls within - /// the ranges reserved for special use as defined by various RFCs. - /// - /// For IPv4, it checks the following reserved ranges: - /// - 0.0.0.0 to 0.255.255.255 (Current network) - /// - 127.0.0.0 to 127.255.255.255 (Loopback) - /// - 224.0.0.0 to 255.255.255.255 (Multicast and Reserved) - /// - /// For IPv6, it checks: - /// - Addresses starting with 'FF' (Multicast) - /// - The loopback address '::1' - /// - /// Parameters: - /// - [ip]: A string representing the IP address to check. - /// - /// Returns: - /// - [bool]: true if the IP address is reserved, false otherwise. - /// - /// Note: This method assumes that the input has already been validated as a - /// valid IP address using [_isIPv4] or [_isIPv6]. - static bool _isReservedIP(String ip) { - if (_isIPv4(ip)) { - List octets = ip.split('.'); - int first = int.parse(octets[0]); - return (first == 0) || (first == 127) || (first >= 224 && first <= 255); - } else if (_isIPv6(ip)) { - return ip.toLowerCase().startsWith('ff') || ip == '::1'; - } - return false; - } - - /// Filters and validates a URL string. - /// - /// This method takes a string [variable] representing a URL and optional [flags] - /// as input. It uses the [Validator.isURL] method to check if the provided string - /// is a valid URL. If the URL is valid, it further checks for specific path and - /// query requirements based on the provided flags. - /// - /// Parameters: - /// - [variable]: The string to be validated as a URL. - /// - [flags]: Optional flags to modify the behavior of the filter. - /// - /// Returns: - /// - If the URL is valid and meets all flag requirements, it returns the original [variable]. - /// - If the URL is invalid or doesn't meet flag requirements, and the [FILTER_NULL_ON_FAILURE] - /// flag is set, it returns `null`. - /// - If the URL is invalid or doesn't meet flag requirements, and the [FILTER_NULL_ON_FAILURE] - /// flag is not set, it returns `false`. - /// - /// The method supports the following flags: - /// - [FILTER_FLAG_PATH_REQUIRED]: Requires the URL to have a non-empty path. - /// - [FILTER_FLAG_QUERY_REQUIRED]: Requires the URL to have a non-empty query string. - /// - [FILTER_NULL_ON_FAILURE]: Returns null instead of false on failure. - static dynamic _filterUrl(String variable, int flags) { - if (Validator.isURL(variable)) { - Uri parsedUrl = Uri.parse(variable); - if ((flags & FILTER_FLAG_PATH_REQUIRED != 0 && parsedUrl.path.isEmpty) || - (flags & FILTER_FLAG_QUERY_REQUIRED != 0 && - parsedUrl.query.isEmpty)) { - return (flags & FILTER_NULL_ON_FAILURE != 0) ? null : false; - } - return variable; - } else if (flags & FILTER_NULL_ON_FAILURE != 0) { - return null; - } else { - return false; - } - } - - /// Filters a string variable using a regular expression. - /// - /// This method takes a string [variable], [flags], and [opts] as input. - /// It attempts to match the [variable] against a regular expression - /// provided in the [opts] map. - /// - /// Parameters: - /// - [variable]: The string to be filtered using the regular expression. - /// - [flags]: Optional flags to modify the behavior of the filter. - /// - [opts]: A map of options, which should include a 'regexp' key with - /// a non-empty regular expression string as its value. - /// - /// Returns: - /// - If the regular expression matches the [variable], it returns the original [variable]. - /// - If the regular expression doesn't match, or if 'regexp' is missing from [opts], - /// and the [FILTER_NULL_ON_FAILURE] flag is set, it returns `null`. - /// - If the regular expression doesn't match, or if 'regexp' is missing from [opts], - /// and the [FILTER_NULL_ON_FAILURE] flag is not set, it returns `false`. - /// - /// The method prints a warning if the 'regexp' option is missing from [opts]. - static dynamic _filterRegexp( - String variable, int flags, Map opts) { - if (opts.containsKey('regexp') && opts['regexp'].isNotEmpty) { - if (RegExp(opts['regexp']).hasMatch(variable)) { - return variable; - } - } else { - print("Warning: 'regexp' option missing"); - } - return (flags & FILTER_NULL_ON_FAILURE != 0) ? null : false; - } - - /// Sanitizes an email address string by removing invalid characters. - /// - /// This method takes a [variable] string representing an email address and - /// filters out any characters that are not typically allowed in email addresses. - /// - /// Parameters: - /// - [variable]: The string to be sanitized as an email address. - /// - /// Returns: - /// - A sanitized string containing only valid email address characters. - /// - /// The method uses a predefined set of valid characters including: - /// - Lowercase and uppercase letters (a-z, A-Z) - /// - Numbers (0-9) - /// - Special characters commonly allowed in email addresses: - /// !#$%&'*+-/=?^_`{|}~@.[] - /// - /// Any character not in this set is removed from the input string. - static String _sanitizeEmail(String variable) { - const validChars = - 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#\$%&\'*+-/=?^_`{|}~@.[]'; - return variable - .split('') - .where((char) => validChars.contains(char)) - .join(''); - } - - /// Sanitizes a string representation of a floating-point number. - /// - /// This method takes a [variable] string representing a number and [flags] to - /// control the sanitization process. It removes all characters that are not - /// typically part of a floating-point number representation. - /// - /// Parameters: - /// - [variable]: The string to be sanitized as a floating-point number. - /// - [flags]: Integer flags to control which parts of the number to allow. - /// - /// Returns: - /// - A sanitized string containing only characters valid for the specified - /// floating-point number format. - /// - /// The method supports the following flags: - /// - [FILTER_FLAG_ALLOW_FRACTION]: If set, allows decimal points in the result. - /// - [FILTER_FLAG_ALLOW_THOUSAND]: If set, allows comma as a thousand separator. - /// - [FILTER_FLAG_ALLOW_SCIENTIFIC]: If set, allows 'e' or 'E' for scientific notation. - /// - /// If a flag is not set, the corresponding feature (fraction, thousand separator, - /// or scientific notation) will be removed from the result. - static String _sanitizeNumberFloat(String variable, int flags) { - String result = variable.replaceAll(RegExp(r'[^\d+\-.,eE]'), ''); - if (flags & FILTER_FLAG_ALLOW_FRACTION == 0) { - result = result.replaceAll('.', ''); - } - if (flags & FILTER_FLAG_ALLOW_THOUSAND == 0) { - result = result.replaceAll(',', ''); - } - if (flags & FILTER_FLAG_ALLOW_SCIENTIFIC == 0) { - result = result.replaceAll(RegExp(r'[eE]'), ''); - } - return result; - } - - /// Sanitizes a string by handling special characters based on provided flags. - /// - /// This method takes a [variable] string and a set of [flags] to control - /// how special characters should be handled. It uses [sanitizeHtml] as an - /// initial sanitization step and then applies additional transformations - /// based on the provided flags. - /// - /// Parameters: - /// - [variable]: The string to be sanitized. - /// - [flags]: An integer representing bitwise flags to control sanitization. - /// - /// Returns: - /// - A sanitized string with special characters handled according to the flags. - /// - /// The method supports the following flags: - /// - [FILTER_FLAG_STRIP_LOW]: Removes characters with ASCII values 0-31. - /// - [FILTER_FLAG_STRIP_HIGH]: Removes characters with ASCII values 127-255. - /// - [FILTER_FLAG_ENCODE_LOW]: Encodes characters with ASCII values 0-31 to HTML entities. - /// - [FILTER_FLAG_ENCODE_HIGH]: Encodes characters with ASCII values 127-255 to HTML entities. - /// - [FILTER_FLAG_ENCODE_AMP]: Encodes ampersands to '&'. - /// - [FILTER_FLAG_NO_ENCODE_QUOTES]: Prevents encoding of single and double quotes. - /// - /// Note: This method first applies [sanitizeHtml] and then processes the result - /// based on the provided flags. - static String _sanitizeSpecialChars(String variable, int flags) { - String result = sanitizeHtml(variable); - if (flags & FILTER_FLAG_STRIP_LOW != 0) { - result = result.replaceAll(RegExp(r'[\x00-\x1F]'), ''); - } - if (flags & FILTER_FLAG_STRIP_HIGH != 0) { - result = result.replaceAll(RegExp(r'[\x7F-\xFF]'), ''); - } - if (flags & FILTER_FLAG_ENCODE_LOW != 0) { - result = result.replaceAllMapped( - RegExp(r'[\x00-\x1F]'), (Match m) => '&#${m[0]!.codeUnitAt(0)};'); - } - if (flags & FILTER_FLAG_ENCODE_HIGH != 0) { - result = result.replaceAllMapped( - RegExp(r'[\x7F-\xFF]'), (Match m) => '&#${m[0]!.codeUnitAt(0)};'); - } - if (flags & FILTER_FLAG_ENCODE_AMP != 0) { - result = result.replaceAll('&', '&'); - } - if (flags & FILTER_FLAG_NO_ENCODE_QUOTES != 0) { - result = result.replaceAll(''', "'").replaceAll('"', '"'); - } - return result; - } - - /// Sanitizes a URL string by removing invalid characters. - /// - /// This method takes a [variable] string representing a URL and filters out - /// any characters that are not typically allowed in URLs according to RFC 3986. - /// - /// Parameters: - /// - [variable]: The string to be sanitized as a URL. - /// - /// Returns: - /// - A sanitized string containing only valid URL characters. - /// - /// The method uses a predefined set of valid characters including: - /// - Lowercase and uppercase letters (a-z, A-Z) - /// - Numbers (0-9) - /// - Special characters allowed in URLs: -._~:/?#[]@!$&'()*+,;= - /// - /// Any character not in this set is removed from the input string. - static String _sanitizeUrl(String variable) { - const validChars = - 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~:/?#[]@!\$&\'()*+,;='; - return variable - .split('') - .where((char) => validChars.contains(char)) - .join(''); - } -} diff --git a/packages/http/lib/src/foundation/header_bag.dart b/packages/http/lib/src/foundation/header_bag.dart deleted file mode 100644 index 78632a7..0000000 --- a/packages/http/lib/src/foundation/header_bag.dart +++ /dev/null @@ -1,448 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the symfony HeaderBag.php class to Dart - * - * (C) Protevus - * (C) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'dart:collection'; - -/// HeaderBag is a class that manages HTTP headers. -/// -/// This class provides functionality to store, retrieve, and manipulate HTTP headers. -/// It supports operations such as adding, removing, and checking for the presence of headers, -/// as well as special handling for Cache-Control directives. -/// -/// Key features: -/// - Case-insensitive header names -/// - Support for multiple values per header -/// - Special handling for Cache-Control headers -/// - Methods to add, remove, and check headers -/// - Implements Iterable for easy traversal of headers -/// -/// Usage: -/// ```dart -/// var headers = HeaderBag(); -/// headers.set('Content-Type', 'application/json'); -/// headers.add({'Accept': ['text/html', 'application/xhtml+xml']}); -/// print(headers.get('content-type')); // Prints: application/json -/// ``` -/// -/// This class is particularly useful for HTTP clients and servers that need to -/// manage complex header scenarios, including multiple header values and -/// Cache-Control directives. -class HeaderBag extends IterableBase>> { - - /// A constant string containing uppercase letters and underscore. - /// - /// This constant is used for case-insensitive string operations, - /// particularly in header name formatting. It includes the underscore - /// character followed by all uppercase letters of the English alphabet. - /// - /// The string is defined as: - /// - Underscore: '_' - /// - Uppercase letters: 'A' through 'Z' - /// - /// This constant is typically used in conjunction with the 'lower' constant - /// for case conversion operations within the HeaderBag class. - static const String upper = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - - /// A constant string containing lowercase letters and hyphen. - /// - /// This constant is used for case-insensitive string operations, - /// particularly in header name formatting. It includes the hyphen - /// character followed by all lowercase letters of the English alphabet. - /// - /// The string is defined as: - /// - Hyphen: '-' - /// - Lowercase letters: 'a' through 'z' - /// - /// This constant is typically used in conjunction with the 'upper' constant - /// for case conversion operations within the HeaderBag class. - static const String lower = '-abcdefghijklmnopqrstuvwxyz'; - - /// A map to store the headers. - /// - /// This private field stores all the HTTP headers in the HeaderBag. - /// The keys of the map are header names (stored in lowercase), - /// and the values are lists of header values. - /// - /// Using a list for values allows for multiple values per header, - /// which is common in HTTP headers (e.g., multiple Set-Cookie headers). - /// - /// The use of nullable String (String?) in the list allows for the - /// possibility of null values, which might occur in some edge cases. - final Map> _headers = {}; - - /// A map to store cache control directives. - /// - /// This map holds key-value pairs representing Cache-Control directives. - /// Keys are directive names (e.g., "max-age", "no-cache"), and values are - /// the corresponding directive values or true for valueless directives. - /// - /// This map is used internally to manage and manipulate Cache-Control - /// header information efficiently, allowing for easy addition, removal, - /// and retrieval of individual directives. - final Map _cacheControl = {}; - - /// Constructor for HeaderBag - /// - /// Creates a new HeaderBag instance with the given headers. - /// - /// @param headers An optional map of headers to initialize the HeaderBag with. - /// The map keys are header names, and the values are lists of - /// header values. If not provided, an empty map is used. - /// - /// This constructor initializes the HeaderBag by setting each header in the - /// provided map using the `set` method, which ensures proper formatting and - /// handling of special headers like 'Cache-Control'. - HeaderBag([Map> headers = const {}]) { - headers.forEach((key, values) { - set(key, values); - }); - } - - /// Returns a string representation of the headers. - /// - /// This method creates a formatted string of all headers in the HeaderBag. - /// The headers are sorted alphabetically by key, and each header is - /// presented on a new line with the header name capitalized appropriately. - /// The header names are right-padded to align all header values. - /// - /// If the HeaderBag is empty, an empty string is returned. - /// - /// @return A formatted string representation of all headers. - @override - String toString() { - if (_headers.isEmpty) { - return ''; - } - - var sortedHeaders = SplayTreeMap>.from(_headers); - var max = sortedHeaders.keys.map((k) => k.length).reduce((a, b) => a > b ? a : b) + 1; - var content = StringBuffer(); - - for (var entry in sortedHeaders.entries) { - var name = entry.key.replaceAllMapped(RegExp(r'-([a-z])'), (match) => '-${match.group(1)!.toUpperCase()}'); - for (var value in entry.value) { - content.write('${name.padRight(max)}: $value\r\n'); - } - } - - return content.toString(); - } - - /// Returns all headers or headers for a specific key. - /// - /// If a [key] is provided, this method returns a map containing only that key - /// (in lowercase) and its associated list of values. If the key doesn't exist, - /// an empty list is returned for that key. - /// - /// If no [key] is provided, this method returns all headers in the HeaderBag. - /// - /// @param key The optional key to retrieve specific headers. - /// @return A map of headers. If a key is provided, the map will contain only - /// that key-value pair. If no key is provided, all headers are returned. - Map> all([String? key]) { - if (key != null) { - return {key.toLowerCase(): _headers[key.toLowerCase()] ?? []}; - } - return _headers; - } - - /// Returns the parameter keys. - /// - /// This method retrieves all the keys from the internal _headers map - /// and returns them as a list of strings. The keys represent the names - /// of all the headers stored in this HeaderBag. - /// - /// @return A list of strings containing all the header names. - List keys() { - return _headers.keys.toList(); - } - - /// Replaces the current HTTP headers with a new set of headers. - /// - /// This method first clears all existing headers in the HeaderBag, - /// then adds the new headers provided in the [headers] parameter. - /// - /// @param headers A map of new headers to replace the existing ones. - /// The map keys are header names, and the values are - /// lists of header values. - void replace(Map> headers) { - _headers.clear(); - add(headers); - } - - /// Adds new headers to the current HTTP headers set. - /// - /// This method takes a map of headers and adds them to the existing headers - /// in the HeaderBag. If a header with the same name already exists, its values - /// are appended to the existing values. - /// - /// @param headers A map where keys are header names and values are lists of - /// header values to be added. - /// - /// Each header in the input map is added using the `set` method, which handles - /// the details of appending values and updating special headers like 'Cache-Control'. - void add(Map> headers) { - headers.forEach((key, values) { - set(key, values); - }); - } - - /// Returns the first value of the specified HTTP header. - /// - /// This method retrieves the first value of the header specified by [key]. - /// If the header doesn't exist or has no values, it returns the [defaultValue]. - /// - /// @param key The name of the HTTP header to retrieve. - /// @param defaultValue An optional default value to return if the header - /// doesn't exist or has no values. Defaults to null if not specified. - /// @return The first value of the specified header, or the default value - /// if the header doesn't exist or has no values. - String? get(String key, [String? defaultValue]) { - var headers = all(key)[key.toLowerCase()]; - if (headers == null || headers.isEmpty) { - return defaultValue; - } - return headers[0]; - } - - /// Sets a header by name. - /// - /// This method sets or adds a header to the HeaderBag. It can handle both - /// single values and lists of values. - /// - /// @param key The name of the header to set. This will be converted to lowercase. - /// @param values The value or list of values to set for the header. - /// @param replace Whether to replace the existing values (if any) or append to them. - /// Defaults to true. - /// - /// If [replace] is true or the header doesn't exist, it will overwrite any existing - /// values. If [replace] is false and the header exists, it will append the new values. - /// - /// For the 'cache-control' header, this method also updates the internal - /// cache control directives by parsing the new header value. - void set(String key, dynamic values, [bool replace = true]) { - key = key.toLowerCase(); - List valueList; - - if (values is List) { - valueList = List.from(values); - if (replace || !_headers.containsKey(key)) { - _headers[key] = valueList; - } else { - _headers[key] = List.from(_headers[key]!)..addAll(valueList); - } - } else { - if (replace || !_headers.containsKey(key)) { - _headers[key] = [values]; - } else { - _headers[key]!.add(values); - } - } - - if (key == 'cache-control') { - _cacheControl.addAll(_parseCacheControl(_headers[key]!.join(', '))); - } - } - - /// Checks if a specific HTTP header is present in the HeaderBag. - /// - /// This method determines whether a header with the given [key] exists - /// in the HeaderBag. The header name (key) is case-insensitive. - /// - /// @param key The name of the HTTP header to check for. - /// @return true if the header exists, false otherwise. - bool hasHeader(String key) { - return _headers.containsKey(key.toLowerCase()); - } - - /// Checks if a specific HTTP header contains a given value. - /// - /// This method determines whether the header specified by [key] contains - /// the given [value]. The header name (key) is case-insensitive. - /// - /// @param key The name of the HTTP header to check. - /// @param value The value to search for in the header. - /// @return true if the header contains the value, false otherwise. - /// If the header doesn't exist, this method returns false. - bool containsHeaderValue(String key, String value) { - return _headers[key.toLowerCase()]?.contains(value) ?? false; - } - - /// Removes a header from the HeaderBag. - /// - /// This method removes the header specified by [key] from the HeaderBag. - /// The key is case-insensitive and will be converted to lowercase before removal. - /// - /// If the removed header is 'cache-control', this method also clears - /// the internal cache control directives. - /// - /// @param key The name of the header to remove. - void remove(String key) { - key = key.toLowerCase(); - _headers.remove(key); - if (key == 'cache-control') { - _cacheControl.clear(); - } - } - - /// Returns the HTTP header value converted to a date. - /// - /// This method retrieves the value of the specified HTTP header and attempts - /// to parse it as a DateTime object. If the header doesn't exist or its value - /// is null, the method returns the provided default value. - /// - /// @param key The name of the HTTP header to retrieve and parse as a date. - /// @param defaultValue An optional DateTime object to return if the header - /// doesn't exist or its value is null. Defaults to null if not specified. - /// @return A DateTime object representing the parsed header value, or the - /// default value if the header doesn't exist or its value is null. - /// @throws Exception if the header value cannot be parsed as a valid date. - /// - /// Throws an exception when the HTTP header is not parseable. - DateTime? getDate(String key, [DateTime? defaultValue]) { - var value = get(key); - if (value == null) { - return defaultValue; - } - - try { - return DateTime.parse(value); - } catch (e) { - throw Exception('The "$key" HTTP header is not parseable ($value).'); - } - } - - /// Adds a custom Cache-Control directive. - /// - /// This method adds a new directive to the Cache-Control header or updates - /// an existing one. The directive is specified by [key], and an optional - /// [value] can be provided. - /// - /// @param key The name of the Cache-Control directive to add or update. - /// @param value The value of the directive. Defaults to true if not specified. - /// - /// After updating the internal cache control directives, this method - /// regenerates the Cache-Control header string and sets it using the `set` method. - void addCacheControlDirective(String key, [dynamic value = true]) { - _cacheControl[key] = value; - set('Cache-Control', getCacheControlHeader()); - } - - /// Checks if a specific Cache-Control directive is present. - /// - /// This method determines whether a Cache-Control directive with the given [key] - /// exists in the internal cache control directives map. - /// - /// @param key The name of the Cache-Control directive to check for. - /// @return true if the directive exists, false otherwise. - bool hasCacheControlDirective(String key) { - return _cacheControl.containsKey(key); - } - - /// Returns the value of a specific Cache-Control directive. - /// - /// This method retrieves the value associated with the given Cache-Control - /// directive [key] from the internal cache control directives map. - /// - /// @param key The name of the Cache-Control directive to retrieve. - /// @return The value of the specified Cache-Control directive, or null if - /// the directive doesn't exist. The return type is dynamic as - /// Cache-Control directive values can be of various types. - dynamic getCacheControlDirective(String key) { - return _cacheControl[key]; - } - - /// Removes a Cache-Control directive. - /// - /// This method removes the specified Cache-Control directive from the internal - /// cache control directives map and updates the Cache-Control header accordingly. - /// - /// @param key The name of the Cache-Control directive to remove. - /// - /// After removing the directive from the internal map, this method regenerates - /// the Cache-Control header string and sets it using the `set` method. - void removeCacheControlDirective(String key) { - _cacheControl.remove(key); - set('Cache-Control', getCacheControlHeader()); - } - - /// Returns an iterator for the headers. - /// - /// This method provides an iterator that allows iteration over all headers - /// in the HeaderBag. Each iteration yields a MapEntry where the key is the - /// header name (as a String) and the value is a List of String? representing - /// the header values. - /// - /// This implementation directly returns the iterator of the internal _headers - /// map entries, allowing for efficient iteration over all headers. - /// - /// @return An Iterator>> for iterating over - /// all headers in the HeaderBag. - @override - Iterator>> get iterator { - return _headers.entries.iterator; - } - - /// Returns the number of headers. - /// - /// This getter provides the count of unique headers in the HeaderBag. - /// It directly returns the length of the internal _headers map, - /// which represents the number of distinct header names stored. - /// - /// @return An integer representing the number of headers in the HeaderBag. - @override - int get length { - return _headers.length; - } - - /// Generates the Cache-Control header value. - /// - /// This method creates a string representation of the Cache-Control header - /// based on the directives stored in the internal _cacheControl map. - /// - /// The method performs the following steps: - /// 1. Creates a sorted copy of the _cacheControl map using a SplayTreeMap. - /// 2. Iterates through the entries of the sorted map. - /// 3. Formats each entry as "key=value". - /// 4. Joins all formatted entries with ", " as separator. - /// - /// @return A string representation of the Cache-Control header, where - /// directives are sorted alphabetically by key and separated by commas. - /// For example: "max-age=300, must-revalidate, no-cache". - String getCacheControlHeader() { - var sortedCacheControl = SplayTreeMap.from(_cacheControl); - return sortedCacheControl.entries.map((e) => '${e.key}=${e.value}').join(', '); - } - - /// Parses a Cache-Control HTTP header string into a map of directives. - /// - /// This method takes a Cache-Control header value as a string and converts it - /// into a map where keys are directive names and values are directive values. - /// - /// The method performs the following steps: - /// 1. Splits the header string by commas to separate individual directives. - /// 2. For each directive, splits by '=' to separate the name and value. - /// 3. Trims whitespace from directive names and values. - /// 4. If a directive has no value (no '='), it's set to true. - /// - /// @param header A string containing the Cache-Control header value. - /// @return A Map where keys are directive names (String) - /// and values are either String (for directives with values) or - /// bool (true for directives without values). - Map _parseCacheControl(String header) { - var parts = header.split(',').map((e) => e.split('=')).toList(); - var map = {}; - for (var part in parts) { - map[part[0].trim()] = part.length > 1 ? part[1].trim() : true; - } - return map; - } -} diff --git a/packages/http/lib/src/foundation/header_utils.dart b/packages/http/lib/src/foundation/header_utils.dart deleted file mode 100644 index 4cca83d..0000000 --- a/packages/http/lib/src/foundation/header_utils.dart +++ /dev/null @@ -1,434 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the symfony HeaderUtils.php class to Dart - * - * (C) Protevus - * (C) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'dart:convert'; - -class HeaderUtils { - - /// A constant string representing the "attachment" disposition type. - /// - /// This value is used in HTTP headers, particularly in the Content-Disposition - /// header, to indicate that the content is expected to be downloaded and saved - /// locally by the user agent, rather than being displayed inline in the browser. - static const String DISPOSITION_ATTACHMENT = 'attachment'; - - /// A constant string representing the "inline" disposition type. - /// - /// This value is used in HTTP headers, particularly in the Content-Disposition - /// header, to indicate that the content is expected to be displayed inline - /// in the browser, rather than being downloaded and saved locally. - static const String DISPOSITION_INLINE = 'inline'; - - /// Private constructor to prevent instantiation of the HeaderUtils class. - /// - /// This class is intended to be used as a utility class with static methods only. - /// The underscore before the constructor name makes it private to this library. - HeaderUtils._(); - - /// Splits an HTTP header by one or more separators. - /// - /// This method parses a given HTTP header string and splits it into parts - /// based on the provided separators. It handles quoted strings and tokens - /// according to HTTP header specifications. - /// - /// Parameters: - /// - [header]: The HTTP header string to be split. - /// - [separators]: A string containing one or more separator characters. - /// - /// Returns: - /// A List of Lists of Strings, where each inner List represents a part of - /// the header split by the separators. - /// - /// Throws: - /// - [ArgumentError] if [separators] is empty. - /// - /// Example: - /// HeaderUtils.split('da, en-gb;q=0.8', ',;') - /// // => [['da'], ['en-gb', 'q=0.8']] - /// - /// The method uses regular expressions to handle complex cases such as - /// quoted strings and multiple separators. It preserves the structure of - /// the original header while splitting it into logical parts. - static List> split(String header, String separators) { - if (separators.isEmpty) { - throw ArgumentError('At least one separator must be specified.'); - } - - final quotedSeparators = RegExp.escape(separators); - - final pattern = ''' - (?!\\s) - (?: - # quoted-string - "(?:[^"\\\\]|\\\\.)*(?:"|\\\\|)" - | - # token - [^"$quotedSeparators]+ - )+ - (?[$quotedSeparators]) - \\s* - '''; - - final matches = RegExp(pattern, multiLine: true, dotAll: true, caseSensitive: false) - .allMatches(header.trim()) - .toList(); - - return _groupParts(matches, separators); - } - - /// Combines an array of arrays into one associative array. - /// - /// Each of the nested arrays should have one or two elements. The first - /// value will be used as the keys in the associative array, and the second - /// will be used as the values, or true if the nested array only contains one - /// element. Array keys are lowercased. - /// - /// Parameters: - /// - [parts]: A List of Lists of Strings, where each inner List represents a part - /// to be combined into the associative array. - /// - /// Returns: - /// A Map where the keys are the lowercased first elements of each - /// inner List, and the values are either the second elements or true if there's no - /// second element. - /// - /// Example: - /// HeaderUtils.combine([['foo', 'abc'], ['bar']]) - /// // => {'foo': 'abc', 'bar': true} - static Map combine(List> parts) { - final assoc = {}; - for (var part in parts) { - final name = part[0].toLowerCase(); - final value = part.length > 1 ? part[1] : true; - assoc[name] = value; - } - return assoc; - } - - /// Joins an associative array into a string for use in an HTTP header. - /// - /// This method takes a Map of key-value pairs and joins them into a single string, - /// suitable for use in an HTTP header. Each key-value pair is formatted as follows: - /// - If the value is `true`, only the key is included. - /// - Otherwise, the pair is formatted as "key=value", where the value is quoted if necessary. - /// - /// The formatted pairs are then joined with the specified separator and an additional space. - /// - /// Parameters: - /// - [assoc]: A Map containing the key-value pairs to be joined. - /// - [separator]: A String used to separate the formatted pairs in the output. - /// - /// Returns: - /// A String representing the joined key-value pairs, suitable for use in an HTTP header. - /// - /// Example: - /// HeaderUtils.headerToString({'foo': 'abc', 'bar': true, 'baz': 'a b c'}, ',') - /// // => 'foo=abc, bar, baz="a b c"' - static String headerToString(Map assoc, String separator) { - final parts = []; - assoc.forEach((name, value) { - if (value == true) { - parts.add(name); - } else { - parts.add('$name=${quote(value.toString())}'); - } - }); - return parts.join('$separator '); - } - - /// Quotes a string for use in HTTP headers if necessary. - /// - /// This method takes a string and determines whether it needs to be quoted - /// for use in HTTP headers. If quoting is necessary, it encloses the string - /// in double quotes and escapes any existing double quotes within the string. - /// - /// Parameters: - /// - [s]: The input string to be quoted if necessary. - /// - /// Returns: - /// A String that is either: - /// - The original string if it doesn't need quoting - /// - The string enclosed in double quotes with internal quotes escaped - /// - An empty quoted string ('""') if the input is an empty string - /// - /// Throws: - /// - [ArgumentError] if the input string is null. - /// - /// Example: - /// quote('simple') // => 'simple' - /// quote('needs "quotes"') // => '"needs \"quotes\""' - /// quote('') // => '""' - static String quote(String? s) { - if (s == null) { - throw ArgumentError('Input string cannot be null'); - } - - if (s.isEmpty) { - return '""'; - } - - final isQuotingAllowed = _isQuotingAllowed(s); - - if (!isQuotingAllowed) { - return '"${s.replaceAll('"', '\\"')}"'; - } - - return s; -} - -/// Determines if a string can be used unquoted in HTTP headers. -/// -/// This method checks if the given string consists only of characters -/// that are allowed in unquoted header values according to HTTP specifications. -/// -/// Parameters: -/// - [s]: The string to be checked. -/// -/// Returns: -/// - `true` if the string can be used unquoted in HTTP headers. -/// - `false` if the string needs to be quoted for use in HTTP headers. -/// -/// The allowed characters are: -/// - Alphanumeric characters (a-z, A-Z, 0-9) -/// - The following special characters: !#$%&'*+-\.^_`|~ -/// -/// This method is typically used internally by other header-related functions -/// to determine whether a value needs quoting before being included in an HTTP header. -static bool _isQuotingAllowed(String s) { - final pattern = RegExp('^[a-zA-Z0-9!#\$%&\'*+\\-\\.^_`|~]+\$'); - return pattern.hasMatch(s); -} - - /// Removes quotes and unescapes characters in a string. - /// - /// This method processes a string that may have been quoted or contain - /// escaped characters. It performs the following operations: - /// 1. Removes surrounding double quotes if present. - /// 2. Unescapes any escaped characters (i.e., removes the backslash). - /// - /// Parameters: - /// - [s]: The input string to be unquoted and unescaped. - /// - /// Returns: - /// A String with quotes removed and escaped characters processed. - /// - /// Example: - /// unquote('"Hello \\"World\\""') // => 'Hello "World"' - /// unquote('No \\"quotes\\"') // => 'No "quotes"' - static String unquote(String s) { - return s.replaceAllMapped(RegExp(r'\\(.)|\"'), (match) => match[1] ?? ''); - } - - /// Generates an HTTP Content-Disposition header value. - /// - /// This method creates a properly formatted Content-Disposition header value - /// based on the given disposition type and filename. It supports both ASCII - /// and non-ASCII filenames, providing a fallback for older user agents. - /// - /// Parameters: - /// - [disposition]: The disposition type, must be either "attachment" or "inline". - /// - [filename]: The filename to be used in the Content-Disposition header. - /// - [filenameFallback]: An optional ASCII-only fallback filename for older user agents. - /// If not provided, it defaults to the same value as [filename]. - /// - /// Returns: - /// A String representing the formatted Content-Disposition header value. - /// - /// Throws: - /// - [ArgumentError] if: - /// - The disposition is neither "attachment" nor "inline". - /// - The filename fallback contains non-ASCII characters. - /// - The filename fallback contains the "%" character. - /// - Either filename or fallback contains "/" or "\" characters. - /// - /// @see RFC 6266 - /// - /// Example: - /// makeDisposition('attachment', 'example.pdf') - /// // => 'attachment; filename="example.pdf"' - /// - /// makeDisposition('inline', 'résumé.pdf', 'resume.pdf') - /// // => 'inline; filename="resume.pdf"; filename*=utf-8\'\'r%C3%A9sum%C3%A9.pdf' - static String makeDisposition(String disposition, String filename, [String filenameFallback = '']) { - if (![DISPOSITION_ATTACHMENT, DISPOSITION_INLINE].contains(disposition)) { - throw ArgumentError('The disposition must be either "$DISPOSITION_ATTACHMENT" or "$DISPOSITION_INLINE".'); - } - - filenameFallback = filenameFallback.isEmpty ? filename : filenameFallback; - - if (!RegExp(r'^[\x20-\x7e]*$').hasMatch(filenameFallback)) { - throw ArgumentError('The filename fallback must only contain ASCII characters.'); - } - - if (filenameFallback.contains('%')) { - throw ArgumentError('The filename fallback cannot contain the "%" character.'); - } - - if (filename.contains('/') || filename.contains('\\') || filenameFallback.contains('/') || filenameFallback.contains('\\')) { - throw ArgumentError('The filename and the fallback cannot contain the "/" and "\\" characters.'); - } - - final params = {'filename': filenameFallback}; - if (filename != filenameFallback) { - params['filename*'] = "utf-8''${Uri.encodeComponent(filename)}"; - } - - return '$disposition; ${headerToString(params, ';')}'; - } - -/// Like parse_str(), but preserves dots in variable names. -/// Parses a query string into a Map of key-value pairs. -/// -/// This method takes a query string and converts it into a Map where the keys -/// are the query parameters and the values are their corresponding values. -/// -/// Parameters: -/// - [query]: The query string to parse. -/// - [ignoreBrackets]: If true, treats square brackets as part of the parameter name. -/// Defaults to false. -/// - [separator]: The character used to separate key-value pairs in the query string. -/// Defaults to '&'. -/// -/// Returns: -/// A Map where keys are the parameter names and values are the -/// corresponding parameter values. -/// -/// If [ignoreBrackets] is false (default), the method handles parameters with square -/// brackets specially, decoding them from base64 and including the bracket content -/// in the resulting key. -/// -/// Example: -/// parseQuery('foo=bar&baz=qux') -/// // => {'foo': 'bar', 'baz': 'qux'} -/// -/// parseQuery('foo[]=bar&foo[]=baz', false, '&') -/// // => {'foo[]': 'bar', 'foo[]': 'baz'} -/// -/// Note: This method includes some specific handling for the character '0' in keys -/// and values, truncating strings at this character. It also trims whitespace from -/// the left side of keys. This is like parse_str(), but preserves dots in variable names. -static Map parseQuery(String query, [bool ignoreBrackets = false, String separator = '&']) { - final result = {}; - - if (ignoreBrackets) { - for (var item in query.split(separator)) { - var parts = item.split('='); - result[parts[0]] = Uri.decodeComponent(parts[1]); - } - return result; - } - - for (var v in query.split(separator)) { - var i = v.indexOf('0'); - if (i != -1) { - v = v.substring(0, i); - } - - i = v.indexOf('='); - String k; - if (i == -1) { - k = Uri.decodeComponent(v); - v = ''; - } else { - k = Uri.decodeComponent(v.substring(0, i)); - v = v.substring(i + 1); - } - - i = k.indexOf('0'); - if (i != -1) { - k = k.substring(0, i); - } - - k = k.trimLeft(); - - i = k.indexOf('['); - if (i == -1) { - result[utf8.decode(base64.decode(k))] = Uri.decodeComponent(v); - } else { - result['${utf8.decode(base64.decode(k.substring(0, i)))}[${Uri.decodeComponent(k.substring(i + 1))}]'] = Uri.decodeComponent(v); - } - } - - return result; -} - - /// Groups parts of a header string based on specified separators. - /// - /// This recursive method processes a list of [RegExpMatch] objects, grouping them - /// based on the provided [separators]. It handles nested structures in header strings. - /// - /// Parameters: - /// - [matches]: A list of [RegExpMatch] objects representing parts of the header. - /// - [separators]: A string containing characters used as separators. - /// - [first]: A boolean indicating if this is the first call in the recursion (default: true). - /// - /// Returns: - /// A List of Lists of Strings, where each inner List represents a grouped part of the header. - /// - /// The method works by: - /// 1. Splitting the parts based on the first separator in the [separators] string. - /// 2. Recursively processing subgroups if more separators are available. - /// 3. Handling special cases for the last separator and quoted strings. - /// - /// This method is typically used internally by the [split] method to process complex - /// header structures with multiple levels of separators. - static List> _groupParts(List matches, String separators, [bool first = true]) { - final separator = separators[0]; - separators = separators.substring(1); - var i = 0; - - if (separators.isEmpty && !first) { - final parts = ['']; - - for (var match in matches) { - if (i == 0 && match.namedGroup('separator') != null) { - i = 1; - parts.add(''); - } else { - parts[i] += unquote(match[0]!); - } - } - - return [parts]; - } - - final parts = >[]; - final partMatches = >{}; - - for (var match in matches) { - if (match.namedGroup('separator') == separator) { - i++; - } else { - partMatches.putIfAbsent(i, () => []).add(match); - } - } - - for (var subMatches in partMatches.values) { - if (separators.isEmpty) { - final unquoted = unquote(subMatches[0][0]!); - if (unquoted.isNotEmpty) { - parts.add([unquoted]); - } - } else { - final groupedParts = _groupParts(subMatches, separators, false); - if (groupedParts.isNotEmpty) { - parts.add(groupedParts.expand((element) => element).toList()); - } - } - } - - return parts; - } -} diff --git a/packages/http/lib/src/foundation/input_bag.dart b/packages/http/lib/src/foundation/input_bag.dart deleted file mode 100644 index c00cbcd..0000000 --- a/packages/http/lib/src/foundation/input_bag.dart +++ /dev/null @@ -1,238 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the symfony InputBag.php class to Dart - * - * (C) Protevus - * (C) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'dart:collection'; - -import 'package:protevus_http/foundation.dart'; -import 'package:protevus_http/foundation_exception.dart'; - -/// InputBag is an abstract class that extends ParameterBag to handle user input values. -/// It provides methods for getting, setting, and filtering input parameters. -/// -/// Key features: -/// - Retrieves scalar input values by name -/// - Replaces or adds new input values -/// - Sets input values with type checking -/// - Converts parameter values to enums -/// - Filters and transforms parameter values -/// -/// This class implements type-safe operations and throws appropriate exceptions -/// for invalid inputs or operations. It's designed to work with various types of -/// input data such as GET, POST, REQUEST, and COOKIE parameters. -final class InputBag extends ParameterBag - with IterableMixin> { - /// Retrieves a value from the input bag by its key. - /// - /// This method overrides the base [ParameterBag.get] method to add additional - /// type checking for both the default value and the retrieved value. - /// - /// Parameters: - /// - [key]: The key of the value to retrieve. - /// - [defaultValue]: The default value to return if the key is not found. - /// Must be a scalar value (num, String, bool) or implement [Stringable]. - /// - /// Returns: - /// The value associated with the key, or the default value if the key is not found. - /// - /// Throws: - /// - [FormatException]: If the default value is not a scalar or [Stringable]. - /// - [BadRequestException]: If the input value is not a scalar or [Stringable]. - @override - dynamic get(String key, [dynamic defaultValue]) { - if (defaultValue != null && - !(defaultValue is num || - defaultValue is String || - defaultValue is bool || - defaultValue is Stringable)) { - throw FormatException( - 'Expected a scalar value as a 2nd argument to "get()", "${defaultValue.runtimeType}" given.'); - } - - var value = super.get(key, this); - - if (value != null && - identical(this, value) == false && - !(value is num || - value is String || - value is bool || - value is Stringable)) { - throw BadRequestException( - 'Input value "$key" contains a non-scalar value.'); - } - - return identical(this, value) ? defaultValue : value; - } - - /// Replaces the current input values with a new set of inputs. - /// - /// This method overrides the base [ParameterBag.replace] method. - /// Instead of directly replacing the parameters, it uses the [add] method - /// to set the new input values, which ensures that each input is properly - /// validated and set according to the rules defined in the [set] method. - /// - /// Parameters: - /// - [inputs]: A Map containing the new input values to replace the current ones. - @override - void replace(Map inputs) { - add(inputs); - } - - /// Adds multiple input values to the InputBag. - /// - /// This method overrides the base [ParameterBag.add] method. - /// It iterates through the provided map of inputs and sets each key-value pair - /// using the [set] method, which ensures that each input is properly - /// validated and set according to the rules defined in the [set] method. - /// - /// Parameters: - /// - [inputs]: A Map containing the input values to be added to the InputBag. - @override - void add(Map inputs) { - for (final entry in inputs.entries) { - set(entry.key, entry.value); - } - } - - /// Sets an input value in the InputBag. - /// - /// This method overrides the base [ParameterBag.set] method to add additional - /// type checking for the input value. - /// - /// Parameters: - /// - [key]: The key under which to store the value. - /// - [value]: The value to store. Must be null, a scalar (num, String, bool), - /// a List, a Map, or implement [Stringable]. - /// - /// Throws: - /// - [FormatException]: If the value is not null, a scalar, List, Map, or [Stringable]. - /// - /// The method sets the value in the [parameters] map after successful validation. - @override - void set(String key, dynamic value) { - if (value != null && - !(value is num || - value is String || - value is bool || - value is List || - value is Map || - value is Stringable)) { - throw FormatException( - 'Expected a scalar, List, or Map as a 2nd argument to "set()", "${value.runtimeType}" given.'); - } - - parameters[key] = value; - } - - /// Returns the parameter value converted to an enum. - /// - /// This method attempts to convert the parameter value associated with [key] to an enum - /// of type [T]. The [values] list should contain all possible enum values. - /// - /// Parameters: - /// - [key]: The key of the parameter to retrieve and convert. - /// - [values]: A list of all possible enum values of type [T]. - /// - [defaultValue]: An optional default value to return if the key is not found. - /// - /// Returns: - /// The enum value corresponding to the parameter value, or [defaultValue] if the key is not found. - /// - /// Throws: - /// - [BadRequestException]: If the parameter value cannot be converted to the specified enum. - /// This exception wraps the original [UnexpectedValueException] thrown by the superclass. - @override - T? getEnum(String key, List values, [T? defaultValue]) { - try { - return super.getEnum(key, values, defaultValue); - } on UnexpectedValueException catch (e) { - throw BadRequestException(e.toString()); - } - } - - /// Retrieves a string value from the input bag by its key. - /// - /// This method overrides the base [ParameterBag.getString] method. - /// It retrieves the value associated with the given [key] and converts it to a string. - /// - /// Parameters: - /// - [key]: The key of the value to retrieve. - /// - [defaultValue]: The default value to return if the key is not found. Defaults to an empty string. - /// - /// Returns: - /// A string representation of the value associated with the key, or the default value if the key is not found. - @override - String getString(String key, [String defaultValue = '']) { - return get(key, defaultValue).toString(); - } - - /// Filters and transforms a parameter value. - /// - /// This method retrieves a value from the input parameters and applies a specified filter to it. - /// - /// Parameters: - /// - [key]: The key of the parameter to filter. - /// - [defaultValue]: The default value to use if the key is not found in the parameters. - /// - [filter]: An optional integer representing the filter to apply. If null, [Filter.defaultFilter] is used. - /// - [options]: Additional options for the filter. Can be a Map or an integer representing flags. - /// - /// Returns: - /// The filtered value, or null if the filtering fails and the FILTER_NULL_ON_FAILURE flag is set. - /// - /// Throws: - /// - [BadRequestException]: If the input value is a List and neither FILTER_REQUIRE_ARRAY nor FILTER_FORCE_ARRAY flags are set. - /// - [FormatException]: If FILTER_CALLBACK is used without providing a proper callback function. - /// - [BadRequestException]: If the input value is invalid and the FILTER_NULL_ON_FAILURE flag is not set. - /// - /// This method handles various scenarios: - /// - Converts options to a Map if it's not already one. - /// - Checks for List inputs and appropriate flags. - /// - Validates the callback function when FILTER_CALLBACK is used. - /// - Applies the filter using [Filter.filterVar]. - /// - Handles the FILTER_NULL_ON_FAILURE flag. - @override - dynamic filter(String key, - {dynamic defaultValue, int? filter, dynamic options}) { - var value = has(key) ? parameters[key] : defaultValue; - - // Always turn options into a Map - this allows filter_var option shortcuts. - if (options is! Map && options != null) { - options = {'flags': options}; - } - options ??= {}; - - if (value is List && - !((options['flags'] ?? 0) & - (Filter.FILTER_REQUIRE_ARRAY | Filter.FILTER_FORCE_ARRAY))) { - throw BadRequestException( - 'Input value "$key" contains a List, but "FILTER_REQUIRE_ARRAY" or "FILTER_FORCE_ARRAY" flags were not set.'); - } - - if ((filter ?? 0) & Filter.FILTER_CALLBACK != 0 && - options['options'] is! Function) { - throw FormatException( - 'A Function must be passed when FILTER_CALLBACK is used, "${options['options'].runtimeType}" given.'); - } - - options['flags'] ??= 0; - bool nullOnFailure = - (options['flags'] & Filter.FILTER_NULL_ON_FAILURE) != 0; - options['flags'] |= Filter.FILTER_NULL_ON_FAILURE; - - var filteredValue = - Filter.filterVar(value, filter ?? Filter.FILTER_DEFAULT, options); - - if (filteredValue != null || nullOnFailure) { - return filteredValue; - } - - throw BadRequestException( - 'Input value "$key" is invalid and flag "FILTER_NULL_ON_FAILURE" was not set.'); - } -} diff --git a/packages/http/lib/src/foundation/parameter_bag.dart b/packages/http/lib/src/foundation/parameter_bag.dart deleted file mode 100644 index 2451781..0000000 --- a/packages/http/lib/src/foundation/parameter_bag.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:protevus_http/foundation.dart'; - -abstract class ParameterBag extends ParameterBagBase { - @override - final Map parameters; - - ParameterBag([Map initialParameters = const {}]) - : parameters = Map.from(initialParameters); - - @override - void replace(Map parameters) { - parameters.clear(); - parameters.addAll(parameters); - } - - @override - void add(Map parameters) { - parameters.addAll(parameters); - } - - @override - void set(String key, dynamic value) { - parameters[key] = value; - } - - @override - void remove(String key) { - parameters.remove(key); - } -} diff --git a/packages/http/lib/src/foundation/parameter_bag_base.dart b/packages/http/lib/src/foundation/parameter_bag_base.dart deleted file mode 100644 index 6c5d83d..0000000 --- a/packages/http/lib/src/foundation/parameter_bag_base.dart +++ /dev/null @@ -1,428 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the symfony ParameterBag.php class to Dart - * - * (C) Protevus - * (C) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'package:protevus_http/foundation.dart'; -import 'package:protevus_http/foundation_exception.dart'; - -/// ParameterBag is an abstract container for key/value pairs. -/// It implements Iterable> and Countable interfaces. -abstract class ParameterBagBase - implements Iterable>, Countable { - /// The underlying map containing the parameters. - /// - /// This getter provides access to the internal map that stores all the key-value pairs - /// of parameters. The keys are of type [String], and the values can be of any type, - /// hence [dynamic]. - /// - /// This map is the core data structure of the ParameterBag, allowing for storage and - /// retrieval of various parameters used throughout the application. - Map get parameters; - - /// Returns all parameters or a specific nested parameter. - /// - /// If [key] is null, this method returns all parameters as a [Map]. - /// If [key] is provided, it returns the value associated with that key, which must be - /// a [Map]. If the value is not a Map, it throws a [BadRequestException]. - /// - /// Parameters: - /// [key] - Optional. The key of the nested parameter to retrieve. - /// - /// Returns: - /// A [Map] containing either all parameters or the nested parameter. - /// - /// Throws: - /// [BadRequestException] if the value for the given key is not a Map. - Map all([String? key]) { - if (key == null) { - return parameters; - } - - final value = parameters[key]; - if (value is! Map) { - throw BadRequestException( - 'Unexpected value for parameter "$key": expecting "Map", got "${value.runtimeType}".'); - } - - return value; - } - - /// Returns a list of all parameter keys. - /// - /// This method retrieves all the keys from the [parameters] map and returns them - /// as a [List]. This can be useful when you need to iterate over or - /// inspect all the keys in the parameter bag without accessing their values. - /// - /// Returns: - /// A [List] containing all the keys from the parameters map. - List keys() { - return parameters.keys.toList(); - } - - /// Replaces the current parameters with a new set of parameters. - /// - /// This method completely replaces the existing parameters in the ParameterBag - /// with the new parameters provided in the [parameters] argument. - /// - /// Parameters: - /// [parameters] - A Map containing the new set of parameters - /// that will replace the existing ones. - /// - /// Example: - /// parameterBag.replace({'key1': 'value1', 'key2': 42}); - void replace(Map parameters); - - /// Adds new parameters to the existing set of parameters. - /// - /// This method merges the provided [parameters] with the existing parameters - /// in the ParameterBag. If a key already exists, its value will be updated - /// with the new value from the provided map. - /// - /// Parameters: - /// [parameters] - A Map containing the new parameters - /// to be added to the existing set. - /// - /// Example: - /// parameterBag.add({'key1': 'newValue', 'key3': 'value3'}); - void add(Map parameters); - - /// Retrieves the value associated with the given key from the parameters. - /// - /// This method searches for the specified [key] in the parameters map. - /// If the key is found, it returns the corresponding value. - /// If the key is not found, it returns the [defaultValue]. - /// - /// Parameters: - /// [key] - The key to look up in the parameters map. - /// [defaultValue] - Optional. The value to return if the key is not found. - /// If not provided, it defaults to null. - /// - /// Returns: - /// The value associated with the key if found, otherwise the defaultValue. - /// - /// Example: - /// var value = parameterBag.get('username', 'guest'); - dynamic get(String key, [dynamic defaultValue]) { - return parameters.containsKey(key) ? parameters[key] : defaultValue; - } - - /// Sets a parameter value for the given key. - /// - /// This method adds or updates a parameter in the ParameterBag. - /// If the key already exists, its value will be updated. - /// If the key doesn't exist, a new key-value pair will be added. - /// - /// Parameters: - /// [key] - The string key for the parameter. - /// [value] - The value to be associated with the key. Can be of any type. - /// - /// Example: - /// parameterBag.set('username', 'john_doe'); - /// parameterBag.set('age', 30); - void set(String key, dynamic value); - - /// Checks if a parameter with the given key exists in the ParameterBag. - /// - /// This method determines whether the specified [key] is present in the - /// parameters map. It returns true if the key exists, and false otherwise. - /// - /// Parameters: - /// [key] - The string key to check for existence in the parameters map. - /// - /// Returns: - /// A boolean value: true if the key exists, false otherwise. - /// - /// Example: - /// if (parameterBag.has('username')) { - /// // Do something with the username parameter - /// } - bool has(String key) { - return parameters.containsKey(key); - } - - /// Removes a parameter from the ParameterBag. - /// - /// This method removes the key-value pair associated with the given [key] - /// from the parameters map. If the key doesn't exist, this method does nothing. - /// - /// Parameters: - /// [key] - The string key of the parameter to be removed. - /// - /// Example: - /// parameterBag.remove('username'); - void remove(String key); - - /// Returns the alphabetic characters of the parameter value. - /// - /// This method retrieves the value associated with the given [key] as a string, - /// and then removes all non-alphabetic characters from it. If the key doesn't - /// exist or its value is empty, it returns the [defaultValue]. - /// - /// Parameters: - /// [key] - The key of the parameter to retrieve and process. - /// [defaultValue] - Optional. The value to return if the key is not found - /// or its value is empty. Defaults to an empty string. - /// - /// Returns: - /// A string containing only alphabetic characters (a-z and A-Z) from the - /// original parameter value. - /// - /// Example: - /// parameterBag.set('mixed', 'abc123XYZ!@#'); - /// print(parameterBag.getAlpha('mixed')); // Outputs: 'abcXYZ' - String getAlpha(String key, [String defaultValue = '']) { - return getString(key, defaultValue).replaceAll(RegExp(r'[^a-zA-Z]'), ''); - } - - /// Returns the alphanumeric characters of the parameter value. - /// - /// This method retrieves the value associated with the given [key] as a string, - /// and then removes all non-alphanumeric characters from it. If the key doesn't - /// exist or its value is empty, it returns the [defaultValue]. - /// - /// Parameters: - /// [key] - The key of the parameter to retrieve and process. - /// [defaultValue] - Optional. The value to return if the key is not found - /// or its value is empty. Defaults to an empty string. - /// - /// Returns: - /// A string containing only alphanumeric characters (a-z, A-Z, and 0-9) from the - /// original parameter value. - /// - /// Example: - /// parameterBag.set('mixed', 'abc123XYZ!@#'); - /// print(parameterBag.getAlnum('mixed')); // Outputs: 'abc123XYZ' - String getAlnum(String key, [String defaultValue = '']) { - return getString(key, defaultValue).replaceAll(RegExp(r'[^a-zA-Z0-9]'), ''); - } - - /// Returns only the digit characters from the parameter value. - /// - /// This method retrieves the value associated with the given [key] as a string, - /// and then removes all non-digit characters from it. If the key doesn't - /// exist or its value is empty, it returns the [defaultValue]. - /// - /// Parameters: - /// [key] - The key of the parameter to retrieve and process. - /// [defaultValue] - Optional. The value to return if the key is not found - /// or its value is empty. Defaults to an empty string. - /// - /// Returns: - /// A string containing only digit characters (0-9) from the original parameter value. - /// - /// Example: - /// parameterBag.set('mixed', 'abc123XYZ!@#'); - /// print(parameterBag.getDigits('mixed')); // Outputs: '123' - String getDigits(String key, [String defaultValue = '']) { - return getString(key, defaultValue).replaceAll(RegExp(r'[^0-9]'), ''); - } - - /// Returns the parameter value as a string. - /// - /// This method retrieves the value associated with the given [key] and converts it to a string. - /// If the key doesn't exist, it returns the [defaultValue]. - /// - /// Parameters: - /// [key] - The key of the parameter to retrieve. - /// [defaultValue] - Optional. The value to return if the key is not found. - /// Defaults to an empty string. - /// - /// Returns: - /// A string representation of the parameter value. - /// - /// Throws: - /// [UnexpectedValueException] if the value cannot be converted to a string - /// (i.e., if it's not a String, num, or bool). - /// - /// Example: - /// parameterBag.set('number', 42); - /// print(parameterBag.getString('number')); // Outputs: '42' - String getString(String key, [String defaultValue = '']) { - final value = get(key, defaultValue); - if (value is! String && value is! num && value is! bool) { - throw UnexpectedValueException( - 'Parameter value "$key" cannot be converted to "String".'); - } - return value.toString(); - } - - /// Returns the parameter value converted to an integer. - /// - /// This method retrieves the value associated with the given [key] and attempts to convert it to an integer. - /// If the key doesn't exist or the value cannot be converted to an integer, it returns the [defaultValue]. - /// - /// Parameters: - /// [key] - The key of the parameter to retrieve. - /// [defaultValue] - Optional. The value to return if the key is not found or the value cannot be converted to an integer. - /// Defaults to 0. - /// - /// Returns: - /// An integer representation of the parameter value. - /// - /// Example: - /// parameterBag.set('number', '42'); - /// print(parameterBag.getInt('number')); // Outputs: 42 - /// print(parameterBag.getInt('nonexistent', 10)); // Outputs: 10 - int getInt(String key, [int defaultValue = 0]) { - final value = get(key, defaultValue); - if (value is int) return value; - if (value is String) { - return int.tryParse(value) ?? defaultValue; - } - return defaultValue; - } - - /// Returns the parameter value converted to a boolean. - /// - /// This method retrieves the value associated with the given [key] and attempts to convert it to a boolean. - /// If the key doesn't exist, it returns the [defaultValue]. - /// - /// The conversion rules are as follows: - /// - If the value is already a boolean, it is returned as-is. - /// - If the value is a string, it returns true if the string is 'true' (case-insensitive) or '1'. - /// - For all other cases, it returns the [defaultValue]. - /// - /// Parameters: - /// [key] - The key of the parameter to retrieve. - /// [defaultValue] - Optional. The value to return if the key is not found or the value cannot be converted to a boolean. - /// Defaults to false. - /// - /// Returns: - /// A boolean representation of the parameter value. - /// - /// Example: - /// parameterBag.set('flag1', 'true'); - /// parameterBag.set('flag2', '1'); - /// parameterBag.set('flag3', 'false'); - /// print(parameterBag.getBoolean('flag1')); // Outputs: true - /// print(parameterBag.getBoolean('flag2')); // Outputs: true - /// print(parameterBag.getBoolean('flag3')); // Outputs: false - /// print(parameterBag.getBoolean('nonexistent')); // Outputs: false - bool getBoolean(String key, [bool defaultValue = false]) { - final value = get(key, defaultValue); - if (value is bool) return value; - if (value is String) { - return value.toLowerCase() == 'true' || value == '1'; - } - return defaultValue; - } - - /// Returns the parameter value converted to an enum. - /// - /// This method retrieves the value associated with the given [key] and attempts to convert it - /// to an enum of type [T]. The method compares the string representation of each enum value - /// (without the enum type prefix) to the parameter value. - /// - /// Parameters: - /// [key] - The key of the parameter to retrieve. - /// [values] - A list of all possible enum values of type [T]. - /// [defaultValue] - Optional. The value to return if the key is not found or the value - /// cannot be converted to an enum. Defaults to null. - /// - /// Returns: - /// An enum value of type [T] if a match is found, otherwise returns the [defaultValue]. - /// - /// Throws: - /// [UnexpectedValueException] if the value exists but cannot be converted to an enum. - /// - /// Example: - /// enum Color { red, green, blue } - /// parameterBag.set('color', 'red'); - /// var color = parameterBag.getEnum('color', Color.values); // Returns Color.red - T? getEnum(String key, List values, [T? defaultValue]) { - final value = get(key); - if (value == null) return defaultValue; - try { - return values.firstWhere((e) => e.toString().split('.').last == value); - } catch (e) { - throw UnexpectedValueException( - 'Parameter "$key" cannot be converted to enum: ${e.toString()}'); - } - } - - /// Filters a parameter value based on the given key. - /// - /// This method retrieves the value associated with the given [key] and applies - /// basic filtering logic. If the key doesn't exist, it returns the [defaultValue]. - /// - /// The current implementation provides a simple string sanitization for string values, - /// trimming whitespace from the beginning and end. For all other types, the value - /// is returned as-is. - /// - /// This method is designed to be overridden or extended in subclasses to provide - /// more sophisticated filtering logic. - /// - /// Parameters: - /// [key] - The key of the parameter to filter. - /// [defaultValue] - Optional. The value to return if the key doesn't exist. - /// [filter] - Optional. An integer representing the filter type (not used in the base implementation). - /// [options] - Optional. Additional options for filtering (not used in the base implementation). - /// - /// Returns: - /// The filtered value if the key exists, otherwise the [defaultValue]. - /// - /// Example: - /// parameterBag.set('name', ' John Doe '); - /// print(parameterBag.filter('name')); // Outputs: 'John Doe' - dynamic filter(String key, - {dynamic defaultValue, int? filter, dynamic options}) { - if (!has(key)) { - return defaultValue; - } - - var value = get(key); - - // Basic filtering logic, can be overridden or extended in subclasses - if (value is String) { - // Simple string sanitization as an example - return value.trim(); - } - - // For other types, return as is - return value; - } - - /// Returns an iterator for the entries in the parameters map. - /// - /// This getter provides an iterator that allows for traversing all key-value - /// pairs (entries) in the underlying parameters map. It's particularly useful - /// for iterating over all parameters in the ParameterBag. - /// - /// The iterator yields [MapEntry] objects, where each entry contains a String - /// key and a dynamic value, corresponding to a parameter in the ParameterBag. - /// - /// This implementation is part of the [Iterable] interface, allowing - /// ParameterBag to be used in for-in loops and with other Iterable methods. - /// - /// Returns: - /// An [Iterator] of [MapEntry] for the parameters map. - /// - /// Example: - /// for (var entry in parameterBag) { - /// print('${entry.key}: ${entry.value}'); - /// } - @override - Iterator> get iterator => - parameters.entries.iterator; - - /// Returns the number of parameters in the ParameterBag. - /// - /// This getter provides the count of key-value pairs in the underlying - /// parameters map. It's an implementation of the [Countable] interface. - /// - /// Returns: - /// An integer representing the number of parameters stored in the ParameterBag. - /// - /// Example: - /// int parameterCount = parameterBag.count; - /// print('Number of parameters: $parameterCount'); - @override - int get count => parameters.length; -} diff --git a/packages/http/lib/src/foundation/request.dart b/packages/http/lib/src/foundation/request.dart deleted file mode 100644 index 25227c1..0000000 --- a/packages/http/lib/src/foundation/request.dart +++ /dev/null @@ -1,1333 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'package:http/http.dart' as http; -import 'package:intl/intl.dart'; -import 'package:collection/collection.dart'; - -// Assuming these classes have been ported to Dart -import 'accept_header.dart'; -import 'file_bag.dart'; -import 'header_bag.dart'; -import 'header_utils.dart'; -import 'input_bag.dart'; -import 'parameter_bag.dart'; -import 'server_bag.dart'; -import "package:protevus_http/foundation_session.dart"; -import 'ip_utils.dart'; - -class Request { - static const int HEADER_FORWARDED = 0b000001; - static const int HEADER_X_FORWARDED_FOR = 0b000010; - static const int HEADER_X_FORWARDED_HOST = 0b000100; - static const int HEADER_X_FORWARDED_PROTO = 0b001000; - static const int HEADER_X_FORWARDED_PORT = 0b010000; - static const int HEADER_X_FORWARDED_PREFIX = 0b100000; - - static const int HEADER_X_FORWARDED_AWS_ELB = 0b0011010; - static const int HEADER_X_FORWARDED_TRAEFIK = 0b0111110; - - static const String METHOD_HEAD = 'HEAD'; - static const String METHOD_GET = 'GET'; - static const String METHOD_POST = 'POST'; - static const String METHOD_PUT = 'PUT'; - static const String METHOD_PATCH = 'PATCH'; - static const String METHOD_DELETE = 'DELETE'; - static const String METHOD_PURGE = 'PURGE'; - static const String METHOD_OPTIONS = 'OPTIONS'; - static const String METHOD_TRACE = 'TRACE'; - static const String METHOD_CONNECT = 'CONNECT'; - - static List trustedProxies = []; - static List trustedHostPatterns = []; - static List trustedHosts = []; - static bool httpMethodParameterOverride = false; - - late ParameterBag attributes; - late InputBag request; - late InputBag query; - late ServerBag server; - late FileBag files; - late InputBag cookies; - late HeaderBag headers; - - dynamic content; - List? languages; - List? charsets; - List? encodings; - List? acceptableContentTypes; - - String? pathInfo; - String? requestUri; - String? baseUrl; - String? basePath; - String? method; - String? format; - dynamic session; - String? locale; - String defaultLocale = 'en'; - - static Map>? formats; - static Function? requestFactory; - - String? preferredFormat; - bool isHostValid = true; - bool isForwardedValid = true; - late bool isSafeContentPreferred; - - Map trustedValuesCache = {}; - - static int trustedHeaderSet = -1; - - static const Map FORWARDED_PARAMS = { - HEADER_X_FORWARDED_FOR: 'for', - HEADER_X_FORWARDED_HOST: 'host', - HEADER_X_FORWARDED_PROTO: 'proto', - HEADER_X_FORWARDED_PORT: 'host', - }; - - static const Map TRUSTED_HEADERS = { - HEADER_FORWARDED: 'FORWARDED', - HEADER_X_FORWARDED_FOR: 'X_FORWARDED_FOR', - HEADER_X_FORWARDED_HOST: 'X_FORWARDED_HOST', - HEADER_X_FORWARDED_PROTO: 'X_FORWARDED_PROTO', - HEADER_X_FORWARDED_PORT: 'X_FORWARDED_PORT', - HEADER_X_FORWARDED_PREFIX: 'X_FORWARDED_PREFIX', - }; - - bool isIisRewrite = false; - - Request({ - Map query = const {}, - Map request = const {}, - Map attributes = const {}, - Map cookies = const {}, - Map files = const {}, - Map server = const {}, - dynamic content, - }) { - initialize(query, request, attributes, cookies, files, server, content); - } - - void initialize( - Map query, - Map request, - Map attributes, - Map cookies, - Map files, - Map server, - dynamic content, - ) { - this.request = InputBag(request); - this.query = InputBag(query); - this.attributes = ParameterBag(attributes); - this.cookies = InputBag(cookies); - this.files = FileBag(files); - this.server = ServerBag(server); - this.headers = HeaderBag(this.server.getHeaders()); - - this.content = content; - this.languages = null; - this.charsets = null; - this.encodings = null; - this.acceptableContentTypes = null; - this.pathInfo = null; - this.requestUri = null; - this.baseUrl = null; - this.basePath = null; - this.method = null; - this.format = null; - } - - static Request createFromGlobals() { - // Dart equivalent of PHP's superglobals - var get = Platform.environment; - var post = {}; // POST data needs to be handled differently in Dart - var cookies = {}; // Cookie handling needs to be implemented - var files = {}; // File uploads need to be handled differently - var server = Platform.environment; - - var request = createRequestFromFactory(get, post, {}, cookies, files, server); - - if (request.headers.get('CONTENT_TYPE')?.startsWith('application/x-www-form-urlencoded') == true && - ['PUT', 'DELETE', 'PATCH'].contains(request.server.get('REQUEST_METHOD', 'GET').toUpperCase())) { - // Parse request body - var data = Uri(query: request.getContent()).queryParameters; - request.request = InputBag(data); - } - - return request; - } - - static Request create( - String uri, { - String method = 'GET', - Map parameters = const {}, - Map cookies = const {}, - Map files = const {}, - Map server = const {}, - dynamic content, - }) { - var defaultServer = { - 'SERVER_NAME': 'localhost', - 'SERVER_PORT': '80', - 'HTTP_HOST': 'localhost', - 'HTTP_USER_AGENT': 'Dart', - 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'HTTP_ACCEPT_LANGUAGE': 'en-us,en;q=0.5', - 'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', - 'REMOTE_ADDR': '127.0.0.1', - 'SCRIPT_NAME': '', - 'SCRIPT_FILENAME': '', - 'SERVER_PROTOCOL': 'HTTP/1.1', - 'REQUEST_TIME': DateTime.now().millisecondsSinceEpoch ~/ 1000, - 'REQUEST_TIME_FLOAT': DateTime.now().millisecondsSinceEpoch / 1000, - }; - - server = {...defaultServer, ...server}; - - server['PATH_INFO'] = ''; - server['REQUEST_METHOD'] = method.toUpperCase(); - - var components = Uri.parse(uri); - if (components.host != null) { - server['SERVER_NAME'] = components.host!; - server['HTTP_HOST'] = components.host!; - } - - if (components.scheme != null) { - if (components.scheme == 'https') { - server['HTTPS'] = 'on'; - server['SERVER_PORT'] = '443'; - } else { - server.remove('HTTPS'); - server['SERVER_PORT'] = '80'; - } - } - - if (components.port != 0) { - server['SERVER_PORT'] = components.port.toString(); - server['HTTP_HOST'] = '${server['HTTP_HOST']}:${components.port}'; - } - - if (components.userInfo.isNotEmpty) { - var userInfoParts = components.userInfo.split(':'); - server['PHP_AUTH_USER'] = userInfoParts[0]; - if (userInfoParts.length > 1) { - server['PHP_AUTH_PW'] = userInfoParts[1]; - } - } - - if (components.path.isEmpty) { - components = components.replace(path: '/'); - } - - Map request = {}; - Map query = {}; - - switch (method.toUpperCase()) { - case 'POST': - case 'PUT': - case 'DELETE': - if (!server.containsKey('CONTENT_TYPE')) { - server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; - } - request = parameters; - break; - case 'PATCH': - request = parameters; - break; - default: - query = parameters; - break; - } - - var queryString = ''; - if (components.query.isNotEmpty) { - var qs = Uri.splitQueryString(components.query); - if (query.isNotEmpty) { - query = {...qs, ...query}; - queryString = Uri(queryParameters: query).query; - } else { - query = qs; - queryString = components.query; - } - } else if (query.isNotEmpty) { - queryString = Uri(queryParameters: query).query; - } - - server['REQUEST_URI'] = '${components.path}${queryString.isNotEmpty ? '?$queryString' : ''}'; - server['QUERY_STRING'] = queryString; - - return createRequestFromFactory(query, request, {}, cookies, files, server, content); - } - - static void setFactory(Function? callable) { - requestFactory = callable; - } - - Request duplicate({ - Map? query, - Map? request, - Map? attributes, - Map? cookies, - Map? files, - Map? server, - }) { - var dup = Request(); - dup.query = query != null ? InputBag(query) : this.query; - dup.request = request != null ? InputBag(request) : this.request; - dup.attributes = attributes != null ? ParameterBag(attributes) : this.attributes; - dup.cookies = cookies != null ? InputBag(cookies) : this.cookies; - dup.files = files != null ? FileBag(files) : this.files; - if (server != null) { - dup.server = ServerBag(server); - dup.headers = HeaderBag(dup.server.getHeaders()); - } else { - dup.server = this.server; - dup.headers = this.headers; - } - dup.languages = null; - dup.charsets = null; - dup.encodings = null; - dup.acceptableContentTypes = null; - dup.pathInfo = null; - dup.requestUri = null; - dup.baseUrl = null; - dup.basePath = null; - dup.method = null; - dup.format = null; - - if (!dup.get('_format') && this.get('_format') != null) { - dup.attributes.set('_format', this.get('_format')); - } - - if (dup.getRequestFormat(null) == null) { - dup.setRequestFormat(this.getRequestFormat(null)); - } - - return dup; - } - - @override - String toString() { - var content = getContent(); - - var cookieHeader = ''; - var cookies = []; - - for (var entry in this.cookies.all().entries) { - if (entry.value is List) { - cookies.add(Uri(queryParameters: {entry.key: entry.value}).query.replaceAll('&', '; ')); - } else { - cookies.add('${entry.key}=${entry.value}'); - } - } - - if (cookies.isNotEmpty) { - cookieHeader = 'Cookie: ${cookies.join('; ')}\r\n'; - } - - return '${getMethod()} ${getRequestUri()} ${server.get('SERVER_PROTOCOL')}\r\n' - '${headers.toString()}' - '$cookieHeader\r\n' - '$content'; - } - - void overrideGlobals() { - // This method is not directly applicable in Dart as it doesn't have global variables like PHP - // You might need to implement a global state management solution in your Dart application - } - - static void setTrustedProxies(List proxies, int trustedHeaderSet) { - trustedProxies = proxies.where((proxy) => proxy != 'REMOTE_ADDR').toList(); - if (proxies.contains('REMOTE_ADDR')) { - var remoteAddr = Platform.environment['REMOTE_ADDR']; - if (remoteAddr != null) { - trustedProxies.add(remoteAddr); - } - } - Request.trustedHeaderSet = trustedHeaderSet; - } - - static List getTrustedProxies() { - return trustedProxies; - } - - static int getTrustedHeaderSet() { - return trustedHeaderSet; - } - - static void setTrustedHosts(List hostPatterns) { - trustedHostPatterns = hostPatterns.map((hostPattern) => RegExp(hostPattern, caseSensitive: false).pattern).toList(); - trustedHosts = []; - } - - static List getTrustedHosts() { - return trustedHostPatterns; - } - - static String normalizeQueryString(String? qs) { - if (qs == null || qs.isEmpty) { - return ''; - } - - var queryParams = Uri.splitQueryString(qs); - var sortedKeys = queryParams.keys.toList()..sort(); - var normalizedParams = sortedKeys.map((key) => '$key=${Uri.encodeQueryComponent(queryParams[key]!)}'); - - return normalizedParams.join('&'); - } - - static void enableHttpMethodParameterOverride() { - httpMethodParameterOverride = true; - } - - static bool getHttpMethodParameterOverride() { - return httpMethodParameterOverride; - } - - dynamic get(String key, [dynamic defaultValue]) { - if (attributes.get(key) != null) { - return attributes.get(key); - } - - if (query.has(key)) { - return query.all()[key]; - } - - if (request.has(key)) { - return request.all()[key]; - } - - return defaultValue; - } - - SessionInterface getSession() { - if (session == null) { - throw Exception('Session has not been set.'); - } - if (session is Function) { - session = session(); - } - return session as SessionInterface; - } - - bool hasPreviousSession() { - return hasSession() && cookies.has(getSession().getName()); - } - - bool hasSession([bool skipIfUninitialized = false]) { - return session != null && (!skipIfUninitialized || session is SessionInterface); - } -void setSession(SessionInterface session) { - this.session = session; - } - - void setSessionFactory(Function factory) { - this.session = factory; - } - - List getClientIps() { - var ip = server.get('REMOTE_ADDR'); - - if (!isFromTrustedProxy()) { - return [ip]; - } - - var trustedValues = getTrustedValues(HEADER_X_FORWARDED_FOR, ip); - return trustedValues.isNotEmpty ? trustedValues : [ip]; - } - - String? getClientIp() { - var ips = getClientIps(); - return ips.isNotEmpty ? ips[0] : null; - } - - String getScriptName() { - return server.get('SCRIPT_NAME', server.get('ORIG_SCRIPT_NAME', '')); - } - - String getPathInfo() { - return pathInfo ??= preparePathInfo(); - } - - String getBasePath() { - return basePath ??= prepareBasePath(); - } - - String getBaseUrl() { - var trustedPrefix = ''; - - if (isFromTrustedProxy() && getTrustedValues(HEADER_X_FORWARDED_PREFIX).isNotEmpty) { - trustedPrefix = getTrustedValues(HEADER_X_FORWARDED_PREFIX)[0].trimRight('/'); - } - - return '$trustedPrefix${getBaseUrlReal()}'; - } - - String getBaseUrlReal() { - return baseUrl ??= prepareBaseUrl(); - } - - String getScheme() { - return isSecure() ? 'https' : 'http'; - } - - dynamic getPort() { - String? host; - if (isFromTrustedProxy()) { - var forwardedPort = getTrustedValues(HEADER_X_FORWARDED_PORT); - if (forwardedPort.isNotEmpty) { - host = forwardedPort[0]; - } else { - var forwardedHost = getTrustedValues(HEADER_X_FORWARDED_HOST); - if (forwardedHost.isNotEmpty) { - host = forwardedHost[0]; - } - } - } - - if (host == null) { - host = headers.get('HOST'); - } - - if (host == null) { - return server.get('SERVER_PORT'); - } - - if (host.startsWith('[')) { - var pos = host.lastIndexOf(']'); - if (pos > 0) { - host = host.substring(pos + 1); - } - } - - var pos = host.lastIndexOf(':'); - if (pos > 0) { - return int.tryParse(host.substring(pos + 1)) ?? (getScheme() == 'https' ? 443 : 80); - } - - return getScheme() == 'https' ? 443 : 80; - } - - String? getUser() { - return headers.get('PHP_AUTH_USER'); - } - - String? getPassword() { - return headers.get('PHP_AUTH_PW'); - } - - String? getUserInfo() { - var userInfo = getUser(); - var pass = getPassword(); - if (pass != null && pass.isNotEmpty) { - userInfo = '$userInfo:$pass'; - } - return userInfo; - } - - String getHttpHost() { - var scheme = getScheme(); - var port = getPort(); - - if ((scheme == 'http' && port == 80) || (scheme == 'https' && port == 443)) { - return getHost(); - } - - return '${getHost()}:$port'; - } - - String getRequestUri() { - return requestUri ??= prepareRequestUri(); - } - - String getSchemeAndHttpHost() { - return '${getScheme()}://${getHttpHost()}'; - } - - String getUri() { - var qs = getQueryString(); - if (qs != null && qs.isNotEmpty) { - qs = '?$qs'; - } else { - qs = ''; - } - - return '${getSchemeAndHttpHost()}${getBaseUrl()}${getPathInfo()}$qs'; - } - - String getUriForPath(String path) { - return '${getSchemeAndHttpHost()}${getBaseUrl()}$path'; - } - - String getRelativeUriForPath(String path) { - if (path.isEmpty || path[0] != '/') { - return path; - } - - var basePath = getPathInfo(); - if (path == basePath) { - return ''; - } - - var sourceDirs = basePath.split('/'); - var targetDirs = path.split('/'); - sourceDirs = sourceDirs.sublist(1, sourceDirs.length - 1); - var targetFile = targetDirs.removeLast(); - - for (var i = 0; i < sourceDirs.length; i++) { - if (i < targetDirs.length && sourceDirs[i] == targetDirs[i]) { - sourceDirs.removeAt(i); - targetDirs.removeAt(i); - i--; - } else { - break; - } - } - - targetDirs.add(targetFile); - var relativePath = '../' * sourceDirs.length + targetDirs.join('/'); - - return relativePath.isEmpty || relativePath[0] == '/' || relativePath.contains(':') - ? './$relativePath' - : relativePath; - } - - String? getQueryString() { - var qs = normalizeQueryString(server.get('QUERY_STRING')); - return qs.isEmpty ? null : qs; - } - - bool isSecure() { - if (isFromTrustedProxy()) { - var proto = getTrustedValues(HEADER_X_FORWARDED_PROTO); - if (proto.isNotEmpty) { - return ['https', 'on', 'ssl', '1'].contains(proto[0].toLowerCase()); - } - } - - var https = server.get('HTTPS'); - return https != null && https.toLowerCase() != 'off'; - } - - String getHost() { - var host = ''; - if (isFromTrustedProxy()) { - var trustedValues = getTrustedValues(HEADER_X_FORWARDED_HOST); - if (trustedValues.isNotEmpty) { - host = trustedValues[0]; - } - } - - if (host.isEmpty) { - host = headers.get('HOST') ?? ''; - } - - if (host.isEmpty) { - host = server.get('SERVER_NAME') ?? ''; - } - - if (host.isEmpty) { - host = server.get('SERVER_ADDR') ?? ''; - } - - // Trim and remove port number from host - host = host.toLowerCase().replaceAll(RegExp(r':\d+$'), '').trim(); - - // Check for forbidden characters - if (host.isNotEmpty && !RegExp(r'^(\[)?[a-zA-Z0-9-:\]_]+\.?$').hasMatch(host)) { - if (!isHostValid) { - return ''; - } - isHostValid = false; - throw Exception('Invalid Host "$host".'); - } - - if (trustedHostPatterns.isNotEmpty) { - if (trustedHosts.contains(host)) { - return host; - } - - for (var pattern in trustedHostPatterns) { - if (RegExp(pattern).hasMatch(host)) { - trustedHosts.add(host); - return host; - } - } - - if (!isHostValid) { - return ''; - } - isHostValid = false; - throw Exception('Untrusted Host "$host".'); - } - - return host; - } - - void setMethod(String method) { - this.method = null; - server.set('REQUEST_METHOD', method); - } - - String getMethod() { - if (method != null) { - return method!; - } - - method = server.get('REQUEST_METHOD', 'GET').toUpperCase(); - - if (method != 'POST') { - return method!; - } - - var methodOverride = headers.get('X-HTTP-METHOD-OVERRIDE'); - - if (methodOverride == null && httpMethodParameterOverride) { - methodOverride = request.get('_method', query.get('_method', 'POST')); - } - - if (methodOverride is String) { - methodOverride = methodOverride.toUpperCase(); - if (['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'PATCH', 'PURGE', 'TRACE'].contains(methodOverride)) { - method = methodOverride; - } - - if (!RegExp(r'^[A-Z]+$').hasMatch(methodOverride)) { - throw Exception('Invalid method override "$methodOverride".'); - } - - method = methodOverride; - } - - return method!; - } - - String getRealMethod() { - return server.get('REQUEST_METHOD', 'GET').toUpperCase(); - } - - String? getMimeType(String format) { - if (formats == null) { - initializeFormats(); - } - return formats![format]?.first; - } - - static List getMimeTypes(String format) { - if (formats == null) { - initializeFormats(); - } - return formats![format] ?? []; - } - - String? getFormat(String? mimeType) { - var canonicalMimeType = mimeType; - if (mimeType != null && mimeType.contains(';')) { - canonicalMimeType = mimeType.split(';').first.trim(); - } - - if (formats == null) { - initializeFormats(); - } - - for (var entry in formats!.entries) { - if (entry.value.contains(mimeType) || entry.value.contains(canonicalMimeType)) { - return entry.key; - } - } - - return null; - } - - void setFormat(String? format, dynamic mimeTypes) { - if (formats == null) { - initializeFormats(); - } - formats![format!] = mimeTypes is List ? mimeTypes : [mimeTypes]; - } - - String? getRequestFormat([String? defaultFormat = 'html']) { - if (format == null) { - format = attributes.get('_format'); - } - return format ?? defaultFormat; - } - - void setRequestFormat(String? format) { - this.format = format; - } - - String? getContentTypeFormat() { - return getFormat(headers.get('CONTENT_TYPE', '')); - } - - void setDefaultLocale(String locale) { - defaultLocale = locale; - - if (this.locale == null) { - setPhpDefaultLocale(locale); - } - } - - String getDefaultLocale() { - return defaultLocale; - } - - void setLocale(String locale) { - setPhpDefaultLocale(this.locale = locale); - } - - String getLocale() { - return locale ?? defaultLocale; - } - - bool isMethod(String method) { - return getMethod() == method.toUpperCase(); - } - - bool isMethodSafe() { - return ['GET', 'HEAD', 'OPTIONS', 'TRACE'].contains(getMethod()); - } - - bool isMethodIdempotent() { - return ['HEAD', 'GET', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PURGE'].contains(getMethod()); - } - - bool isMethodCacheable() { - return ['GET', 'HEAD'].contains(getMethod()); - } - - String? getProtocolVersion() { - if (isFromTrustedProxy()) { - var viaHeader = headers.get('Via'); - if (viaHeader != null) { - var matches = RegExp(r'^(HTTP/)?([1-9]\.[0-9]) ').firstMatch(viaHeader); - if (matches != null) { - return 'HTTP/${matches.group(2)}'; - } - } - } - - return server.get('SERVER_PROTOCOL'); - } - - dynamic getContent({bool asResource = false}) { - if (content is IOSink && asResource) { - return content; - } - - if (asResource) { - content = File('php://input').openRead(); - return content; - } - - if (content is IOSink) { - var stringContent = StringBuffer(); - content.stream.transform(utf8.decoder).listen((data) { - stringContent.write(data); - }); - content = stringContent.toString(); - } - - if (content == null || content == false) { - content = File('php://input').readAsStringSync(); - } - - return content; - } - - InputBag getPayload() { - if (request.count() > 0) { - return InputBag(Map.from(request.all())); - } - - var content = getContent(); - if (content.isEmpty) { - return InputBag({}); - } - - try { - var decodedContent = json.decode(content); - if (decodedContent is! Map) { - throw FormatException('JSON content was expected to decode to a Map, "${decodedContent.runtimeType}" returned.'); - } - return InputBag(decodedContent); - } catch (e) { - throw FormatException('Could not decode request body.', e); - } - } - - Map toArray() { - var content = getContent(); - if (content.isEmpty) { - throw FormatException('Request body is empty.'); - } - - try { - var decodedContent = json.decode(content); - if (decodedContent is! Map) { - throw FormatException('JSON content was expected to decode to a Map, "${decodedContent.runtimeType}" returned.'); - } - return decodedContent; - } catch (e) { - throw FormatException('Could not decode request body.', e); - } - } - - List getETags() { - return headers.get('If-None-Match', '').split(RegExp(r'\s*,\s*'))..removeWhere((e) => e.isEmpty); - } - - bool isNoCache() { - return headers.hasCacheControlDirective('no-cache') || headers.get('Pragma') == 'no-cache'; - } - - String? getPreferredFormat([String? defaultFormat = 'html']) { - if (preferredFormat == null) { - preferredFormat = getRequestFormat(null); - } - - if (preferredFormat != null) { - return preferredFormat; - } - - for (var mimeType in getAcceptableContentTypes()) { - preferredFormat = getFormat(mimeType); - if (preferredFormat != null) { - return preferredFormat; - } - } - - return defaultFormat; - } - - String? getPreferredLanguage([List? locales]) { - var preferredLanguages = getLanguages(); - - if (locales == null || locales.isEmpty) { - return preferredLanguages.isNotEmpty ? preferredLanguages.first : null; - } - - locales = locales.map(formatLocale).toList(); - if (preferredLanguages.isEmpty) { - return locales.first; - } - - var matches = preferredLanguages.where((lang) => locales!.contains(lang)).toList(); - if (matches.isNotEmpty) { - return matches.first; - } - - var combinations = preferredLanguages.expand(getLanguageCombinations).toList(); - for (var combination in combinations) { - for (var locale in locales) { - if (locale.startsWith(combination)) { - return locale; - } - } - } - - return locales.first; - } - - List getLanguages() { - if (languages !=null) { - return languages!; - } - - languages = []; - var acceptLanguage = headers.get('Accept-Language'); - if (acceptLanguage != null) { - var acceptHeader = AcceptHeader.fromString(acceptLanguage); - for (var item in acceptHeader.all()) { - languages!.add(formatLocale(item.value)); - } - } - languages = languages!.toSet().toList(); // Remove duplicates - return languages!; - } - - static String formatLocale(String locale) { - var components = getLanguageComponents(locale); - return [components[0], components[1], components[2]].where((e) => e != null).join('_'); - } - - static List getLanguageCombinations(String locale) { - var components = getLanguageComponents(locale); - var language = components[0]; - var script = components[1]; - var region = components[2]; - - return [ - [language, script, region].where((e) => e != null).join('_'), - [language, script].where((e) => e != null).join('_'), - [language, region].where((e) => e != null).join('_'), - language, - ].toSet().toList(); // Remove duplicates - } - - static List getLanguageComponents(String locale) { - locale = locale.toLowerCase().replaceAll('_', '-'); - var pattern = RegExp(r'^([a-zA-Z]{2,3}|i-[a-zA-Z]{5,})(?:-([a-zA-Z]{4}))?(?:-([a-zA-Z]{2}))?(?:-(.+))?$'); - var match = pattern.firstMatch(locale); - - if (match == null) { - return [locale, null, null]; - } - - var language = match.group(1); - if (language!.startsWith('i-')) { - language = language.substring(2); - } - - var script = match.group(2); - script = script != null ? script[0].toUpperCase() + script.substring(1).toLowerCase() : null; - - var region = match.group(3); - region = region?.toUpperCase(); - - return [language, script, region]; - } - - List getCharsets() { - if (charsets == null) { - var acceptCharset = headers.get('Accept-Charset'); - if (acceptCharset != null) { - charsets = AcceptHeader.fromString(acceptCharset).keys.map((e) => e.toString()).toList(); - } else { - charsets = []; - } - } - return charsets!; - } - - List getEncodings() { - if (encodings == null) { - var acceptEncoding = headers.get('Accept-Encoding'); - if (acceptEncoding != null) { - encodings = AcceptHeader.fromString(acceptEncoding).keys.map((e) => e.toString()).toList(); - } else { - encodings = []; - } - } - return encodings!; - } - - List getAcceptableContentTypes() { - if (acceptableContentTypes == null) { - var accept = headers.get('Accept'); - if (accept != null) { - acceptableContentTypes = AcceptHeader.fromString(accept).keys.map((e) => e.toString()).toList(); - } else { - acceptableContentTypes = []; - } - } - return acceptableContentTypes!; - } - - bool isXmlHttpRequest() { - return headers.get('X-Requested-With') == 'XMLHttpRequest'; - } - - bool preferSafeContent() { - if (isSafeContentPreferred != null) { - return isSafeContentPreferred; - } - - if (!isSecure()) { - return isSafeContentPreferred = false; - } - - return isSafeContentPreferred = AcceptHeader.fromString(headers.get('Prefer') ?? '').has('safe'); - } - - String prepareRequestUri() { - var requestUri = ''; - - if (isIisRewrite() && server.get('UNENCODED_URL') != null) { - requestUri = server.get('UNENCODED_URL')!; - server.remove('UNENCODED_URL'); - } else if (server.get('REQUEST_URI') != null) { - requestUri = server.get('REQUEST_URI')!; - if (requestUri.isNotEmpty && requestUri[0] != '/') { - var uriComponents = Uri.parse(requestUri); - requestUri = uriComponents.path; - if (uriComponents.query != null) { - requestUri += '?${uriComponents.query}'; - } - } - } else if (server.get('ORIG_PATH_INFO') != null) { - requestUri = server.get('ORIG_PATH_INFO')!; - if (server.get('QUERY_STRING') != null) { - requestUri += '?${server.get('QUERY_STRING')}'; - } - server.remove('ORIG_PATH_INFO'); - } - - server.set('REQUEST_URI', requestUri); - - return requestUri; - } - - String prepareBaseUrl() { - var filename = basename(server.get('SCRIPT_FILENAME') ?? ''); - var scriptName = server.get('SCRIPT_NAME'); - var phpSelf = server.get('PHP_SELF'); - var origScriptName = server.get('ORIG_SCRIPT_NAME'); - - if (scriptName != null && basename(scriptName) == filename) { - return scriptName; - } - - if (phpSelf != null && basename(phpSelf) == filename) { - return phpSelf; - } - - if (origScriptName != null && basename(origScriptName) == filename) { - return origScriptName; - } - - var requestUri = getRequestUri(); - var baseUrl = ''; - - if (requestUri == '/' || requestUri.isEmpty) { - return ''; - } - - if (requestUri != null) { - var filenameParts = filename.split('/').reversed; - var uriParts = requestUri.split('/'); - - var i = 0; - for (var part in filenameParts) { - if (i >= uriParts.length || uriParts[uriParts.length - 1 - i] != part) { - break; - } - i++; - } - - if (i > 0) { - baseUrl = uriParts.sublist(0, uriParts.length - i).join('/'); - } - } - - return baseUrl; - } - - String prepareBasePath() { - var baseUrl = getBaseUrl(); - if (baseUrl.isEmpty) { - return ''; - } - - var filename = basename(server.get('SCRIPT_FILENAME') ?? ''); - var basePath = baseUrl; - - if (basename(baseUrl) == filename) { - basePath = dirname(baseUrl); - } - - if (basePath == '\\') { - return ''; - } - - return basePath; - } - - String preparePathInfo() { - var requestUri = getRequestUri(); - - if (requestUri == null || requestUri.isEmpty) { - return '/'; - } - - var baseUrl = getBaseUrlReal(); - if (baseUrl != null && baseUrl.isNotEmpty) { - var pathInfo = substring(requestUri, baseUrl.length); - if (pathInfo.isEmpty || pathInfo[0] != '/') { - pathInfo = '/$pathInfo'; - } - return pathInfo; - } - - return requestUri; - } - - static void initializeFormats() { - formats = { - 'html': ['text/html', 'application/xhtml+xml'], - 'txt': ['text/plain'], - 'js': ['application/javascript', 'application/x-javascript', 'text/javascript'], - 'css': ['text/css'], - 'json': ['application/json', 'application/x-json'], - 'jsonld': ['application/ld+json'], - 'xml': ['text/xml', 'application/xml', 'application/x-xml'], - 'rdf': ['application/rdf+xml'], - 'atom': ['application/atom+xml'], - 'rss': ['application/rss+xml'], - 'form': ['application/x-www-form-urlencoded', 'multipart/form-data'], - }; - } - - void setPhpDefaultLocale(String locale) { - // This is a no-op in Dart as it doesn't have a direct equivalent to PHP's setlocale - } - - String? getUrlencodedPrefix(String string, String prefix) { - if (isIisRewrite()) { - if (!string.toLowerCase().startsWith(prefix.toLowerCase())) { - return null; - } - } else if (!string.startsWith(prefix)) { - return null; - } - - var len = prefix.length; - var match = RegExp('^((?:%[0-9A-Fa-f]{2}|.){$len})').firstMatch(string); - return match != null ? match.group(1) : null; - } - - static Request createRequestFromFactory( - Map query, - Map request, - Map attributes, - Map cookies, - Map files, - Map server, - [dynamic content] - ) { - if (requestFactory != null) { - var factoryRequest = requestFactory!(query, request, attributes, cookies, files, server, content); - if (factoryRequest is! Request) { - throw Exception('The Request factory must return an instance of Symfony\\Component\\HttpFoundation\\Request.'); - } - return factoryRequest; - } - - return Request( - query: query, - request: request, - attributes: attributes, - cookies: cookies, - files: files, - server: server, - content: content, - ); - } - - bool isFromTrustedProxy() { - return trustedProxies.isNotEmpty && IpUtils.checkIp(server.get('REMOTE_ADDR', ''), trustedProxies); - } - - List getTrustedValues(int type, [String? ip]) { - var cacheKey = '$type${(trustedHeaderSet & type) != 0 ? headers.get(TRUSTED_HEADERS[type]) : ''}$ip${headers.get(TRUSTED_HEADERS[HEADER_FORWARDED])}'; - - if (trustedValuesCache.containsKey(cacheKey)) { - return trustedValuesCache[cacheKey]; - } - - var clientValues = []; - var forwardedValues = []; - - if ((trustedHeaderSet & type) != 0 && headers.has(TRUSTED_HEADERS[type]!)) { - clientValues = headers.get(TRUSTED_HEADERS[type]!)!.split(',').map((v) { - return type == HEADER_X_FORWARDED_PORT ? '0.0.0.0:$v' : v.trim(); - }).toList(); - } - - if ((trustedHeaderSet & HEADER_FORWARDED) != 0 && FORWARDED_PARAMS.containsKey(type) && headers.has(TRUSTED_HEADERS[HEADER_FORWARDED]!)) { - var forwarded = headers.get(TRUSTED_HEADERS[HEADER_FORWARDED]); - var parts = HeaderUtils.split(forwarded!, ',;='); - var param = FORWARDED_PARAMS[type]; - for (var subParts in parts) { - var combinedParts = HeaderUtils.combine(subParts); - var v = combinedParts[param]; - if (v == null) { - continue; - } - if (type == HEADER_X_FORWARDED_PORT) { - if (v.endsWith(']') || !v.contains(':')) { - v = isSecure() ? ':443' : ':80'; - } - v = '0.0.0.0$v'; - } - forwardedValues.add(v); - } - } - - if (ip != null) { - clientValues = normalizeAndFilterClientIps(clientValues, ip); - forwardedValues = normalizeAndFilterClientIps(forwardedValues, ip); - } - - if (forwardedValues == clientValues || clientValues.isEmpty) { - return trustedValuesCache[cacheKey] = forwardedValues; - } - - if (forwardedValues.isEmpty) { - return trustedValuesCache[cacheKey] = clientValues; - } - - if (!isForwardedValid) { - return trustedValuesCache[cacheKey] = ip != null ? ['0.0.0.0', ip] : []; - } - isForwardedValid = false; - - throw Exception('The request has both a trusted "${TRUSTED_HEADERS[HEADER_FORWARDED]}" header and a trusted "${TRUSTED_HEADERS[type]}" header, conflicting with each other. You should either configure your proxy to remove one of them, or configure your project to distrust the offending one.'); - } - - List normalizeAndFilterClientIps(List clientIps, String ip) { - if (clientIps.isEmpty) { - return []; - } - clientIps.add(ip); // Complete the IP chain with the IP the request actually came from - String? firstTrustedIp; - - for (var i = 0; i < clientIps.length; i++) { - var clientIp = clientIps[i]; - if (clientIp.contains('.')) { - // Strip :port from IPv4 addresses. This is allowed in Forwarded - // and may occur in X-Forwarded-For. - var pos = clientIp.indexOf(':'); - if (pos != -1) { - clientIps[i] = clientIp = clientIp.substring(0, pos); - } - } else if (clientIp.startsWith('[')) { - // Strip brackets and :port from IPv6 addresses. - var pos = clientIp.indexOf(']', 1); - clientIps[i] = clientIp = clientIp.substring(1, pos); - } - - if (!isValidIp(clientIp)) { - clientIps.removeAt(i); - i--; - continue; - } - - if (IpUtils.checkIp(clientIp, trustedProxies)) { - clientIps.removeAt(i); - i--; - - // Fallback to this when the client IP falls into the range of trusted proxies - firstTrustedIp ??= clientIp; - } - } - - // Now the IP chain contains only untrusted proxies and the client IP - return clientIps.isNotEmpty ? clientIps.reversed.toList() : [if (firstTrustedIp != null) firstTrustedIp]; - } - - bool isIisRewrite() { - if (server.getInt('IIS_WasUrlRewritten') == 1) { - isIisRewrite = true; - server.remove('IIS_WasUrlRewritten'); - } - return isIisRewrite; - } - - bool isValidIp(String ip) { - return RegExp(r'^(\d{1,3}\.){3}\d{1,3}$').hasMatch(ip) || RegExp(r'^[0-9a-fA-F:]+$').hasMatch(ip); - } -} diff --git a/packages/http/lib/src/foundation/response_header_bag.dart b/packages/http/lib/src/foundation/response_header_bag.dart deleted file mode 100644 index d7cd3fd..0000000 --- a/packages/http/lib/src/foundation/response_header_bag.dart +++ /dev/null @@ -1,530 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the symfony ResponseHeaderBag.php class to Dart - * - * (C) Protevus - * (C) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'package:protevus_http/foundation.dart'; - -/// ResponseHeaderBag is a container for HTTP response headers. -/// -/// This class extends HeaderBag and provides additional functionality specific to -/// handling response headers. It includes methods for managing cookies, cache control, -/// and other HTTP response-specific headers. -/// -/// Key features: -/// - Manages cookies with support for different domains and paths -/// - Handles cache control headers and directives -/// - Preserves case-sensitive header names -/// - Provides methods for setting, getting, and removing headers -/// - Implements special handling for certain headers like 'Set-Cookie' and 'Cache-Control' -/// -/// The class uses several data structures to manage headers efficiently: -/// - [computedCacheControl]: Stores parsed cache control directives -/// - [cookies]: A nested map structure for storing cookies by domain, path, and name -/// - [headerNames]: Preserves the original case of header names -/// -/// It also provides constants for cookie formats and content disposition types. -/// -/// This class is designed to be used in HTTP response handling, particularly -/// in web frameworks and server-side applications. -class ResponseHeaderBag extends HeaderBag { - - /// A constant string representing the 'flat' format for cookies. - /// - /// This constant is used in methods that deal with cookie formatting, - /// particularly in the `getCookies` method, to specify that cookies - /// should be returned in a flat list structure. - static const String COOKIES_FLAT = 'flat'; - - /// A constant string representing the 'array' format for cookies. - /// - /// This constant is used in methods that deal with cookie formatting, - /// particularly in the `getCookies` method, to specify that cookies - /// should be returned in an array structure. - static const String COOKIES_ARRAY = 'array'; - - /// A constant string representing the 'attachment' disposition type for headers. - /// - /// This constant is typically used when setting the Content-Disposition header - /// to indicate that the content should be downloaded as an attachment rather - /// than displayed inline in the browser. - static const String DISPOSITION_ATTACHMENT = 'attachment'; - - /// A constant string representing the 'inline' disposition type for headers. - /// - /// This constant is typically used when setting the Content-Disposition header - /// to indicate that the content should be displayed inline in the browser - /// rather than downloaded as an attachment. - static const String DISPOSITION_INLINE = 'inline'; - - /// A map that stores computed cache control directives. - /// - /// This map is used to cache the parsed values of the Cache-Control header. - /// The keys are the directive names (e.g., 'max-age', 'public', 'private'), - /// and the values are the corresponding directive values. - /// - /// This cache is updated whenever the Cache-Control header is set or modified, - /// and it's used to provide quick access to cache control directives without - /// having to re-parse the header string each time. - Map computedCacheControl = {}; - -/// A nested map structure representing cookies. -/// -/// The structure is as follows: -/// - The outermost map's key is the domain (String). -/// - The middle map's key is the path (String). -/// - The innermost map's key is the cookie name (String). -/// - The value of the innermost map is the Cookie object. -/// -/// This structure allows for efficient storage and retrieval of cookies -/// based on their domain, path, and name. - Map>> cookies = {}; - -/// A map that stores the original case-sensitive names of headers. -/// -/// This map is used to preserve the original capitalization of header names -/// when they are set or retrieved. The keys are the lowercase versions of -/// the header names, and the values are the original case-sensitive names. -/// -/// For example, if a header "Content-Type" is set, this map would contain -/// an entry with key "content-type" and value "Content-Type". -/// -/// This allows the class to maintain case-insensitive header lookup while -/// still being able to return headers with their original capitalization. - Map headerNames = {}; - - /// Constructor for the ResponseHeaderBag class. - /// - /// This constructor initializes a new ResponseHeaderBag instance with the given headers. - /// If no headers are provided, an empty map is used. - /// - /// The constructor performs two important initializations: - /// 1. If the 'cache-control' header is not present in the provided headers, - /// it sets an empty 'Cache-Control' header. - /// 2. If the 'date' header is not present, it initializes the 'Date' header - /// with the current date and time. - /// - /// These initializations ensure that the response complies with RFC2616 - 14.18, - /// which states that all Responses need to have a Date header. - /// - /// @param headers An optional map of headers to initialize the ResponseHeaderBag with. - /// If not provided, an empty map is used. - ResponseHeaderBag([Map>? headers]) : super(headers ?? {}) { - if (!headers!.containsKey('cache-control')) { - set('Cache-Control', ''); - } - - // RFC2616 - 14.18 says all Responses need to have a Date - if (!headers.containsKey('date')) { - initDate(); - } - } - - /// Returns all headers with their original case-sensitive names preserved. - /// - /// This method creates a new map of headers where the keys (header names) - /// maintain their original capitalization as stored in the [headerNames] map. - /// If a header name is not found in [headerNames], the original name is used. - /// - /// @return A Map> where keys are the original case-sensitive - /// header names and values are lists of corresponding header values. - Map> allPreserveCase() { - final headers = >{}; - super.all().forEach((name, value) { - headers[headerNames[name] ?? name] = value; - }); - return headers; - } - - /// Returns all headers with their original case-sensitive names preserved, excluding cookies. - /// - /// This method creates a new map of headers where the keys (header names) - /// maintain their original capitalization as stored in the [headerNames] map. - /// It uses the [allPreserveCase] method to get all headers, and then removes - /// the 'Set-Cookie' header (if present) from the result. - /// - /// @return A Map> where keys are the original case-sensitive - /// header names (excluding 'Set-Cookie') and values are lists of corresponding header values. - Map> allPreserveCaseWithoutCookies() { - final headers = allPreserveCase(); - if (headerNames.containsKey('set-cookie')) { - headers.remove(headerNames['set-cookie']); - } - return headers; - } - - /// Replaces the current headers with new headers. - /// - /// This method clears the existing headers and replaces them with the provided ones. - /// It also performs the following actions: - /// 1. Resets the [headerNames] map, which is used to preserve the original case of header names. - /// 2. If the new headers don't include a 'cache-control' header, it sets an empty 'Cache-Control' header. - /// 3. If the new headers don't include a 'date' header, it initializes the 'Date' header with the current date and time. - /// - /// These actions ensure that the response always has the necessary headers as per HTTP standards, - /// particularly adhering to RFC2616 - 14.18 which requires all Responses to have a Date header. - /// - /// @param headers An optional map of headers to replace the current headers. - /// If not provided, an empty map is used. - @override - void replace([Map>? headers]) { - headerNames = {}; - super.replace(headers ?? {}); - if (!headers!.containsKey('cache-control')) { - set('Cache-Control', ''); - } - if (!headers.containsKey('date')) { - initDate(); - } - } - - /// Returns all headers, optionally filtered by a key. - /// - /// If a [key] is provided, this method returns a map containing only the header - /// for that key. The key is case-insensitive. If the key is 'set-cookie', - /// it returns all cookies formatted as strings. - /// - /// If no [key] is provided, it returns all headers, including all cookies - /// under the 'set-cookie' key. - /// - /// @param key An optional header key to filter the results. - /// @return A map where keys are header names and values are lists of header values. - /// For 'set-cookie', each value in the list is a formatted cookie string. - @override - Map> all([String? key]) { - final headers = super.all(); - if (key != null) { - final uniqueKey = key.toLowerCase(); - if (uniqueKey != 'set-cookie') { - return {uniqueKey: headers[uniqueKey] ?? []}; - } else { - return {'set-cookie': cookies.values.expand((path) => path.values.expand((cookie) => cookie.values)).map((cookie) => cookie.toString()).toList()}; - } - } - - for (var path in cookies.values) { - for (var cookie in path.values) { - headers['set-cookie'] ??= []; - headers['set-cookie']!.add(cookie.toString()); - } - } - return headers; - } - - /// Sets a header value. - /// - /// This method sets a header with the given key and value(s). It handles special cases for - /// certain headers, particularly 'set-cookie' and cache-related headers. - /// - /// For 'set-cookie': - /// - If replace is true, it clears existing cookies before setting new ones. - /// - It creates Cookie objects from the provided string values. - /// - /// For cache-related headers ('cache-control', 'etag', 'last-modified', 'expires'): - /// - It recalculates the Cache-Control header based on the new values. - /// - It updates the computed cache control directives. - /// - /// @param key The name of the header to set. - /// @param values The value(s) to set for the header. Can be a single value or a list. - /// @param replace Whether to replace existing values (true) or append to them (false). - /// Defaults to true. - @override - void set(String key, dynamic values, [bool replace = true]) { - final uniqueKey = key.toLowerCase(); - if (uniqueKey == 'set-cookie') { - if (replace) { - cookies = {}; - } - for (var cookie in List.from(values)) { - setCookie(Cookie.fromString(cookie)); - } - headerNames[uniqueKey] = key; - return; - } - headerNames[uniqueKey] = key; - super.set(key, values, replace); - - // Ensure the cache-control header has sensible defaults - if (['cache-control', 'etag', 'last-modified', 'expires'].contains(uniqueKey)) { - final computedValue = computeCacheControlValue(); - super.set('Cache-Control', computedValue, replace); - headerNames['cache-control'] = 'Cache-Control'; - computedCacheControl = parseCacheControl(computedValue); - } - } - - /// Removes a header from the response. - /// - /// This method removes the specified header from the response. It handles special cases for - /// certain headers: - /// - /// - For 'set-cookie': Clears all cookies. - /// - For 'cache-control': Clears the computed cache control directives. - /// - For 'date': Reinitializes the Date header with the current date and time. - /// - /// The method is case-insensitive for the header name. - /// - /// @param key The name of the header to remove. - @override - void remove(String key) { - final uniqueKey = key.toLowerCase(); - headerNames.remove(uniqueKey); - if (uniqueKey == 'set-cookie') { - cookies = {}; - return; - } - super.remove(key); - if (uniqueKey == 'cache-control') { - computedCacheControl = {}; - } - if (uniqueKey == 'date') { - initDate(); - } - } - - /// Checks if a specific cache-control directive exists in the computed cache control. - /// - /// This method checks whether the given [key] exists as a directive in the - /// [computedCacheControl] map. The [computedCacheControl] map contains - /// parsed cache control directives from the Cache-Control header. - /// - /// @param key The cache control directive to check for. - /// @return true if the directive exists, false otherwise. - @override - bool hasCacheControlDirective(String key) { - return computedCacheControl.containsKey(key); - } - - /// Retrieves the value of a specific cache-control directive. - /// - /// This method returns the value associated with the given [key] from the - /// [computedCacheControl] map. The [computedCacheControl] map contains - /// parsed cache control directives from the Cache-Control header. - /// - /// @param key The cache control directive to retrieve. - /// @return The value of the cache control directive, or null if the directive doesn't exist. - @override - dynamic getCacheControlDirective(String key) { - return computedCacheControl[key]; - } - - /// Sets a cookie in the ResponseHeaderBag. - /// - /// This method adds or updates a cookie in the [cookies] map structure. - /// If the cookie's domain or path doesn't exist in the map, it creates - /// the necessary nested maps. The cookie is then stored using its name as the key. - /// - /// Additionally, it updates the [headerNames] map to ensure that 'set-cookie' - /// is mapped to 'Set-Cookie', maintaining proper header capitalization. - /// - /// @param cookie The Cookie object to be set in the response. - void setCookie(Cookie cookie) { - cookies.putIfAbsent(cookie.domain ?? '', () => {}) - .putIfAbsent(cookie.path, () => {})[cookie.name] = cookie; - headerNames['set-cookie'] = 'Set-Cookie'; - } - - /// Removes a cookie from the array, but does not unset it in the browser. - /// - /// This method removes the specified cookie from the internal [cookies] structure. - /// It does not send any instructions to the browser to delete the cookie. - /// - /// The method navigates through the nested map structure of [cookies], - /// removing the cookie and cleaning up empty maps along the way. - /// - /// If all cookies are removed, it also removes the 'set-cookie' entry from [headerNames]. - /// - /// @param name The name of the cookie to remove. - /// @param path The path of the cookie. Defaults to '/'. - /// @param domain The domain of the cookie. If null, it will attempt to remove - /// the cookie from all domains. - void removeCookie(String name, [String? path = '/', String? domain]) { - path ??= '/'; - final domainCookies = cookies[domain] ?? {}; - final pathCookies = domainCookies[path] ?? {}; - pathCookies.remove(name); - - if (pathCookies.isEmpty) { - domainCookies.remove(path); - if (domainCookies.isEmpty) { - cookies.remove(domain); - } - } - - if (cookies.isEmpty) { - headerNames.remove('set-cookie'); - } - } - - /// Returns an array of cookies based on the specified format. - /// - /// This method retrieves all cookies stored in the ResponseHeaderBag and returns them - /// in the format specified by the [format] parameter. - /// - /// @param format The format in which to return the cookies. Can be either - /// [COOKIES_FLAT] (default) or [COOKIES_ARRAY]. - /// - [COOKIES_FLAT]: Returns a flat list of all cookies. - /// - [COOKIES_ARRAY]: Returns a list of all cookies without flattening. - /// - /// @return A List containing all cookies in the specified format. - /// - /// @throws ArgumentError If the provided format is not valid (i.e., not COOKIES_FLAT or COOKIES_ARRAY). - List getCookies([String format = COOKIES_FLAT]) { - if (!([COOKIES_FLAT, COOKIES_ARRAY].contains(format))) { - throw ArgumentError('Format "$format" invalid (${[COOKIES_FLAT, COOKIES_ARRAY].join(', ')}).'); - } - - if (format == COOKIES_ARRAY) { - return cookies.values.expand((path) => path.values.expand((cookie) => cookie.values)).toList(); - } - - final flattenedCookies = []; - for (var path in cookies.values) { - for (var domainCookies in path.values) { - for (var cookie in domainCookies.values) { - flattenedCookies.add(cookie); - } - } - } - return flattenedCookies; - } - - /// Clears a cookie in the browser. - /// - /// This method sets a cookie with the given name to null and expires it - /// immediately, effectively clearing it from the browser. - /// - /// @param name The name of the cookie to clear. - /// @param path The path for which the cookie is valid. Defaults to '/'. - /// @param domain The domain for which the cookie is valid. - /// @param secure Whether the cookie should only be transmitted over secure protocols. Defaults to false. - /// @param httpOnly Whether the cookie should be accessible only through the HTTP protocol. Defaults to true. - /// @param sameSite The SameSite attribute for the cookie. Can be 'Lax', 'Strict', or 'None'. - /// @param partitioned Whether the cookie should be partitioned. Defaults to false. - void clearCookie(String name, - [String? path = '/', String? domain, bool secure = false, bool httpOnly = true, String? sameSite, bool partitioned = false]) { - final cookieString = '$name=null; Expires=${DateTime.fromMillisecondsSinceEpoch(1).toUtc().toIso8601String()}; Path=${path ?? "/"}; Domain=$domain${secure ? "; Secure" : ""}${httpOnly ? "; HttpOnly" : ""}${sameSite != null ? "; SameSite=$sameSite" : ""}${partitioned ? "; Partitioned" : ""}'; - setCookie(Cookie.fromString(cookieString)); - } - - /// Creates a Content-Disposition header value. - /// - /// This method generates a Content-Disposition header value based on the provided parameters. - /// It uses the HeaderUtils.makeDisposition method to create the header value. - /// - /// @param disposition The disposition type, typically either 'attachment' or 'inline'. - /// @param filename The primary filename to be used in the Content-Disposition header. - /// @param filenameFallback An optional fallback filename to be used if the primary filename - /// contains characters not supported by all user agents. Defaults to an empty string. - /// - /// @return A string representing the Content-Disposition header value. - String makeDisposition(String disposition, String filename, [String filenameFallback = '']) { - return HeaderUtils.makeDisposition(disposition, filename, filenameFallback); - } - - /// Computes and returns the value for the Cache-Control header. - /// - /// This method determines the appropriate Cache-Control value based on the current state - /// of the response headers and the computed cache control directives. - /// - /// The logic is as follows: - /// 1. If no cache control directives have been computed: - /// - If 'Last-Modified' or 'Expires' headers are present, it returns 'private, must-revalidate'. - /// - Otherwise, it returns a conservative default of 'no-cache, private'. - /// 2. If cache control directives have been computed: - /// - If 'public' or 'private' directives are present, it returns the current header as-is. - /// - If 's-maxage' is not present, it appends ', private' to the current header. - /// - Otherwise, it returns the current header as-is. - /// - /// This method ensures that appropriate caching behavior is set, defaulting to more - /// restrictive caching when specific directives are not explicitly set. - /// - /// @return A String representing the computed Cache-Control header value. - String computeCacheControlValue() { - if (computedCacheControl.isEmpty) { - if (hasHeader('Last-Modified') || hasHeader('Expires')) { - return 'private, must-revalidate'; // allows for heuristic expiration (RFC 7234 Section 4.2.2) in the case of "Last-Modified" - } - - // Conservative by default - return 'no-cache, private'; - } - - final header = getCacheControlHeader(); - if (computedCacheControl.containsKey('public') || computedCacheControl.containsKey('private')) { - return header; - } - - // Public if s-maxage is defined, private otherwise - if (!computedCacheControl.containsKey('s-maxage')) { - return '$header, private'; - } - - return header; - } - - /// Parses a Cache-Control header string into a map of directives. - /// - /// This method takes a Cache-Control header value as input and breaks it down - /// into individual directives. Each directive is then stored in a map where - /// the key is the directive name and the value is the directive's value (if any). - /// - /// The method handles both directives with values (e.g., "max-age=3600") and - /// those without values (e.g., "no-cache"). - /// - /// @param header A string representing the Cache-Control header value. - /// @return A Map where keys are directive names and values are - /// directive values. For directives without values, an empty string is used. - Map parseCacheControl(String header) { - final directives = {}; - for (var directive in header.split(',')) { - final parts = directive.trim().split('='); - directives[parts[0]] = parts.length > 1 ? parts[1] : ''; - } - return directives; - } - - /// Initializes the Date header with the current UTC date and time. - /// - /// This method sets the 'Date' header of the HTTP response to the current - /// date and time in UTC format. The date is formatted according to the - /// ISO 8601 standard. - /// - /// The Date header is important for HTTP responses as it informs the - /// client about the time at which the response was generated by the server. - /// This can be useful for caching mechanisms and for calculating the age - /// of the response. - void initDate() { - set('Date', DateTime.now().toUtc().toIso8601String()); - } - - /// Checks if a header exists in the ResponseHeaderBag. - /// - /// This method checks whether a header with the given [key] exists, - /// regardless of the case of the key. It converts the [key] to lowercase - /// before checking, ensuring case-insensitive matching. - /// - /// @param key The name of the header to check for. - /// @return true if the header exists, false otherwise. - bool containsKey(String key) { - return super.all().containsKey(key.toLowerCase()); - } - - /// Gets the value of a header. - /// - /// This method retrieves the value of the header specified by [key]. - /// The key is case-insensitive. If the header exists, it returns all values - /// joined by a comma and space. If the header doesn't exist, it returns null. - /// - /// @param key The name of the header to retrieve. - /// @return A String containing the header value(s), or null if the header doesn't exist. - String? value(String key) { - return super.all()[key.toLowerCase()]?.join(', '); - } -} diff --git a/packages/http/lib/src/foundation/server_bag.dart b/packages/http/lib/src/foundation/server_bag.dart deleted file mode 100644 index f7577bc..0000000 --- a/packages/http/lib/src/foundation/server_bag.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'dart:collection'; -import 'dart:convert'; -import 'package:protevus_http/foundation.dart'; -import 'package:protevus_http/src/foundation/parameter_bag.dart'; - -/// ServerBag is a container for HTTP headers from the server environment. -/// -/// This class extends ParameterBag and provides functionality to handle -/// HTTP headers, including special cases for authentication headers. -class ServerBag extends ParameterBag - with IterableMixin> { - final Map _parameters; - - /// Creates a new ServerBag instance. - /// - /// The constructor takes a map of server parameters and initializes - /// the ParameterBag with these parameters. - ServerBag([Map parameters = const {}]) - : _parameters = Map.from(parameters), - super(); - - // Override the getter from ParameterBag - @override - Map get parameters => _parameters; - - /// Gets the HTTP headers from the server parameters. - /// - /// This method processes the server parameters to extract and normalize - /// HTTP headers, including special handling for authentication headers. - /// - /// Returns: - /// A Map containing the extracted HTTP headers. - Map getHeaders() { - var headers = {}; - - parameters.forEach((key, value) { - if (key.startsWith('HTTP_')) { - headers[key.substring(5)] = value.toString(); - } else if (['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'] - .contains(key) && - value.toString().isNotEmpty) { - headers[key] = value.toString(); - } - }); - - if (parameters.containsKey('PHP_AUTH_USER')) { - headers['PHP_AUTH_USER'] = parameters['PHP_AUTH_USER'].toString(); - headers['PHP_AUTH_PW'] = parameters['PHP_AUTH_PW']?.toString() ?? ''; - } else { - String? authorizationHeader; - if (parameters.containsKey('HTTP_AUTHORIZATION')) { - authorizationHeader = parameters['HTTP_AUTHORIZATION'].toString(); - } else if (parameters.containsKey('REDIRECT_HTTP_AUTHORIZATION')) { - authorizationHeader = - parameters['REDIRECT_HTTP_AUTHORIZATION'].toString(); - } - - if (authorizationHeader != null) { - if (authorizationHeader.toLowerCase().startsWith('basic ')) { - // Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW - var decoded = - utf8.decode(base64.decode(authorizationHeader.substring(6))); - var exploded = decoded.split(':'); - if (exploded.length == 2) { - headers['PHP_AUTH_USER'] = exploded[0]; - headers['PHP_AUTH_PW'] = exploded[1]; - } - } else if (!parameters.containsKey('PHP_AUTH_DIGEST') && - authorizationHeader.toLowerCase().startsWith('digest ')) { - headers['PHP_AUTH_DIGEST'] = authorizationHeader; - parameters['PHP_AUTH_DIGEST'] = authorizationHeader; - } else if (authorizationHeader.toLowerCase().startsWith('bearer ')) { - headers['AUTHORIZATION'] = authorizationHeader; - } - } - } - - if (headers.containsKey('AUTHORIZATION')) { - return headers; - } - - // PHP_AUTH_USER/PHP_AUTH_PW - if (headers.containsKey('PHP_AUTH_USER')) { - var authUser = headers['PHP_AUTH_USER']!; - var authPw = headers['PHP_AUTH_PW'] ?? ''; - headers['AUTHORIZATION'] = - 'Basic ${base64.encode(utf8.encode('$authUser:$authPw'))}'; - } else if (headers.containsKey('PHP_AUTH_DIGEST')) { - headers['AUTHORIZATION'] = headers['PHP_AUTH_DIGEST']!; - } - - return headers; - } -} diff --git a/packages/http/lib/src/foundation/session/session_bag_interface.dart b/packages/http/lib/src/foundation/session/session_bag_interface.dart deleted file mode 100644 index 9e7b337..0000000 --- a/packages/http/lib/src/foundation/session/session_bag_interface.dart +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * This file is a port of the symfony SesssionBagInterface.php class to Dart - * - * (C) Protevus - * (C) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/// An abstract class defining the interface for session bags. -/// -/// A session bag is a storage mechanism used to group session attributes together. -/// It provides methods to manage and interact with session data. -abstract class SessionBagInterface { - /// Returns the name of this bag. - /// - /// This method should be implemented to provide a unique identifier for the bag. - /// The name is typically used to distinguish between different types of session bags. - /// - /// @return A string representing the name of the bag. - String getName(); - - /// Initializes the bag with the provided data. - /// - /// This method should be implemented to set up the initial state of the bag - /// using the given array of data. It's typically used when restoring a session - /// from storage or creating a new session with default values. - /// - /// @param array A list of dynamic values to initialize the bag with. - void initialize(List array); - - /// Gets the storage key for this bag. - /// - /// This method should be implemented to return a unique identifier used - /// for storing and retrieving the bag's data in the session storage. - /// The storage key is typically used to organize and access different - /// bags within the session storage mechanism. - /// - /// @return A string representing the storage key for this bag. - String getStorageKey(); - - /// Clears out all data from the bag and returns the cleared data. - /// - /// This method should be implemented to remove all stored attributes from the bag. - /// It's typically used when you want to reset the bag to an empty state. - /// - /// @return A dynamic value representing the data that was contained in the bag before clearing. - dynamic clear(); -} diff --git a/packages/http/lib/src/foundation/session/session_interface.dart b/packages/http/lib/src/foundation/session/session_interface.dart deleted file mode 100644 index 0f4da04..0000000 --- a/packages/http/lib/src/foundation/session/session_interface.dart +++ /dev/null @@ -1,85 +0,0 @@ -import 'package:protevus_http/foundation_session.dart'; -import 'package:protevus_http/foundation_storage.dart'; - -/// Interface for the session. -abstract class SessionInterface { - /// Starts the session storage. - /// - /// Throws [StateError] if session fails to start. - bool start(); - - /// Returns the session ID. - String getId(); - - /// Sets the session ID. - void setId(String id); - - /// Returns the session name. - String getName(); - - /// Sets the session name. - void setName(String name); - - /// Invalidates the current session. - /// - /// Clears all session attributes and flashes and regenerates the - /// session and deletes the old session from persistence. - /// - /// [lifetime] Sets the cookie lifetime for the session cookie. A null value - /// will leave the system settings unchanged, 0 sets the cookie - /// to expire with browser session. Time is in seconds, and is - /// not a Unix timestamp. - bool invalidate({int? lifetime}); - - /// Migrates the current session to a new session id while maintaining all - /// session attributes. - /// - /// [destroy] Whether to delete the old session or leave it to garbage collection. - /// [lifetime] Sets the cookie lifetime for the session cookie. A null value - /// will leave the system settings unchanged, 0 sets the cookie - /// to expire with browser session. Time is in seconds, and is - /// not a Unix timestamp. - bool migrate({bool destroy = false, int? lifetime}); - - /// Force the session to be saved and closed. - /// - /// This method is generally not required for real sessions as - /// the session will be automatically saved at the end of - /// code execution. - void save(); - - /// Checks if an attribute is defined. - bool has(String name); - - /// Returns an attribute. - T? get(String name, [T? defaultValue]); - - /// Sets an attribute. - void set(String name, dynamic value); - - /// Returns attributes. - Map all(); - - /// Sets attributes. - void replace(Map attributes); - - /// Removes an attribute. - /// - /// Returns the removed value or null when it does not exist. - T? remove(String name); - - /// Clears all attributes. - void clear(); - - /// Checks if the session was started. - bool isStarted(); - - /// Registers a SessionBagInterface with the session. - void registerBag(SessionBagInterface bag); - - /// Gets a bag instance by name. - SessionBagInterface getBag(String name); - - /// Gets session meta. - MetadataBag getMetadataBag(); -} diff --git a/packages/http/lib/src/foundation/storage/meta_data_bag.dart b/packages/http/lib/src/foundation/storage/meta_data_bag.dart deleted file mode 100644 index a3cedeb..0000000 --- a/packages/http/lib/src/foundation/storage/meta_data_bag.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'dart:io'; -import 'package:protevus_http/foundation_session.dart'; - -/// Metadata container. -/// -/// Adds metadata to the session. -class MetadataBag implements SessionBagInterface { - static const String CREATED = 'c'; - static const String UPDATED = 'u'; - static const String LIFETIME = 'l'; - - Map _meta = {CREATED: 0, UPDATED: 0, LIFETIME: 0}; - - String _name = '__metadata'; - String _storageKey; - late int _lastUsed; - int _updateThreshold; - - /// Constructor for MetadataBag. - /// - /// @param storageKey The key used to store bag in the session - /// @param updateThreshold The time to wait between two UPDATED updates - MetadataBag({String storageKey = '_sf2_meta', int updateThreshold = 0}) - : _storageKey = storageKey, - _updateThreshold = updateThreshold; - - @override - void initialize(List array) { - // In Dart, we can't use a reference to array directly, - // so we'll copy the data and update it as needed - _meta = Map.from(array.first as Map); - - if (_meta.containsKey(CREATED)) { - _lastUsed = _meta[UPDATED]!; - - int timeStamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; - if (timeStamp - _meta[UPDATED]! >= _updateThreshold) { - _meta[UPDATED] = timeStamp; - } - } else { - _stampCreated(); - } - } - - /// Gets the lifetime that the session cookie was set with. - int getLifetime() { - return _meta[LIFETIME]!; - } - - /// Stamps a new session's metadata. - /// - /// @param lifetime Sets the cookie lifetime for the session cookie. A null value - /// will leave the system settings unchanged, 0 sets the cookie - /// to expire with browser session. Time is in seconds, and is - /// not a Unix timestamp. - void stampNew([int? lifetime]) { - _stampCreated(lifetime); - } - - @override - String getStorageKey() { - return _storageKey; - } - - /// Gets the created timestamp metadata. - /// - /// @return Unix timestamp - int getCreated() { - return _meta[CREATED]!; - } - - /// Gets the last used metadata. - /// - /// @return Unix timestamp - int getLastUsed() { - return _lastUsed; - } - - @override - dynamic clear() { - // nothing to do - return null; - } - - @override - String getName() { - return _name; - } - - /// Sets name. - void setName(String name) { - _name = name; - } - - void _stampCreated([int? lifetime]) { - int timeStamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; - _meta[CREATED] = _meta[UPDATED] = _lastUsed = timeStamp; - _meta[LIFETIME] = lifetime ?? - int.parse(Platform.environment['SESSION_COOKIE_LIFETIME'] ?? '0'); - } -} diff --git a/packages/http/lib/src/foundation/stringable_interface.dart b/packages/http/lib/src/foundation/stringable_interface.dart deleted file mode 100644 index 072c078..0000000 --- a/packages/http/lib/src/foundation/stringable_interface.dart +++ /dev/null @@ -1,16 +0,0 @@ -/// Abstract class representing a Stringable object. -/// -/// This class is the Dart equivalent of PHP's Stringable interface. -/// Classes that implement this abstract class must provide an implementation -/// for the toString() method. -abstract class Stringable { - /// Converts the object to its string representation. - /// - /// This method should be implemented by any class that wants to be Stringable. - /// It's the equivalent of PHP's __toString() magic method. - /// - /// Returns: - /// A string representation of the object. - @override - String toString(); -} diff --git a/packages/http/pubspec.yaml b/packages/http/pubspec.yaml index ed20f1a..b1b7cd4 100644 --- a/packages/http/pubspec.yaml +++ b/packages/http/pubspec.yaml @@ -10,11 +10,7 @@ environment: # Add regular dependencies here. dependencies: - sanitize_html: ^2.1.0 - email_validator: ^3.0.0 - validator_dart: ^0.1.0 - protevus_mime: ^0.0.1 - path: ^1.9.0 + #path: ^1.9.0 dev_dependencies: lints: ^3.0.0 diff --git a/packages/mime/.gitignore b/packages/mime/.gitignore deleted file mode 100644 index 3cceda5..0000000 --- a/packages/mime/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# https://dart.dev/guides/libraries/private-files -# Created by `dart pub` -.dart_tool/ - -# Avoid committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock diff --git a/packages/mime/CHANGELOG.md b/packages/mime/CHANGELOG.md deleted file mode 100644 index effe43c..0000000 --- a/packages/mime/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 1.0.0 - -- Initial version. diff --git a/packages/mime/README.md b/packages/mime/README.md deleted file mode 100644 index 8b55e73..0000000 --- a/packages/mime/README.md +++ /dev/null @@ -1,39 +0,0 @@ - - -TODO: Put a short description of the package here that helps potential users -know whether this package might be useful for them. - -## Features - -TODO: List what your package can do. Maybe include images, gifs, or videos. - -## Getting started - -TODO: List prerequisites and provide or point to information on how to -start using the package. - -## Usage - -TODO: Include short and useful examples for package users. Add longer examples -to `/example` folder. - -```dart -const like = 'sample'; -``` - -## Additional information - -TODO: Tell users more about the package: where to find more information, how to -contribute to the package, how to file issues, what response they can expect -from the package authors, and more. diff --git a/packages/mime/analysis_options.yaml b/packages/mime/analysis_options.yaml deleted file mode 100644 index dee8927..0000000 --- a/packages/mime/analysis_options.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# This file configures the static analysis results for your project (errors, -# warnings, and lints). -# -# This enables the 'recommended' set of lints from `package:lints`. -# This set helps identify many issues that may lead to problems when running -# or consuming Dart code, and enforces writing Dart using a single, idiomatic -# style and format. -# -# If you want a smaller set of lints you can change this to specify -# 'package:lints/core.yaml'. These are just the most critical lints -# (the recommended set includes the core lints). -# The core lints are also what is used by pub.dev for scoring packages. - -include: package:lints/recommended.yaml - -# Uncomment the following section to specify additional rules. - -# linter: -# rules: -# - camel_case_types - -# analyzer: -# exclude: -# - path/to/excluded/files/** - -# For more information about the core and recommended set of lints, see -# https://dart.dev/go/core-lints - -# For additional information about configuring this file, see -# https://dart.dev/guides/language/analysis-options diff --git a/packages/mime/lib/mime.dart b/packages/mime/lib/mime.dart deleted file mode 100644 index 887614e..0000000 --- a/packages/mime/lib/mime.dart +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -library; - -export 'src/mime_type_guesser_interface.dart'; -export 'src/file_binary_mime_type_guesser.dart'; -export 'src/file_info_mime_type_guesser.dart'; -export 'src/mime_types_interface.dart'; -export 'src/mime_types.dart'; diff --git a/packages/mime/lib/mime_exception.dart b/packages/mime/lib/mime_exception.dart deleted file mode 100644 index dd07d6c..0000000 --- a/packages/mime/lib/mime_exception.dart +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -library; - -export 'src/exception/exception_interface.dart'; -export 'src/exception/invalid_argument_exception.dart'; -export 'src/exception/logic_exception.dart'; diff --git a/packages/mime/lib/src/exception/exception_interface.dart b/packages/mime/lib/src/exception/exception_interface.dart deleted file mode 100644 index f337a14..0000000 --- a/packages/mime/lib/src/exception/exception_interface.dart +++ /dev/null @@ -1,24 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -// In Dart, we don't have a direct equivalent of PHP's namespace. -// Instead, we use library or part directives to organize code. -// For this example, we'll assume this is part of a library called 'symfony_mime'. - -// Dart doesn't have a direct equivalent to PHP's Throwable interface. -// Instead, we'll use the Exception class as the base for our interface. - -/// Exception interface for the Symfony MIME component. -/// -/// This interface is used to mark exceptions specific to the MIME component. -/// It doesn't add any additional methods but serves as a marker interface. -/// -/// @author Fabien Potencier -abstract class ExceptionInterface implements Exception { - // This interface doesn't declare any methods. - // It's used as a marker interface in Dart, similar to its use in PHP. -} diff --git a/packages/mime/lib/src/exception/invalid_argument_exception.dart b/packages/mime/lib/src/exception/invalid_argument_exception.dart deleted file mode 100644 index bad2bed..0000000 --- a/packages/mime/lib/src/exception/invalid_argument_exception.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'dart:core'; -import 'exception_interface.dart'; - -/// @author Fabien Potencier -class InvalidArgumentException implements Exception, ExceptionInterface { - final String message; - - // Constructor in Dart - InvalidArgumentException([this.message = '']); - - @override - String toString() => 'InvalidArgumentException: $message'; -} diff --git a/packages/mime/lib/src/exception/logic_exception.dart b/packages/mime/lib/src/exception/logic_exception.dart deleted file mode 100644 index b0d6bd1..0000000 --- a/packages/mime/lib/src/exception/logic_exception.dart +++ /dev/null @@ -1,57 +0,0 @@ -class LogicException implements Exception { - final String message; - final int code; - final Exception? previous; - final StackTrace? stackTrace; - - LogicException( - [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 getTrace() { - return stackTrace?.toString().split('\n') ?? []; - } - - String getTraceAsString() { - return stackTrace?.toString() ?? ""; - } -} diff --git a/packages/mime/lib/src/file_binary_mime_type_guesser.dart b/packages/mime/lib/src/file_binary_mime_type_guesser.dart deleted file mode 100644 index c09564f..0000000 --- a/packages/mime/lib/src/file_binary_mime_type_guesser.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'dart:io'; -import 'package:protevus_mime/mime_exception.dart'; -import 'package:protevus_mime/mime.dart'; - -/// This file is part of the Symfony package. -/// -/// (c) Fabien Potencier -/// -/// For the full copyright and license information, please view the LICENSE -/// file that was distributed with this source code. - -/// Guesses the MIME type with the binary "file" (only available on *nix). -/// -/// @author Bernhard Schussek -class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface { - /// The command to run to get the MIME type of a file. - /// - /// The $cmd pattern must contain a "%s" string that will be replaced - /// with the file name to guess. - /// - /// The command output must start with the MIME type of the file. - final String _cmd; - - /// Creates a new [FileBinaryMimeTypeGuesser] instance. - /// - /// [cmd] The command to run to get the MIME type of a file. - FileBinaryMimeTypeGuesser([this._cmd = 'file -b --mime -- %s 2>/dev/null']); - - @override - bool isGuesserSupported() { - // Dart doesn't have a direct equivalent to PHP's static variables inside methods, - // so we'll use a top-level variable instead. - return isGuesserSupportedCached(); - } - - @override - Future guessMimeType(String filePath) async { - if (!File(filePath).existsSync() || - !File(filePath).statSync().modeString().contains('r')) { - throw InvalidArgumentException( - 'The "$filePath" file does not exist or is not readable.'); - } - - if (!isGuesserSupported()) { - throw LogicException( - 'The "${runtimeType.toString()}" guesser is not supported.'); - } - - final result = await Process.run( - 'sh', ['-c', _cmd.replaceFirst('%s', _escapeShellArg(filePath))]); - - if (result.exitCode > 0) { - return null; - } - - final type = result.stdout.toString().trim(); - final match = - RegExp(r'^([a-z0-9\-]+/[a-z0-9\-\+\.]+)', caseSensitive: false) - .firstMatch(type); - - if (match == null) { - // it's not a type, but an error message - return null; - } - - return match.group(1); - } - - String _escapeShellArg(String arg) { - return "'${arg.replaceAll("'", "'\\''")}'"; - } -} - -bool? _supportedCache; - -bool isGuesserSupportedCached() { - if (_supportedCache != null) { - return _supportedCache!; - } - - if (Platform.isWindows || !_hasCommand('file')) { - return _supportedCache = false; - } - - return _supportedCache = true; -} - -bool _hasCommand(String command) { - try { - final result = Process.runSync('which', [command]); - return result.exitCode == 0 && result.stdout.toString().trim().isNotEmpty; - } catch (e) { - return false; - } -} diff --git a/packages/mime/lib/src/file_info_mime_type_guesser.dart b/packages/mime/lib/src/file_info_mime_type_guesser.dart deleted file mode 100644 index b26aa41..0000000 --- a/packages/mime/lib/src/file_info_mime_type_guesser.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'dart:io'; -import 'package:mime/mime.dart' as mime; - -import 'package:protevus_mime/mime_exception.dart'; -import 'package:protevus_mime/mime.dart'; - -/// Guesses the MIME type using the MIME package, which is similar to PHP's FileInfo. -/// -/// @author Bernhard Schussek -/// Ported to Dart by [Your Name] -class FileInfoMimeTypeGuesser implements MimeTypeGuesserInterface { - /// Constructs a new FileinfoMimeTypeGuesser. - FileInfoMimeTypeGuesser(); - - @override - bool isGuesserSupported() { - // In Dart, we're using the mime package which is always available if imported - return true; - } - - @override - Future guessMimeType(String path) async { - final file = File(path); - - if (!await file.exists() || - !(await file.stat()).type.toString().contains('file')) { - throw InvalidArgumentException( - 'The "$path" file does not exist or is not readable.'); - } - - if (!isGuesserSupported()) { - throw LogicException( - 'The "${runtimeType.toString()}" guesser is not supported.'); - } - - String? mimeType; - try { - // Using the mime package to guess the MIME type - final bytes = await file.openRead(0, 12).first; - mimeType = mime.lookupMimeType(path, headerBytes: bytes); - } catch (e) { - print('Error guessing MIME type: $e'); - return null; - } - - if (mimeType != null && mimeType.length % 2 == 0) { - final mimeStart = mimeType.substring(0, mimeType.length ~/ 2); - if (mimeStart + mimeStart == mimeType) { - mimeType = mimeStart; - } - } - - return mimeType; - } -} diff --git a/packages/mime/lib/src/mime_type_guesser_interface.dart b/packages/mime/lib/src/mime_type_guesser_interface.dart deleted file mode 100644 index 1434323..0000000 --- a/packages/mime/lib/src/mime_type_guesser_interface.dart +++ /dev/null @@ -1,22 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -import 'dart:io'; - -/// Guesses the MIME type of a file. -/// -/// @author Fabien Potencier -abstract class MimeTypeGuesserInterface { - /// Returns true if this guesser is supported. - bool isGuesserSupported(); - - /// Guesses the MIME type of the file with the given path. - /// - /// Throws [UnsupportedError] if the guesser is not supported - /// Throws [FileSystemException] if the file does not exist or is not readable - Future guessMimeType(String path); -} diff --git a/packages/mime/lib/src/mime_types.dart b/packages/mime/lib/src/mime_types.dart deleted file mode 100644 index 0c03c7a..0000000 --- a/packages/mime/lib/src/mime_types.dart +++ /dev/null @@ -1,3872 +0,0 @@ -import 'package:protevus_mime/mime_exception.dart'; -import 'package:protevus_mime/mime.dart'; - -final class MimeTypes implements MimeTypesInterface { - final Map> _extensions = {}; - final Map> _mimeTypes = {}; - final List _guessers = []; - static late MimeTypes? _default; - - /// A map of MIME types to their corresponding file extensions. - /// - /// This map provides a comprehensive list of MIME types as keys, with each key - /// associated with a list of file extensions that correspond to that MIME type. - /// It can be used for tasks such as determining the appropriate MIME type for a - /// given file extension, or finding all possible file extensions for a specific - /// MIME type. - /// - /// The map covers a wide range of file types, including but not limited to: - /// - Document formats (PDF, Word, Excel, etc.) - /// - Image formats (JPEG, PNG, GIF, etc.) - /// - Audio and video formats (MP3, MP4, AVI, etc.) - /// - Archive formats (ZIP, RAR, etc.) - /// - Programming language files (Java, Python, C++, etc.) - /// - Web-related formats (HTML, CSS, JavaScript, etc.) - /// - /// This comprehensive mapping can be particularly useful in applications that - /// deal with file type detection, content type negotiation, or file handling - /// based on MIME types. - static final Map> MAP = { - 'application/acrobat': ['pdf'], - 'application/andrew-inset': ['ez'], - 'application/annodex': ['anx'], - 'application/appinstaller': ['appinstaller'], - 'application/applixware': ['aw'], - 'application/appx': ['appx'], - 'application/appxbundle': ['appxbundle'], - 'application/atom+xml': ['atom'], - 'application/atomcat+xml': ['atomcat'], - 'application/atomdeleted+xml': ['atomdeleted'], - 'application/atomsvc+xml': ['atomsvc'], - 'application/atsc-dwd+xml': ['dwd'], - 'application/atsc-held+xml': ['held'], - 'application/atsc-rsat+xml': ['rsat'], - 'application/bat': ['bat'], - 'application/bdoc': ['bdoc'], - 'application/bzip2': ['bz2', 'bz'], - 'application/calendar+xml': ['xcs'], - 'application/cbor': ['cbor'], - 'application/ccxml+xml': ['ccxml'], - 'application/cdfx+xml': ['cdfx'], - 'application/cdmi-capability': ['cdmia'], - 'application/cdmi-container': ['cdmic'], - 'application/cdmi-domain': ['cdmid'], - 'application/cdmi-object': ['cdmio'], - 'application/cdmi-queue': ['cdmiq'], - 'application/cdr': ['cdr'], - 'application/coreldraw': ['cdr'], - 'application/cpl+xml': ['cpl'], - 'application/csv': ['csv'], - 'application/cu-seeme': ['cu'], - 'application/dash+xml': ['mpd'], - 'application/dash-patch+xml': ['mpp'], - 'application/davmount+xml': ['davmount'], - 'application/dbase': ['dbf'], - 'application/dbf': ['dbf'], - 'application/dicom': ['dcm'], - 'application/docbook+xml': ['dbk', 'docbook'], - 'application/dssc+der': ['dssc'], - 'application/dssc+xml': ['xdssc'], - 'application/ecmascript': ['ecma', 'es'], - 'application/emf': ['emf'], - 'application/emma+xml': ['emma'], - 'application/emotionml+xml': ['emotionml'], - 'application/epub+zip': ['epub'], - 'application/exi': ['exi'], - 'application/express': ['exp'], - 'application/fdt+xml': ['fdt'], - 'application/fits': ['fits', 'fit', 'fts'], - 'application/font-tdpfr': ['pfr'], - 'application/font-woff': ['woff'], - 'application/futuresplash': ['swf', 'spl'], - 'application/geo+json': ['geojson', 'geo.json'], - 'application/gml+xml': ['gml'], - 'application/gnunet-directory': ['gnd'], - 'application/gpx': ['gpx'], - 'application/gpx+xml': ['gpx'], - 'application/gxf': ['gxf'], - 'application/gzip': ['gz'], - 'application/hjson': ['hjson'], - 'application/hta': ['hta'], - 'application/hyperstudio': ['stk'], - 'application/ico': ['ico'], - 'application/ics': ['vcs', 'ics'], - 'application/illustrator': ['ai'], - 'application/inkml+xml': ['ink', 'inkml'], - 'application/ipfix': ['ipfix'], - 'application/its+xml': ['its'], - 'application/java': ['class'], - 'application/java-archive': ['jar', 'war', 'ear'], - 'application/java-byte-code': ['class'], - 'application/java-serialized-object': ['ser'], - 'application/java-vm': ['class'], - 'application/javascript': ['js', 'mjs', 'jsm'], - 'application/jrd+json': ['jrd'], - 'application/json': ['json', 'map'], - 'application/json-patch+json': ['json-patch'], - 'application/json5': ['json5'], - 'application/jsonml+json': ['jsonml'], - 'application/ld+json': ['jsonld'], - 'application/lgr+xml': ['lgr'], - 'application/lost+xml': ['lostxml'], - 'application/lotus123': ['123', 'wk1', 'wk3', 'wk4', 'wks'], - 'application/m3u': ['m3u', 'm3u8', 'vlc'], - 'application/mac-binhex40': ['hqx'], - 'application/mac-compactpro': ['cpt'], - 'application/mads+xml': ['mads'], - 'application/manifest+json': ['webmanifest'], - 'application/marc': ['mrc'], - 'application/marcxml+xml': ['mrcx'], - 'application/mathematica': ['ma', 'nb', 'mb'], - 'application/mathml+xml': ['mathml', 'mml'], - 'application/mbox': ['mbox'], - 'application/mdb': ['mdb'], - 'application/media-policy-dataset+xml': ['mpf'], - 'application/mediaservercontrol+xml': ['mscml'], - 'application/metalink+xml': ['metalink'], - 'application/metalink4+xml': ['meta4'], - 'application/mets+xml': ['mets'], - 'application/microsoftpatch': ['msp'], - 'application/microsoftupdate': ['msu'], - 'application/mmt-aei+xml': ['maei'], - 'application/mmt-usd+xml': ['musd'], - 'application/mods+xml': ['mods'], - 'application/mp21': ['m21', 'mp21'], - 'application/mp4': ['mp4s', 'm4p'], - 'application/mrb-consumer+xml': ['xdf'], - 'application/mrb-publish+xml': ['xdf'], - 'application/ms-tnef': ['tnef', 'tnf'], - 'application/msaccess': ['mdb'], - 'application/msexcel': [ - 'xls', - 'xlc', - 'xll', - 'xlm', - 'xlw', - 'xla', - 'xlt', - 'xld' - ], - 'application/msix': ['msix'], - 'application/msixbundle': ['msixbundle'], - 'application/mspowerpoint': ['ppz', 'ppt', 'pps', 'pot'], - 'application/msword': ['doc', 'dot'], - 'application/msword-template': ['dot'], - 'application/mxf': ['mxf'], - 'application/n-quads': ['nq'], - 'application/n-triples': ['nt'], - 'application/nappdf': ['pdf'], - 'application/node': ['cjs'], - 'application/octet-stream': [ - 'bin', - 'dms', - 'lrf', - 'mar', - 'so', - 'dist', - 'distz', - 'pkg', - 'bpk', - 'dump', - 'elc', - 'deploy', - 'exe', - 'dll', - 'deb', - 'dmg', - 'iso', - 'img', - 'msi', - 'msp', - 'msm', - 'buffer' - ], - 'application/oda': ['oda'], - 'application/oebps-package+xml': ['opf'], - 'application/ogg': ['ogx'], - 'application/omdoc+xml': ['omdoc'], - 'application/onenote': ['onetoc', 'onetoc2', 'onetmp', 'onepkg'], - 'application/ovf': ['ova'], - 'application/owl+xml': ['owx'], - 'application/oxps': ['oxps'], - 'application/p2p-overlay+xml': ['relo'], - 'application/patch-ops-error+xml': ['xer'], - 'application/pcap': ['pcap', 'cap', 'dmp'], - 'application/pdf': ['pdf'], - 'application/pgp': ['pgp', 'gpg', 'asc'], - 'application/pgp-encrypted': ['pgp', 'gpg', 'asc'], - 'application/pgp-keys': ['asc', 'skr', 'pkr', 'pgp', 'gpg', 'key'], - 'application/pgp-signature': ['asc', 'sig', 'pgp', 'gpg'], - 'application/photoshop': ['psd'], - 'application/pics-rules': ['prf'], - 'application/pkcs10': ['p10'], - 'application/pkcs12': ['p12', 'pfx'], - 'application/pkcs7-mime': ['p7m', 'p7c'], - 'application/pkcs7-signature': ['p7s'], - 'application/pkcs8': ['p8'], - 'application/pkcs8-encrypted': ['p8e'], - 'application/pkix-attr-cert': ['ac'], - 'application/pkix-cert': ['cer'], - 'application/pkix-crl': ['crl'], - 'application/pkix-pkipath': ['pkipath'], - 'application/pkixcmp': ['pki'], - 'application/pls': ['pls'], - 'application/pls+xml': ['pls'], - 'application/postscript': ['ai', 'eps', 'ps'], - 'application/powerpoint': ['ppz', 'ppt', 'pps', 'pot'], - 'application/provenance+xml': ['provx'], - 'application/prs.cww': ['cww'], - 'application/prs.wavefront-obj': ['obj'], - 'application/pskc+xml': ['pskcxml'], - 'application/ram': ['ram'], - 'application/raml+yaml': ['raml'], - 'application/rdf+xml': ['rdf', 'owl', 'rdfs'], - 'application/reginfo+xml': ['rif'], - 'application/relax-ng-compact-syntax': ['rnc'], - 'application/resource-lists+xml': ['rl'], - 'application/resource-lists-diff+xml': ['rld'], - 'application/rls-services+xml': ['rs'], - 'application/route-apd+xml': ['rapd'], - 'application/route-s-tsid+xml': ['sls'], - 'application/route-usd+xml': ['rusd'], - 'application/rpki-ghostbusters': ['gbr'], - 'application/rpki-manifest': ['mft'], - 'application/rpki-roa': ['roa'], - 'application/rsd+xml': ['rsd'], - 'application/rss+xml': ['rss'], - 'application/rtf': ['rtf'], - 'application/sbml+xml': ['sbml'], - 'application/schema+json': ['json'], - 'application/scvp-cv-request': ['scq'], - 'application/scvp-cv-response': ['scs'], - 'application/scvp-vp-request': ['spq'], - 'application/scvp-vp-response': ['spp'], - 'application/sdp': ['sdp'], - 'application/senml+xml': ['senmlx'], - 'application/sensml+xml': ['sensmlx'], - 'application/set-payment-initiation': ['setpay'], - 'application/set-registration-initiation': ['setreg'], - 'application/shf+xml': ['shf'], - 'application/sieve': ['siv', 'sieve'], - 'application/smil': ['smil', 'smi', 'sml', 'kino'], - 'application/smil+xml': ['smi', 'smil', 'sml', 'kino'], - 'application/sparql-query': ['rq', 'qs'], - 'application/sparql-results+xml': ['srx'], - 'application/sql': ['sql'], - 'application/srgs': ['gram'], - 'application/srgs+xml': ['grxml'], - 'application/sru+xml': ['sru'], - 'application/ssdl+xml': ['ssdl'], - 'application/ssml+xml': ['ssml'], - 'application/stuffit': ['sit', 'hqx'], - 'application/swid+xml': ['swidtag'], - 'application/tei+xml': ['tei', 'teicorpus'], - 'application/tga': ['tga', 'icb', 'tpic', 'vda', 'vst'], - 'application/thraud+xml': ['tfi'], - 'application/timestamped-data': ['tsd'], - 'application/toml': ['toml'], - 'application/trig': ['trig'], - 'application/ttml+xml': ['ttml'], - 'application/ubjson': ['ubj'], - 'application/urc-ressheet+xml': ['rsheet'], - 'application/urc-targetdesc+xml': ['td'], - 'application/vnd.1000minds.decision-model+xml': ['1km'], - 'application/vnd.3gpp.pic-bw-large': ['plb'], - 'application/vnd.3gpp.pic-bw-small': ['psb'], - 'application/vnd.3gpp.pic-bw-var': ['pvb'], - 'application/vnd.3gpp2.tcap': ['tcap'], - 'application/vnd.3m.post-it-notes': ['pwn'], - 'application/vnd.accpac.simply.aso': ['aso'], - 'application/vnd.accpac.simply.imp': ['imp'], - 'application/vnd.acucobol': ['acu'], - 'application/vnd.acucorp': ['atc', 'acutc'], - 'application/vnd.adobe.air-application-installer-package+zip': ['air'], - 'application/vnd.adobe.flash.movie': ['swf', 'spl'], - 'application/vnd.adobe.formscentral.fcdt': ['fcdt'], - 'application/vnd.adobe.fxp': ['fxp', 'fxpl'], - 'application/vnd.adobe.illustrator': ['ai'], - 'application/vnd.adobe.xdp+xml': ['xdp'], - 'application/vnd.adobe.xfdf': ['xfdf'], - 'application/vnd.age': ['age'], - 'application/vnd.ahead.space': ['ahead'], - 'application/vnd.airzip.filesecure.azf': ['azf'], - 'application/vnd.airzip.filesecure.azs': ['azs'], - 'application/vnd.amazon.ebook': ['azw'], - 'application/vnd.amazon.mobi8-ebook': ['azw3', 'kfx'], - 'application/vnd.americandynamics.acc': ['acc'], - 'application/vnd.amiga.ami': ['ami'], - 'application/vnd.android.package-archive': ['apk'], - 'application/vnd.anser-web-certificate-issue-initiation': ['cii'], - 'application/vnd.anser-web-funds-transfer-initiation': ['fti'], - 'application/vnd.antix.game-component': ['atx'], - 'application/vnd.appimage': ['appimage'], - 'application/vnd.apple.installer+xml': ['mpkg'], - 'application/vnd.apple.keynote': ['key', 'keynote'], - 'application/vnd.apple.mpegurl': ['m3u8', 'm3u'], - 'application/vnd.apple.numbers': ['numbers'], - 'application/vnd.apple.pages': ['pages'], - 'application/vnd.apple.pkpass': ['pkpass'], - 'application/vnd.aristanetworks.swi': ['swi'], - 'application/vnd.astraea-software.iota': ['iota'], - 'application/vnd.audiograph': ['aep'], - 'application/vnd.balsamiq.bmml+xml': ['bmml'], - 'application/vnd.blueice.multipass': ['mpm'], - 'application/vnd.bmi': ['bmi'], - 'application/vnd.businessobjects': ['rep'], - 'application/vnd.chemdraw+xml': ['cdxml'], - 'application/vnd.chess-pgn': ['pgn'], - 'application/vnd.chipnuts.karaoke-mmd': ['mmd'], - 'application/vnd.cinderella': ['cdy'], - 'application/vnd.citationstyles.style+xml': ['csl'], - 'application/vnd.claymore': ['cla'], - 'application/vnd.cloanto.rp9': ['rp9'], - 'application/vnd.clonk.c4group': ['c4g', 'c4d', 'c4f', 'c4p', 'c4u'], - 'application/vnd.cluetrust.cartomobile-config': ['c11amc'], - 'application/vnd.cluetrust.cartomobile-config-pkg': ['c11amz'], - 'application/vnd.coffeescript': ['coffee'], - 'application/vnd.comicbook+zip': ['cbz'], - 'application/vnd.comicbook-rar': ['cbr'], - 'application/vnd.commonspace': ['csp'], - 'application/vnd.contact.cmsg': ['cdbcmsg'], - 'application/vnd.corel-draw': ['cdr'], - 'application/vnd.cosmocaller': ['cmc'], - 'application/vnd.crick.clicker': ['clkx'], - 'application/vnd.crick.clicker.keyboard': ['clkk'], - 'application/vnd.crick.clicker.palette': ['clkp'], - 'application/vnd.crick.clicker.template': ['clkt'], - 'application/vnd.crick.clicker.wordbank': ['clkw'], - 'application/vnd.criticaltools.wbs+xml': ['wbs'], - 'application/vnd.ctc-posml': ['pml'], - 'application/vnd.cups-ppd': ['ppd'], - 'application/vnd.curl.car': ['car'], - 'application/vnd.curl.pcurl': ['pcurl'], - 'application/vnd.dart': ['dart'], - 'application/vnd.data-vision.rdz': ['rdz'], - 'application/vnd.dbf': ['dbf'], - 'application/vnd.debian.binary-package': ['deb', 'udeb'], - 'application/vnd.dece.data': ['uvf', 'uvvf', 'uvd', 'uvvd'], - 'application/vnd.dece.ttml+xml': ['uvt', 'uvvt'], - 'application/vnd.dece.unspecified': ['uvx', 'uvvx'], - 'application/vnd.dece.zip': ['uvz', 'uvvz'], - 'application/vnd.denovo.fcselayout-link': ['fe_launch'], - 'application/vnd.dna': ['dna'], - 'application/vnd.dolby.mlp': ['mlp'], - 'application/vnd.dpgraph': ['dpg'], - 'application/vnd.dreamfactory': ['dfac'], - 'application/vnd.ds-keypoint': ['kpxx'], - 'application/vnd.dvb.ait': ['ait'], - 'application/vnd.dvb.service': ['svc'], - 'application/vnd.dynageo': ['geo'], - 'application/vnd.ecowin.chart': ['mag'], - 'application/vnd.efi.img': ['raw-disk-image', 'img'], - 'application/vnd.efi.iso': ['iso', 'iso9660'], - 'application/vnd.emusic-emusic_package': ['emp'], - 'application/vnd.enliven': ['nml'], - 'application/vnd.epson.esf': ['esf'], - 'application/vnd.epson.msf': ['msf'], - 'application/vnd.epson.quickanime': ['qam'], - 'application/vnd.epson.salt': ['slt'], - 'application/vnd.epson.ssf': ['ssf'], - 'application/vnd.eszigno3+xml': ['es3', 'et3'], - 'application/vnd.etsi.asic-e+zip': ['asice'], - 'application/vnd.ezpix-album': ['ez2'], - 'application/vnd.ezpix-package': ['ez3'], - 'application/vnd.fdf': ['fdf'], - 'application/vnd.fdsn.mseed': ['mseed'], - 'application/vnd.fdsn.seed': ['seed', 'dataless'], - 'application/vnd.flatpak': ['flatpak', 'xdgapp'], - 'application/vnd.flatpak.ref': ['flatpakref'], - 'application/vnd.flatpak.repo': ['flatpakrepo'], - 'application/vnd.flographit': ['gph'], - 'application/vnd.fluxtime.clip': ['ftc'], - 'application/vnd.framemaker': ['fm', 'frame', 'maker', 'book'], - 'application/vnd.frogans.fnc': ['fnc'], - 'application/vnd.frogans.ltf': ['ltf'], - 'application/vnd.fsc.weblaunch': ['fsc'], - 'application/vnd.fujitsu.oasys': ['oas'], - 'application/vnd.fujitsu.oasys2': ['oa2'], - 'application/vnd.fujitsu.oasys3': ['oa3'], - 'application/vnd.fujitsu.oasysgp': ['fg5'], - 'application/vnd.fujitsu.oasysprs': ['bh2'], - 'application/vnd.fujixerox.ddd': ['ddd'], - 'application/vnd.fujixerox.docuworks': ['xdw'], - 'application/vnd.fujixerox.docuworks.binder': ['xbd'], - 'application/vnd.fuzzysheet': ['fzs'], - 'application/vnd.genomatix.tuxedo': ['txd'], - 'application/vnd.geo+json': ['geojson', 'geo.json'], - 'application/vnd.geogebra.file': ['ggb'], - 'application/vnd.geogebra.tool': ['ggt'], - 'application/vnd.geometry-explorer': ['gex', 'gre'], - 'application/vnd.geonext': ['gxt'], - 'application/vnd.geoplan': ['g2w'], - 'application/vnd.geospace': ['g3w'], - 'application/vnd.gerber': ['gbr'], - 'application/vnd.gmx': ['gmx'], - 'application/vnd.google-apps.document': ['gdoc'], - 'application/vnd.google-apps.presentation': ['gslides'], - 'application/vnd.google-apps.spreadsheet': ['gsheet'], - 'application/vnd.google-earth.kml+xml': ['kml'], - 'application/vnd.google-earth.kmz': ['kmz'], - 'application/vnd.grafeq': ['gqf', 'gqs'], - 'application/vnd.groove-account': ['gac'], - 'application/vnd.groove-help': ['ghf'], - 'application/vnd.groove-identity-message': ['gim'], - 'application/vnd.groove-injector': ['grv'], - 'application/vnd.groove-tool-message': ['gtm'], - 'application/vnd.groove-tool-template': ['tpl'], - 'application/vnd.groove-vcard': ['vcg'], - 'application/vnd.haansoft-hwp': ['hwp'], - 'application/vnd.haansoft-hwt': ['hwt'], - 'application/vnd.hal+xml': ['hal'], - 'application/vnd.handheld-entertainment+xml': ['zmm'], - 'application/vnd.hbci': ['hbci'], - 'application/vnd.hhe.lesson-player': ['les'], - 'application/vnd.hp-hpgl': ['hpgl'], - 'application/vnd.hp-hpid': ['hpid'], - 'application/vnd.hp-hps': ['hps'], - 'application/vnd.hp-jlyt': ['jlt'], - 'application/vnd.hp-pcl': ['pcl'], - 'application/vnd.hp-pclxl': ['pclxl'], - 'application/vnd.hydrostatix.sof-data': ['sfd-hdstx'], - 'application/vnd.ibm.minipay': ['mpy'], - 'application/vnd.ibm.modcap': ['afp', 'listafp', 'list3820'], - 'application/vnd.ibm.rights-management': ['irm'], - 'application/vnd.ibm.secure-container': ['sc'], - 'application/vnd.iccprofile': ['icc', 'icm'], - 'application/vnd.igloader': ['igl'], - 'application/vnd.immervision-ivp': ['ivp'], - 'application/vnd.immervision-ivu': ['ivu'], - 'application/vnd.insors.igm': ['igm'], - 'application/vnd.intercon.formnet': ['xpw', 'xpx'], - 'application/vnd.intergeo': ['i2g'], - 'application/vnd.intu.qbo': ['qbo'], - 'application/vnd.intu.qfx': ['qfx'], - 'application/vnd.ipunplugged.rcprofile': ['rcprofile'], - 'application/vnd.irepository.package+xml': ['irp'], - 'application/vnd.is-xpr': ['xpr'], - 'application/vnd.isac.fcs': ['fcs'], - 'application/vnd.jam': ['jam'], - 'application/vnd.jcp.javame.midlet-rms': ['rms'], - 'application/vnd.jisp': ['jisp'], - 'application/vnd.joost.joda-archive': ['joda'], - 'application/vnd.kahootz': ['ktz', 'ktr'], - 'application/vnd.kde.karbon': ['karbon'], - 'application/vnd.kde.kchart': ['chrt'], - 'application/vnd.kde.kformula': ['kfo'], - 'application/vnd.kde.kivio': ['flw'], - 'application/vnd.kde.kontour': ['kon'], - 'application/vnd.kde.kpresenter': ['kpr', 'kpt'], - 'application/vnd.kde.kspread': ['ksp'], - 'application/vnd.kde.kword': ['kwd', 'kwt'], - 'application/vnd.kenameaapp': ['htke'], - 'application/vnd.kidspiration': ['kia'], - 'application/vnd.kinar': ['kne', 'knp'], - 'application/vnd.koan': ['skp', 'skd', 'skt', 'skm'], - 'application/vnd.kodak-descriptor': ['sse'], - 'application/vnd.las.las+xml': ['lasxml'], - 'application/vnd.llamagraphics.life-balance.desktop': ['lbd'], - 'application/vnd.llamagraphics.life-balance.exchange+xml': ['lbe'], - 'application/vnd.lotus-1-2-3': ['123', 'wk1', 'wk3', 'wk4', 'wks'], - 'application/vnd.lotus-approach': ['apr'], - 'application/vnd.lotus-freelance': ['pre'], - 'application/vnd.lotus-notes': ['nsf'], - 'application/vnd.lotus-organizer': ['org'], - 'application/vnd.lotus-screencam': ['scm'], - 'application/vnd.lotus-wordpro': ['lwp'], - 'application/vnd.macports.portpkg': ['portpkg'], - 'application/vnd.mapbox-vector-tile': ['mvt'], - 'application/vnd.mcd': ['mcd'], - 'application/vnd.medcalcdata': ['mc1'], - 'application/vnd.mediastation.cdkey': ['cdkey'], - 'application/vnd.mfer': ['mwf'], - 'application/vnd.mfmp': ['mfm'], - 'application/vnd.micrografx.flo': ['flo'], - 'application/vnd.micrografx.igx': ['igx'], - 'application/vnd.microsoft.portable-executable': [ - 'exe', - 'dll', - 'cpl', - 'drv', - 'scr', - 'efi', - 'ocx', - 'sys', - 'lib' - ], - 'application/vnd.mif': ['mif'], - 'application/vnd.mobius.daf': ['daf'], - 'application/vnd.mobius.dis': ['dis'], - 'application/vnd.mobius.mbk': ['mbk'], - 'application/vnd.mobius.mqy': ['mqy'], - 'application/vnd.mobius.msl': ['msl'], - 'application/vnd.mobius.plc': ['plc'], - 'application/vnd.mobius.txf': ['txf'], - 'application/vnd.mophun.application': ['mpn'], - 'application/vnd.mophun.certificate': ['mpc'], - 'application/vnd.mozilla.xul+xml': ['xul'], - 'application/vnd.ms-3mfdocument': ['3mf'], - 'application/vnd.ms-access': ['mdb'], - 'application/vnd.ms-artgalry': ['cil'], - 'application/vnd.ms-asf': ['asf'], - 'application/vnd.ms-cab-compressed': ['cab'], - 'application/vnd.ms-excel': [ - 'xls', - 'xlm', - 'xla', - 'xlc', - 'xlt', - 'xlw', - 'xll', - 'xld' - ], - 'application/vnd.ms-excel.addin.macroenabled.12': ['xlam'], - 'application/vnd.ms-excel.sheet.binary.macroenabled.12': ['xlsb'], - 'application/vnd.ms-excel.sheet.macroenabled.12': ['xlsm'], - 'application/vnd.ms-excel.template.macroenabled.12': ['xltm'], - 'application/vnd.ms-fontobject': ['eot'], - 'application/vnd.ms-htmlhelp': ['chm'], - 'application/vnd.ms-ims': ['ims'], - 'application/vnd.ms-lrm': ['lrm'], - 'application/vnd.ms-officetheme': ['thmx'], - 'application/vnd.ms-outlook': ['msg'], - 'application/vnd.ms-pki.seccat': ['cat'], - 'application/vnd.ms-pki.stl': ['stl'], - 'application/vnd.ms-powerpoint': ['ppt', 'pps', 'pot', 'ppz'], - 'application/vnd.ms-powerpoint.addin.macroenabled.12': ['ppam'], - 'application/vnd.ms-powerpoint.presentation.macroenabled.12': ['pptm'], - 'application/vnd.ms-powerpoint.slide.macroenabled.12': ['sldm'], - 'application/vnd.ms-powerpoint.slideshow.macroenabled.12': ['ppsm'], - 'application/vnd.ms-powerpoint.template.macroenabled.12': ['potm'], - 'application/vnd.ms-project': ['mpp', 'mpt'], - 'application/vnd.ms-publisher': ['pub'], - 'application/vnd.ms-tnef': ['tnef', 'tnf'], - 'application/vnd.ms-visio.drawing.macroenabled.main+xml': ['vsdm'], - 'application/vnd.ms-visio.drawing.main+xml': ['vsdx'], - 'application/vnd.ms-visio.stencil.macroenabled.main+xml': ['vssm'], - 'application/vnd.ms-visio.stencil.main+xml': ['vssx'], - 'application/vnd.ms-visio.template.macroenabled.main+xml': ['vstm'], - 'application/vnd.ms-visio.template.main+xml': ['vstx'], - 'application/vnd.ms-word': ['doc'], - 'application/vnd.ms-word.document.macroenabled.12': ['docm'], - 'application/vnd.ms-word.template.macroenabled.12': ['dotm'], - 'application/vnd.ms-works': ['wps', 'wks', 'wcm', 'wdb', 'xlr'], - 'application/vnd.ms-wpl': ['wpl'], - 'application/vnd.ms-xpsdocument': ['xps'], - 'application/vnd.msaccess': ['mdb'], - 'application/vnd.mseq': ['mseq'], - 'application/vnd.musician': ['mus'], - 'application/vnd.muvee.style': ['msty'], - 'application/vnd.mynfc': ['taglet'], - 'application/vnd.neurolanguage.nlu': ['nlu'], - 'application/vnd.nintendo.snes.rom': ['sfc', 'smc'], - 'application/vnd.nitf': ['ntf', 'nitf'], - 'application/vnd.noblenet-directory': ['nnd'], - 'application/vnd.noblenet-sealer': ['nns'], - 'application/vnd.noblenet-web': ['nnw'], - 'application/vnd.nokia.n-gage.ac+xml': ['ac'], - 'application/vnd.nokia.n-gage.data': ['ngdat'], - 'application/vnd.nokia.n-gage.symbian.install': ['n-gage'], - 'application/vnd.nokia.radio-preset': ['rpst'], - 'application/vnd.nokia.radio-presets': ['rpss'], - 'application/vnd.novadigm.edm': ['edm'], - 'application/vnd.novadigm.edx': ['edx'], - 'application/vnd.novadigm.ext': ['ext'], - 'application/vnd.oasis.opendocument.chart': ['odc'], - 'application/vnd.oasis.opendocument.chart-template': ['otc'], - 'application/vnd.oasis.opendocument.database': ['odb'], - 'application/vnd.oasis.opendocument.formula': ['odf'], - 'application/vnd.oasis.opendocument.formula-template': ['odft', 'otf'], - 'application/vnd.oasis.opendocument.graphics': ['odg'], - 'application/vnd.oasis.opendocument.graphics-flat-xml': ['fodg'], - 'application/vnd.oasis.opendocument.graphics-template': ['otg'], - 'application/vnd.oasis.opendocument.image': ['odi'], - 'application/vnd.oasis.opendocument.image-template': ['oti'], - 'application/vnd.oasis.opendocument.presentation': ['odp'], - 'application/vnd.oasis.opendocument.presentation-flat-xml': ['fodp'], - 'application/vnd.oasis.opendocument.presentation-template': ['otp'], - 'application/vnd.oasis.opendocument.spreadsheet': ['ods'], - 'application/vnd.oasis.opendocument.spreadsheet-flat-xml': ['fods'], - 'application/vnd.oasis.opendocument.spreadsheet-template': ['ots'], - 'application/vnd.oasis.opendocument.text': ['odt'], - 'application/vnd.oasis.opendocument.text-flat-xml': ['fodt'], - 'application/vnd.oasis.opendocument.text-master': ['odm'], - 'application/vnd.oasis.opendocument.text-template': ['ott'], - 'application/vnd.oasis.opendocument.text-web': ['oth'], - 'application/vnd.olpc-sugar': ['xo'], - 'application/vnd.oma.dd2+xml': ['dd2'], - 'application/vnd.openblox.game+xml': ['obgx'], - 'application/vnd.openofficeorg.extension': ['oxt'], - 'application/vnd.openstreetmap.data+xml': ['osm'], - 'application/vnd.openxmlformats-officedocument.presentationml.presentation': - ['pptx'], - 'application/vnd.openxmlformats-officedocument.presentationml.slide': [ - 'sldx' - ], - 'application/vnd.openxmlformats-officedocument.presentationml.slideshow': [ - 'ppsx' - ], - 'application/vnd.openxmlformats-officedocument.presentationml.template': [ - 'potx' - ], - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': [ - 'xlsx' - ], - 'application/vnd.openxmlformats-officedocument.spreadsheetml.template': [ - 'xltx' - ], - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': [ - 'docx' - ], - 'application/vnd.openxmlformats-officedocument.wordprocessingml.template': [ - 'dotx' - ], - 'application/vnd.osgeo.mapguide.package': ['mgp'], - 'application/vnd.osgi.dp': ['dp'], - 'application/vnd.osgi.subsystem': ['esa'], - 'application/vnd.palm': ['pdb', 'pqa', 'oprc', 'prc'], - 'application/vnd.pawaafile': ['paw'], - 'application/vnd.pg.format': ['str'], - 'application/vnd.pg.osasli': ['ei6'], - 'application/vnd.picsel': ['efif'], - 'application/vnd.pmi.widget': ['wg'], - 'application/vnd.pocketlearn': ['plf'], - 'application/vnd.powerbuilder6': ['pbd'], - 'application/vnd.previewsystems.box': ['box'], - 'application/vnd.proteus.magazine': ['mgz'], - 'application/vnd.publishare-delta-tree': ['qps'], - 'application/vnd.pvi.ptid1': ['ptid'], - 'application/vnd.quark.quarkxpress': [ - 'qxd', - 'qxt', - 'qwd', - 'qwt', - 'qxl', - 'qxb' - ], - 'application/vnd.rar': ['rar'], - 'application/vnd.realvnc.bed': ['bed'], - 'application/vnd.recordare.musicxml': ['mxl'], - 'application/vnd.recordare.musicxml+xml': ['musicxml'], - 'application/vnd.rig.cryptonote': ['cryptonote'], - 'application/vnd.rim.cod': ['cod'], - 'application/vnd.rn-realmedia': ['rm', 'rmj', 'rmm', 'rms', 'rmx', 'rmvb'], - 'application/vnd.rn-realmedia-vbr': [ - 'rmvb', - 'rm', - 'rmj', - 'rmm', - 'rms', - 'rmx' - ], - 'application/vnd.route66.link66+xml': ['link66'], - 'application/vnd.sailingtracker.track': ['st'], - 'application/vnd.sdp': ['sdp'], - 'application/vnd.seemail': ['see'], - 'application/vnd.sema': ['sema'], - 'application/vnd.semd': ['semd'], - 'application/vnd.semf': ['semf'], - 'application/vnd.shana.informed.formdata': ['ifm'], - 'application/vnd.shana.informed.formtemplate': ['itp'], - 'application/vnd.shana.informed.interchange': ['iif'], - 'application/vnd.shana.informed.package': ['ipk'], - 'application/vnd.simtech-mindmapper': ['twd', 'twds'], - 'application/vnd.smaf': ['mmf', 'smaf'], - 'application/vnd.smart.teacher': ['teacher'], - 'application/vnd.snap': ['snap'], - 'application/vnd.software602.filler.form+xml': ['fo'], - 'application/vnd.solent.sdkm+xml': ['sdkm', 'sdkd'], - 'application/vnd.spotfire.dxp': ['dxp'], - 'application/vnd.spotfire.sfs': ['sfs'], - 'application/vnd.sqlite3': ['sqlite3'], - 'application/vnd.squashfs': ['sqsh'], - 'application/vnd.stardivision.calc': ['sdc'], - 'application/vnd.stardivision.chart': ['sds'], - 'application/vnd.stardivision.draw': ['sda'], - 'application/vnd.stardivision.impress': ['sdd', 'sdp'], - 'application/vnd.stardivision.mail': ['smd'], - 'application/vnd.stardivision.math': ['smf'], - 'application/vnd.stardivision.writer': ['sdw', 'vor', 'sgl'], - 'application/vnd.stardivision.writer-global': ['sgl', 'sdw', 'vor'], - 'application/vnd.stepmania.package': ['smzip'], - 'application/vnd.stepmania.stepchart': ['sm'], - 'application/vnd.sun.wadl+xml': ['wadl'], - 'application/vnd.sun.xml.base': ['odb'], - 'application/vnd.sun.xml.calc': ['sxc'], - 'application/vnd.sun.xml.calc.template': ['stc'], - 'application/vnd.sun.xml.draw': ['sxd'], - 'application/vnd.sun.xml.draw.template': ['std'], - 'application/vnd.sun.xml.impress': ['sxi'], - 'application/vnd.sun.xml.impress.template': ['sti'], - 'application/vnd.sun.xml.math': ['sxm'], - 'application/vnd.sun.xml.writer': ['sxw'], - 'application/vnd.sun.xml.writer.global': ['sxg'], - 'application/vnd.sun.xml.writer.template': ['stw'], - 'application/vnd.sus-calendar': ['sus', 'susp'], - 'application/vnd.svd': ['svd'], - 'application/vnd.symbian.install': ['sis', 'sisx'], - 'application/vnd.syncml+xml': ['xsm'], - 'application/vnd.syncml.dm+wbxml': ['bdm'], - 'application/vnd.syncml.dm+xml': ['xdm'], - 'application/vnd.syncml.dmddf+xml': ['ddf'], - 'application/vnd.tao.intent-module-archive': ['tao'], - 'application/vnd.tcpdump.pcap': ['pcap', 'cap', 'dmp'], - 'application/vnd.tmobile-livetv': ['tmo'], - 'application/vnd.trid.tpt': ['tpt'], - 'application/vnd.triscape.mxs': ['mxs'], - 'application/vnd.trueapp': ['tra'], - 'application/vnd.truedoc': ['pfr'], - 'application/vnd.ufdl': ['ufd', 'ufdl'], - 'application/vnd.uiq.theme': ['utz'], - 'application/vnd.umajin': ['umj'], - 'application/vnd.unity': ['unityweb'], - 'application/vnd.uoml+xml': ['uoml'], - 'application/vnd.vcx': ['vcx'], - 'application/vnd.visio': ['vsd', 'vst', 'vss', 'vsw'], - 'application/vnd.visionary': ['vis'], - 'application/vnd.vsf': ['vsf'], - 'application/vnd.wap.wbxml': ['wbxml'], - 'application/vnd.wap.wmlc': ['wmlc'], - 'application/vnd.wap.wmlscriptc': ['wmlsc'], - 'application/vnd.webturbo': ['wtb'], - 'application/vnd.wolfram.player': ['nbp'], - 'application/vnd.wordperfect': ['wpd', 'wp', 'wp4', 'wp5', 'wp6', 'wpp'], - 'application/vnd.wqd': ['wqd'], - 'application/vnd.wt.stf': ['stf'], - 'application/vnd.xara': ['xar'], - 'application/vnd.xdgapp': ['flatpak', 'xdgapp'], - 'application/vnd.xfdl': ['xfdl'], - 'application/vnd.yamaha.hv-dic': ['hvd'], - 'application/vnd.yamaha.hv-script': ['hvs'], - 'application/vnd.yamaha.hv-voice': ['hvp'], - 'application/vnd.yamaha.openscoreformat': ['osf'], - 'application/vnd.yamaha.openscoreformat.osfpvg+xml': ['osfpvg'], - 'application/vnd.yamaha.smaf-audio': ['saf'], - 'application/vnd.yamaha.smaf-phrase': ['spf'], - 'application/vnd.yellowriver-custom-menu': ['cmp'], - 'application/vnd.youtube.yt': ['yt'], - 'application/vnd.zul': ['zir', 'zirz'], - 'application/vnd.zzazz.deck+xml': ['zaz'], - 'application/voicexml+xml': ['vxml'], - 'application/wasm': ['wasm'], - 'application/watcherinfo+xml': ['wif'], - 'application/widget': ['wgt'], - 'application/winhlp': ['hlp'], - 'application/wk1': ['123', 'wk1', 'wk3', 'wk4', 'wks'], - 'application/wmf': ['wmf'], - 'application/wordperfect': ['wp', 'wp4', 'wp5', 'wp6', 'wpd', 'wpp'], - 'application/wsdl+xml': ['wsdl'], - 'application/wspolicy+xml': ['wspolicy'], - 'application/wwf': ['wwf'], - 'application/x-123': ['123', 'wk1', 'wk3', 'wk4', 'wks'], - 'application/x-7z-compressed': ['7z', '7z.001'], - 'application/x-abiword': ['abw', 'abw.CRASHED', 'abw.gz', 'zabw'], - 'application/x-ace': ['ace'], - 'application/x-ace-compressed': ['ace'], - 'application/x-alz': ['alz'], - 'application/x-amiga-disk-format': ['adf'], - 'application/x-amipro': ['sam'], - 'application/x-annodex': ['anx'], - 'application/x-aportisdoc': ['pdb', 'pdc'], - 'application/x-apple-diskimage': ['dmg'], - 'application/x-apple-systemprofiler+xml': ['spx'], - 'application/x-appleworks-document': ['cwk'], - 'application/x-applix-spreadsheet': ['as'], - 'application/x-applix-word': ['aw'], - 'application/x-archive': ['a', 'ar'], - 'application/x-arj': ['arj'], - 'application/x-asar': ['asar'], - 'application/x-asp': ['asp'], - 'application/x-atari-2600-rom': ['a26'], - 'application/x-atari-7800-rom': ['a78'], - 'application/x-atari-lynx-rom': ['lnx'], - 'application/x-authorware-bin': ['aab', 'x32', 'u32', 'vox'], - 'application/x-authorware-map': ['aam'], - 'application/x-authorware-seg': ['aas'], - 'application/x-awk': ['awk'], - 'application/x-bat': ['bat'], - 'application/x-bcpio': ['bcpio'], - 'application/x-bdoc': ['bdoc'], - 'application/x-bittorrent': ['torrent'], - 'application/x-blender': ['blend', 'BLEND', 'blender'], - 'application/x-blorb': ['blb', 'blorb'], - 'application/x-bps-patch': ['bps'], - 'application/x-bsdiff': ['bsdiff'], - 'application/x-bz2': ['bz2'], - 'application/x-bzdvi': ['dvi.bz2'], - 'application/x-bzip': ['bz', 'bz2'], - 'application/x-bzip-compressed-tar': ['tar.bz2', 'tbz2', 'tb2'], - 'application/x-bzip1': ['bz'], - 'application/x-bzip1-compressed-tar': ['tar.bz', 'tbz'], - 'application/x-bzip2': ['bz2', 'boz'], - 'application/x-bzip2-compressed-tar': ['tar.bz2', 'tbz2', 'tb2'], - 'application/x-bzip3': ['bz3'], - 'application/x-bzip3-compressed-tar': ['tar.bz3', 'tbz3'], - 'application/x-bzpdf': ['pdf.bz2'], - 'application/x-bzpostscript': ['ps.bz2'], - 'application/x-cb7': ['cb7'], - 'application/x-cbr': ['cbr', 'cba', 'cbt', 'cbz', 'cb7'], - 'application/x-cbt': ['cbt'], - 'application/x-cbz': ['cbz'], - 'application/x-ccmx': ['ccmx'], - 'application/x-cd-image': ['iso', 'iso9660'], - 'application/x-cdlink': ['vcd'], - 'application/x-cdr': ['cdr'], - 'application/x-cdrdao-toc': ['toc'], - 'application/x-cfs-compressed': ['cfs'], - 'application/x-chat': ['chat'], - 'application/x-chess-pgn': ['pgn'], - 'application/x-chm': ['chm'], - 'application/x-chrome-extension': ['crx'], - 'application/x-cisco-vpn-settings': ['pcf'], - 'application/x-cocoa': ['cco'], - 'application/x-compress': ['Z'], - 'application/x-compressed-iso': ['cso'], - 'application/x-compressed-tar': ['tar.gz', 'tgz'], - 'application/x-conference': ['nsc'], - 'application/x-coreldraw': ['cdr'], - 'application/x-cpio': ['cpio'], - 'application/x-cpio-compressed': ['cpio.gz'], - 'application/x-csh': ['csh'], - 'application/x-cue': ['cue'], - 'application/x-dar': ['dar'], - 'application/x-dbase': ['dbf'], - 'application/x-dbf': ['dbf'], - 'application/x-dc-rom': ['dc'], - 'application/x-deb': ['deb', 'udeb'], - 'application/x-debian-package': ['deb', 'udeb'], - 'application/x-designer': ['ui'], - 'application/x-desktop': ['desktop', 'kdelnk'], - 'application/x-dgc-compressed': ['dgc'], - 'application/x-dia-diagram': ['dia'], - 'application/x-dia-shape': ['shape'], - 'application/x-director': [ - 'dir', - 'dcr', - 'dxr', - 'cst', - 'cct', - 'cxt', - 'w3d', - 'fgd', - 'swa' - ], - 'application/x-discjuggler-cd-image': ['cdi'], - 'application/x-docbook+xml': ['dbk', 'docbook'], - 'application/x-doom': ['wad'], - 'application/x-doom-wad': ['wad'], - 'application/x-dosexec': ['exe'], - 'application/x-dreamcast-rom': ['iso'], - 'application/x-dtbncx+xml': ['ncx'], - 'application/x-dtbook+xml': ['dtb'], - 'application/x-dtbresource+xml': ['res'], - 'application/x-dvi': ['dvi'], - 'application/x-e-theme': ['etheme'], - 'application/x-egon': ['egon'], - 'application/x-emf': ['emf'], - 'application/x-envoy': ['evy'], - 'application/x-eris-link+cbor': ['eris'], - 'application/x-eva': ['eva'], - 'application/x-excellon': ['drl'], - 'application/x-fd-file': ['fd', 'qd'], - 'application/x-fds-disk': ['fds'], - 'application/x-fictionbook': ['fb2'], - 'application/x-fictionbook+xml': ['fb2'], - 'application/x-fishscript': ['fish'], - 'application/x-flash-video': ['flv'], - 'application/x-fluid': ['fl'], - 'application/x-font-afm': ['afm'], - 'application/x-font-bdf': ['bdf'], - 'application/x-font-ghostscript': ['gsf'], - 'application/x-font-linux-psf': ['psf'], - 'application/x-font-otf': ['otf'], - 'application/x-font-pcf': ['pcf', 'pcf.Z', 'pcf.gz'], - 'application/x-font-snf': ['snf'], - 'application/x-font-speedo': ['spd'], - 'application/x-font-ttf': ['ttf', 'ttc'], - 'application/x-font-type1': ['pfa', 'pfb', 'pfm', 'afm'], - 'application/x-freearc': ['arc'], - 'application/x-freemind': ['mm'], - 'application/x-futuresplash': ['spl'], - 'application/x-gameboy-color-rom': ['gbc', 'cgb'], - 'application/x-gameboy-rom': ['gb', 'sgb'], - 'application/x-gba-rom': ['gba', 'agb'], - 'application/x-gca-compressed': ['gca'], - 'application/x-gedcom': ['ged', 'gedcom'], - 'application/x-genesis-32x-rom': ['32x', 'mdx'], - 'application/x-genesis-rom': ['gen', 'smd', 'md'], - 'application/x-gettext-translation': ['gmo', 'mo'], - 'application/x-glade': ['glade'], - 'application/x-gnome-app-info': ['desktop', 'desktop.in'], - 'application/x-go-sgf': ['sgf'], - 'application/x-godot-resource': ['tres', 'godot', 'tscn'], - 'application/x-gp32-rom': ['gp32'], - 'application/x-gramps-xml': ['gramps'], - 'application/x-graphing-calculator': ['gcf'], - 'application/x-graphite': ['gra'], - 'application/x-gtar': ['gtar'], - 'application/x-gtar-compressed': ['tgz', 'taz'], - 'application/x-gtk-builder': ['ui'], - 'application/x-gz-font-linux-psf': ['psf.gz'], - 'application/x-gzdvi': ['dvi.gz'], - 'application/x-gzip': ['gz'], - 'application/x-gzpdf': ['pdf.gz'], - 'application/x-gzpostscript': ['ps.gz'], - 'application/x-hdf': ['hdf'], - 'application/x-hfe-file': ['hfe'], - 'application/x-hfe-floppy-image': ['hfe'], - 'application/x-httpd-eruby': ['rhtml'], - 'application/x-httpd-php': ['php', 'php3', 'php4', 'php5', 'phps', 'phtml'], - 'application/x-httpd-php-source': ['phps'], - 'application/x-httpd-php3': ['php3'], - 'application/x-httpd-php4': ['php4'], - 'application/x-httpd-php5': ['php5'], - 'application/x-ica': ['ica'], - 'application/x-info': ['info'], - 'application/x-install-instructions': ['install'], - 'application/x-internet-signup': ['ins', 'isp'], - 'application/x-iphone': ['iii'], - 'application/x-ips-patch': ['ips'], - 'application/x-ipynb+json': ['ipynb'], - 'application/x-iso9660-image': ['iso'], - 'application/x-iwork-keynote-sffkey': ['key'], - 'application/x-iwork-numbers-sffnumbers': ['numbers'], - 'application/x-iwork-pages-sffpages': ['pages'], - 'application/x-java-archive-diff': ['jardiff'], - 'application/x-java-jnlp-file': ['jnlp'], - 'application/x-javascript': ['js', 'jsm'], - 'application/x-jbuilder-project': ['jpr', 'jpx'], - 'application/x-karbon': ['karbon'], - 'application/x-kchart': ['chrt'], - 'application/x-kexi-connectiondata': ['kexic'], - 'application/x-kexi-project': ['kexi'], - 'application/x-kexiproject-shortcut': ['kexis'], - 'application/x-kformula': ['kfo'], - 'application/x-killustrator': ['kil'], - 'application/x-kivio': ['flw'], - 'application/x-kontour': ['kon'], - 'application/x-kpovmodeler': ['kpm'], - 'application/x-kpresenter': ['kpr', 'kpt'], - 'application/x-krita': ['kra'], - 'application/x-kspread': ['ksp'], - 'application/x-kword': ['kwd', 'kwt'], - 'application/x-latex': ['latex'], - 'application/x-lha': ['lha', 'lzh'], - 'application/x-lha-compressed': ['lha', 'lzh'], - 'application/x-lrzip': ['lrz'], - 'application/x-lrzip-compressed-tar': ['tar.lrz', 'tlrz'], - 'application/x-lyx': ['lyx'], - 'application/x-lz4': ['lz4'], - 'application/x-lzh': ['lha', 'lzh'], - 'application/x-lzh-compressed': ['lha', 'lzh'], - 'application/x-lzip': ['lz'], - 'application/x-lzip-compressed-tar': ['tar.lz', 'tlz'], - 'application/x-lzma': ['lzma'], - 'application/x-lzma-compressed-tar': ['tar.lzma', 'tlzma'], - 'application/x-lzop': ['lzo'], - 'application/x-lzx': ['lzx'], - 'application/x-makeself': ['run'], - 'application/x-mame-chd': ['chd'], - 'application/x-markaby': ['mab'], - 'application/x-mie': ['mie'], - 'application/x-mif': ['mif'], - 'application/x-mimearchive': ['mhtml', 'mht'], - 'application/x-mobipocket-ebook': ['prc', 'mobi'], - 'application/x-modrinth-modpack+zip': ['mrpack'], - 'application/x-ms-application': ['application'], - 'application/x-ms-manifest': ['manifest'], - 'application/x-ms-reader': ['lit'], - 'application/x-ms-shortcut': ['lnk'], - 'application/x-ms-wim': ['wim', 'swm'], - 'application/x-ms-wmd': ['wmd'], - 'application/x-ms-wmz': ['wmz'], - 'application/x-ms-xbap': ['xbap'], - 'application/x-msaccess': ['mdb'], - 'application/x-msbinder': ['obd'], - 'application/x-mscardfile': ['crd'], - 'application/x-msclip': ['clp'], - 'application/x-msdownload': ['exe', 'dll', 'com', 'bat', 'msi'], - 'application/x-msdos-program': ['exe', 'dll', 'com', 'bat', 'msi'], - 'application/x-msi': ['msi'], - 'application/x-msmetafile': ['wmf', 'emf', 'emz'], - 'application/x-msmediaview': ['mvb', 'm13', 'm14'], - 'application/x-msmoney': ['mny'], - 'application/x-mspublisher': ['pub'], - 'application/x-msschedule': ['scd'], - 'application/x-msterminal': ['trm'], - 'application/x-mswrite': ['wri'], - 'application/x-n64-rom': ['n64', 'z64', 'v64'], - 'application/x-navi-animation': ['ani'], - 'application/x-navidoc': ['nvd'], - 'application/x-navimap': ['map'], - 'application/x-navistyle': ['stl'], - 'application/x-nds-rom': ['nds'], - 'application/x-neo-geo-pocket-color-rom': ['ngc'], - 'application/x-neo-geo-pocket-rom': ['ngp'], - 'application/x-netcdf': ['nc', 'cdf'], - 'application/x-netshow-channel': ['nsc'], - 'application/x-nintendo-ds-rom': ['nds'], - 'application/x-nintendo-3ds-rom': ['3ds', 'cci'], - 'application/x-ns-proxy-autoconfig': ['pac'], - 'application/x-nwc': ['nwc'], - 'application/x-nzb': ['nzb'], - 'application/x-object': ['o'], - 'application/x-oleo': ['oleo'], - 'application/x-ool': ['ool'], - 'application/x-oz-application': ['oza'], - 'application/x-pagemaker': ['p65', 'pm', 'pm6', 'pmd'], - 'application/x-pak': ['pak'], - 'application/x-par2': ['par2'], - 'application/x-partial-download': [ - '!qb', - '!bt', - '!download', - 'crdownload', - 'part' - ], - 'application/x-pc-engine-rom': ['pce'], - 'application/x-perl': ['pl', 'pm', 't', 'pod'], - 'application/x-pgn': ['pgn'], - 'application/x-php': ['php', 'php3', 'php4', 'php5', 'phps', 'phtml'], - 'application/x-pilot': ['prc', 'pdb'], - 'application/x-pkcs12': ['p12', 'pfx'], - 'application/x-pkcs7-certificates': ['p7b', 'spc'], - 'application/x-pkcs7-certreqresp': ['p7r'], - 'application/x-planperfect': ['pln'], - 'application/x-pocket-word': ['psw'], - 'application/x-pw': ['pw'], - 'application/x-python-bytecode': ['pyc', 'pyo'], - 'application/x-qed-disk': ['qed'], - 'application/x-qemu-disk': [ - 'qcow', - 'qcow2', - 'qed', - 'vpc', - 'vdi', - 'vmdk', - 'vhd', - 'vhdx', - 'hdd' - ], - 'application/x-quicktime-media-link': ['qtl'], - 'application/x-qw': ['qif'], - 'application/x-rar': ['rar'], - 'application/x-rar-compressed': ['rar'], - 'application/x-raw-disk-image': ['raw-disk-image', 'img'], - 'application/x-raw-disk-image-xz-compressed': [ - 'raw-disk-image.xz', - 'img.xz' - ], - 'application/x-raw-floppy-disk-image': ['fd', 'qd'], - 'application/x-redhat-package-manager': ['rpm'], - 'application/x-reject': ['rej'], - 'application/x-research-info-systems': ['ris'], - 'application/x-rpm': ['rpm'], - 'application/x-ruby': ['rb'], - 'application/x-sami': ['smi'], - 'application/x-sap-file': ['sap'], - 'application/x-saturn-rom': ['iso'], - 'application/x-sc': ['sc'], - 'application/x-scd-image': ['scd', 'sit'], - 'application/x-sega-cd-rom': ['iso'], - 'application/x-sega-pico-rom': ['iso'], - 'application/x-sg1000-rom': ['sg'], - 'application/x-sh': ['sh'], - 'application/x-shar': ['shar'], - 'application/x-shared-library-la': ['la'], - 'application/x-sharedlib': ['so'], - 'application/x-shellscript': ['sh'], - 'application/x-shockwave-flash': ['swf', 'spl'], - 'application/x-siag': ['siag'], - 'application/x-silverlight-app': ['xap'], - 'application/x-sit': ['sit'], - 'application/x-slp': ['slp'], - 'application/x-smaf': ['mmf'], - 'application/x-sms-rom': ['sms'], - 'application/x-source-rpm': ['src.rpm', 'spm'], - 'application/x-spss-por': ['por'], - 'application/x-spss-sav': ['sav', 'zsav'], - 'application/x-sql': ['sql'], - 'application/x-sqlite2': ['sqlite2'], - 'application/x-sqlite3': ['sqlite3', 'sqlite', 'db', 'db3'], - 'application/x-srt': ['srt'], - 'application/x-starcalc': ['sdc', 'vor'], - 'application/x-stardraw': ['sda', 'sdd', 'vor'], - 'application/x-starwriter': ['sdw', 'vor'], - 'application/x-stuffit': ['sit', 'sitx'], - 'application/x-stuffitx': ['sitx'], - 'application/x-subrip': ['srt'], - 'application/x-sv4cpio': ['sv4cpio'], - 'application/x-sv4crc': ['sv4crc'], - 'application/x-t3vm-image': ['t3'], - 'application/x-t602': ['602'], - 'application/x-tads': ['gam'], - 'application/x-tar': ['tar', 'gtar', 'gem'], - 'application/x-targa': ['tga', 'icb', 'tpic', 'vda', 'vst'], - 'application/x-tcl': ['tcl', 'tk'], - 'application/x-tex': ['tex'], - 'application/x-tex-gf': ['gf'], - 'application/x-tex-pk': ['pk'], - 'application/x-tex-tfm': ['tfm'], - 'application/x-texinfo': ['texinfo', 'texi'], - 'application/x-tgif': ['obj'], - 'application/x-theme': ['theme'], - 'application/x-thomson-cartridge-memo7': ['m7'], - 'application/x-thomson-cassette': ['k7'], - 'application/x-trash': ['~', '%', 'bak', 'old', 'sik'], - 'application/x-troff': ['t', 'tr', 'roff'], - 'application/x-troff-man': ['man'], - 'application/x-tzo': ['tar.lzo', 'tzo'], - 'application/x-ufraw': ['ufraw'], - 'application/x-ustar': ['ustar'], - 'application/x-virtualbox-hdd': ['vdi', 'vhd', 'vmdk'], - 'application/x-virtualbox-ova': ['ova'], - 'application/x-virtualbox-ovf': ['ovf'], - 'application/x-virtualbox-vbox': ['vbox'], - 'application/x-virtualbox-vbox-extpack': ['vbox-extpack'], - 'application/x-vnd.kde.kexi': ['kexi'], - 'application/x-vnd.kde.kplato': ['kplato'], - 'application/x-vnd.kde.kugar.mixed': ['kud'], - 'application/x-vnd.kde.nsplugin.class': ['class'], - 'application/x-wais-source': ['src'], - 'application/x-wbfs': ['wbfs'], - 'application/x-web-app-manifest+json': ['webapp'], - 'application/x-webarchive': ['webarchive'], - 'application/x-wetransfer': ['wetransfer'], - 'application/x-wii-rom': ['iso'], - 'application/x-wii-wad': ['wad'], - 'application/x-windows-theme': ['theme'], - 'application/x-winhelp': ['hlp'], - 'application/x-wintega-applet': ['wgt'], - 'application/x-wintega-test': ['wtg'], - 'application/x-wonderswan-color-rom': ['wsc'], - 'application/x-wonderswan-rom': ['ws'], - 'application/x-wpg': ['wpg'], - 'application/x-wwf': ['wwf'], - 'application/x-x509-ca-cert': ['der', 'crt', 'cert', 'pem'], - 'application/x-xar': ['xar'], - 'application/x-xbel': ['xbel'], - 'application/x-xfig': ['fig'], - 'application/x-xliff+xml': ['xlf'], - 'application/x-xpinstall': ['xpi'], - 'application/x-xz': ['xz'], - 'application/x-xz-compressed-tar': ['tar.xz', 'txz'], - 'application/x-xzpdf': ['pdf.xz'], - 'application/x-yaml': ['yaml', 'yml'], - 'application/x-zerosize': ['empty'], - 'application/x-zip-compressed': ['zip'], - 'application/x-zoo': ['zoo'], - 'application/x-zstd-compressed-tar': ['tar.zst', 'tzst'], - 'application/xaml+xml': ['xaml'], - 'application/xcap-att+xml': ['xav'], - 'application/xcap-caps+xml': ['xca'], - 'application/xcap-diff+xml': ['xdf'], - 'application/xcap-el+xml': ['xel'], - 'application/xcap-ns+xml': ['xns'], - 'application/xenc+xml': ['xenc'], - 'application/xhtml+xml': ['xhtml', 'xht'], - 'application/xliff+xml': ['xlf'], - 'application/xml': ['xml', 'xsl', 'xsd', 'rng'], - 'application/xml-dtd': ['dtd'], - 'application/xop+xml': ['xop'], - 'application/xproc+xml': ['xpl'], - 'application/xslt+xml': ['xslt'], - 'application/xspf+xml': ['xspf'], - 'application/xv+xml': ['mxml', 'xhvml', 'xvml', 'xvm'], - 'application/yang': ['yang'], - 'application/yin+xml': ['yin'], - 'application/zip': ['zip'], - 'application/zlib': ['zz'], - 'application/zstd': ['zst'], - 'audio/aac': ['aac'], - 'audio/ac3': ['ac3'], - 'audio/adpcm': ['adp'], - 'audio/amr': ['amr'], - 'audio/amr-wb': ['awb'], - 'audio/annodex': ['axa'], - 'audio/aph': ['aph'], - 'audio/basic': ['au', 'snd'], - 'audio/dts': ['dts'], - 'audio/dv': ['dv'], - 'audio/eac3': ['eac3'], - 'audio/flac': ['flac'], - 'audio/m4a': ['m4a'], - 'audio/midi': ['mid', 'midi', 'kar', 'rmi'], - 'audio/mp2': ['mp2'], - 'audio/mp4': ['mp4a', 'm4a'], - 'audio/mpeg': ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'], - 'audio/ogg': ['oga', 'ogg', 'spx', 'opus'], - 'audio/prs.sid': ['sid'], - 'audio/s3m': ['s3m'], - 'audio/silk': ['sil'], - 'audio/vnd.audible.aax': ['aax'], - 'audio/vnd.dece.audio': ['uva', 'uvva'], - 'audio/vnd.digital-winds': ['eol'], - 'audio/vnd.dra': ['dra'], - 'audio/vnd.dts': ['dts'], - 'audio/vnd.dts.hd': ['dtshd'], - 'audio/vnd.lucent.voice': ['lvp'], - 'audio/vnd.ms-playready.media.pya': ['pya'], - 'audio/vnd.nuera.ecelp4800': ['ecelp4800'], - 'audio/vnd.nuera.ecelp7470': ['ecelp7470'], - 'audio/vnd.nuera.ecelp9600': ['ecelp9600'], - 'audio/vnd.rip': ['rip'], - 'audio/vnd.wave': ['wav'], - 'audio/webm': ['weba'], - 'audio/x-aac': ['aac'], - 'audio/x-aiff': ['aif', 'aiff', 'aifc'], - 'audio/x-caf': ['caf'], - 'audio/x-flac': ['flac'], - 'audio/x-gsm': ['gsm'], - 'audio/x-matroska': ['mka'], - 'audio/x-mpegurl': ['m3u'], - 'audio/x-ms-wax': ['wax'], - 'audio/x-ms-wma': ['wma'], - 'audio/x-pn-realaudio': ['ram', 'ra'], - 'audio/x-pn-realaudio-plugin': ['rmp'], - 'audio/x-realaudio': ['ra'], - 'audio/x-scpls': ['pls'], - 'audio/x-sd2': ['sd2'], - 'audio/x-wav': ['wav'], - 'chemical/x-alchemy': ['alc'], - 'chemical/x-cache': ['cac', 'cache'], - 'chemical/x-cache-csf': ['csf'], - 'chemical/x-cactvs-binary': ['cbin', 'cascii', 'ctab'], - 'chemical/x-cdx': ['cdx'], - 'chemical/x-cerius': ['cer'], - 'chemical/x-chem3d': ['c3d'], - 'chemical/x-chemdraw': ['chm'], - 'chemical/x-cif': ['cif'], - 'chemical/x-cmdf': ['cmdf'], - 'chemical/x-cml': ['cml'], - 'chemical/x-compass': ['cpa'], - 'chemical/x-crossfire': ['bsd'], - 'chemical/x-csml': ['csml', 'csm'], - 'chemical/x-ctx': ['ctx'], - 'chemical/x-cxf': ['cxf', 'cef'], - 'chemical/x-embl-dl-nucleotide': ['emb', 'embl'], - 'chemical/x-galactic-spc': ['spc'], - 'chemical/x-gamess-input': ['inp', 'gam', 'gamin'], - 'chemical/x-gaussian-checkpoint': ['fch', 'fchk'], - 'chemical/x-gaussian-cube': ['cub'], - 'chemical/x-gaussian-input': ['gau', 'gjc', 'gjf'], - 'chemical/x-gaussian-log': ['gal'], - 'chemical/x-gcg8-sequence': ['gcg'], - 'chemical/x-genbank': ['gen'], - 'chemical/x-hin': ['hin'], - 'chemical/x-isostar': ['istr', 'ist'], - 'chemical/x-jcamp-dx': ['jdx', 'dx'], - 'chemical/x-kinemage': ['kin'], - 'chemical/x-macmolecule': ['mcm'], - 'chemical/x-macromodel-input': ['mmd', 'mmod'], - 'chemical/x-mdl-molfile': ['mol'], - 'chemical/x-mdl-rdfile': ['rd'], - 'chemical/x-mdl-rxnfile': ['rxn'], - 'chemical/x-mdl-sdfile': ['sd', 'sdf'], - 'chemical/x-mdl-tgf': ['tgf'], - 'chemical/x-mmcif': ['mcif'], - 'chemical/x-mol2': ['mol2'], - 'chemical/x-molconn-Z': ['b'], - 'chemical/x-mopac-graph': ['gpt'], - 'chemical/x-mopac-input': ['mop', 'mopcrt', 'mpc', 'zmt'], - 'chemical/x-mopac-out': ['moo'], - 'chemical/x-mopac-vib': ['mvb'], - 'chemical/x-ncbi-asn1': ['asn'], - 'chemical/x-ncbi-asn1-ascii': ['prt', 'ent'], - 'chemical/x-ncbi-asn1-binary': ['val', 'aso'], - 'chemical/x-ncbi-asn1-spec': ['asn'], - 'chemical/x-pdb': ['pdb', 'ent'], - 'chemical/x-rosdal': ['ros'], - 'chemical/x-swissprot': ['sw'], - 'chemical/x-vamas-iso14976': ['vms'], - 'chemical/x-vmd': ['vmd'], - 'chemical/x-xtel': ['xtel'], - 'chemical/x-xyz': ['xyz'], - 'font/collection': ['ttc'], - 'font/otf': ['otf'], - 'font/sfnt': ['sfnt'], - 'font/ttf': ['ttf'], - 'font/woff': ['woff'], - 'font/woff2': ['woff2'], - 'image/avif': ['avif'], - 'image/bmp': ['bmp', 'dib'], - 'image/cgm': ['cgm'], - 'image/dicom-rle': ['drle'], - 'image/emf': ['emf'], - 'image/fits': ['fits'], - 'image/g3fax': ['g3'], - 'image/gif': ['gif'], - 'image/heic': ['heic'], - 'image/heic-sequence': ['heics'], - 'image/heif': ['heif'], - 'image/heif-sequence': ['heifs'], - 'image/hej2k': ['hej2'], - 'image/hsj2': ['hsj2'], - 'image/ief': ['ief'], - 'image/jls': ['jls'], - 'image/jp2': ['jp2', 'jpg2'], - 'image/jpeg': ['jpeg', 'jpg', 'jpe'], - 'image/jph': ['jph'], - 'image/jphc': ['jhc'], - 'image/jpm': ['jpm'], - 'image/jpx': ['jpx', 'jpf'], - 'image/jxr': ['jxr'], - 'image/jxra': ['jxra'], - 'image/jxrs': ['jxrs'], - 'image/jxs': ['jxs'], - 'image/jxsc': ['jxsc'], - 'image/jxsi': ['jxsi'], - 'image/jxss': ['jxss'], - 'image/ktx': ['ktx'], - 'image/ktx2': ['ktx2'], - 'image/png': ['png'], - 'image/prs.btif': ['btif'], - 'image/prs.pti': ['pti'], - 'image/sgi': ['sgi'], - 'image/svg+xml': ['svg', 'svgz'], - 'image/t38': ['t38'], - 'image/tiff': ['tif', 'tiff'], - 'image/tiff-fx': ['tfx'], - 'image/vnd.adobe.photoshop': ['psd'], - 'image/vnd.airzip.accelerator.azv': ['azv'], - 'image/vnd.dece.graphic': ['uvi', 'uvvi', 'uvg', 'uvvg'], - 'image/vnd.djvu': ['djvu', 'djv'], - 'image/vnd.dvb.subtitle': ['sub'], - 'image/vnd.dwg': ['dwg'], - 'image/vnd.dxf': ['dxf'], - 'image/vnd.fastbidsheet': ['fbs'], - 'image/vnd.fpx': ['fpx'], - 'image/vnd.fst': ['fst'], - 'image/vnd.fujixerox.edmics-mmr': ['mmr'], - 'image/vnd.fujixerox.edmics-rlc': ['rlc'], - 'image/vnd.globalgraphics.pgb': ['pgb'], - 'image/vnd.microsoft.icon': ['ico'], - 'image/vnd.mix': ['mix'], - 'image/vnd.mozilla.apng': ['apng'], - 'image/vnd.ms-modi': ['mdi'], - 'image/vnd.ms-photo': ['wdp'], - 'image/vnd.net-fpx': ['npx'], - 'image/vnd.pco.b16': ['b16'], - 'image/vnd.radiance': ['rgbe', 'xyze'], - 'image/vnd.sealed.png': ['spng'], - 'image/vnd.sealedmedia.softseal.gif': ['sgif'], - 'image/vnd.sealedmedia.softseal.jpg': ['sjpg'], - 'image/vnd.svf': ['svf'], - 'image/vnd.tencent.tap': ['tap'], - 'image/vnd.valve.source.texture': ['vtf'], - 'image/vnd.wap.wbmp': ['wbmp'], - 'image/vnd.xiff': ['xif'], - 'image/vnd.zbrush.pcx': ['pcx'], - 'image/webp': ['webp'], - 'image/wmf': ['wmf'], - 'image/x-3ds': ['3ds'], - 'image/x-adobe-dng': ['dng'], - 'image/x-applix-graphics': ['ag'], - 'image/x-apm': ['apm'], - 'image/x-bzeps': ['eps.bz2'], - 'image/x-canon-cr2': ['cr2'], - 'image/x-canon-crw': ['crw'], - 'image/x-cmu-raster': ['ras'], - 'image/x-cmx': ['cmx'], - 'image/x-compressed-xcf': ['xcf.gz', 'xcf.bz2'], - 'image/x-dcraw': [ - 'dcr', - 'dng', - 'nef', - 'crw', - 'raf', - 'orf', - 'mrw', - 'x3f', - 'pef', - 'sr2', - 'arw' - ], - 'image/x-dds': ['dds'], - 'image/x-dib': ['dib'], - 'image/x-eps': ['eps', 'epsi', 'epsf'], - 'image/x-exr': ['exr'], - 'image/x-freehand': ['fh', 'fhc', 'fh4', 'fh5', 'fh7'], - 'image/x-gimp-gbr': ['gbr'], - 'image/x-gimp-gih': ['gih'], - 'image/x-gimp-pat': ['pat'], - 'image/x-gzeps': ['eps.gz'], - 'image/x-icns': ['icns'], - 'image/x-ico': ['ico'], - 'image/x-icon': ['ico'], - 'image/x-iff': ['iff', 'lbm'], - 'image/x-ilbm': ['ilbm', 'lbm'], - 'image/x-jng': ['jng'], - 'image/x-kodak-dcr': ['dcr'], - 'image/x-kodak-k25': ['k25'], - 'image/x-kodak-kdc': ['kdc'], - 'image/x-lwo': ['lwo', 'lwob'], - 'image/x-lws': ['lws'], - 'image/x-macpaint': ['pntg'], - 'image/x-mrsid-image': ['sid'], - 'image/x-ms-bmp': ['bmp'], - 'image/x-nikon-nef': ['nef'], - 'image/x-olympus-orf': ['orf'], - 'image/x-panasonic-raw': ['raw'], - 'image/x-panasonic-rw': ['rw2'], - 'image/x-pcx': ['pcx'], - 'image/x-pentax-pef': ['pef'], - 'image/x-pict': ['pic', 'pct', 'pict'], - 'image/x-portable-anymap': ['pnm'], - 'image/x-portable-bitmap': ['pbm'], - 'image/x-portable-graymap': ['pgm'], - 'image/x-portable-pixmap': ['ppm'], - 'image/x-psb': ['psb'], - 'image/x-psd': ['psd'], - 'image/x-rgb': ['rgb'], - 'image/x-sigma-x3f': ['x3f'], - 'image/x-sony-arw': ['arw'], - 'image/x-sony-sr2': ['sr2'], - 'image/x-sony-srf': ['srf'], - 'image/x-targa': ['tga', 'icb', 'tpic', 'vda', 'vst'], - 'image/x-tga': ['tga'], - 'image/x-win-bitmap': ['cur'], - 'image/x-wmf': ['wmf'], - 'image/x-xbitmap': ['xbm'], - 'image/x-xcf': ['xcf'], - 'image/x-xfig': ['fig'], - 'image/x-xpixmap': ['xpm'], - 'image/x-xwindowdump': ['xwd'], - 'message/rfc822': ['eml', 'mime'], - 'model/3mf': ['3mf'], - 'model/gltf+json': ['gltf'], - 'model/gltf-binary': ['glb'], - 'model/iges': ['igs', 'iges'], - 'model/mesh': ['msh', 'mesh', 'silo'], - 'model/mtl': ['mtl'], - 'model/obj': ['obj'], - 'model/stl': ['stl'], - 'model/vnd.collada+xml': ['dae'], - 'model/vnd.dwf': ['dwf'], - 'model/vnd.gdl': ['gdl'], - 'model/vnd.gtw': ['gtw'], - 'model/vnd.mts': ['mts'], - 'model/vnd.usdz+zip': ['usdz'], - 'model/vnd.valve.source.compiled-map': ['bsp'], - 'model/vnd.vtu': ['vtu'], - 'model/vrml': ['wrl', 'vrml'], - 'model/x3d+binary': ['x3db', 'x3dbz'], - 'model/x3d+fastinfoset': ['x3db'], - 'model/x3d+vrml': ['x3dv', 'x3dvz'], - 'model/x3d+xml': ['x3d', 'x3dz'], - 'text/cache-manifest': ['appcache', 'manifest'], - 'text/calendar': ['ics', 'ifb'], - 'text/coffeescript': ['coffee', 'litcoffee'], - 'text/css': ['css'], - 'text/csv': ['csv'], - 'text/h323': ['323'], - 'text/html': ['html', 'htm', 'shtml'], - 'text/iuls': ['uls'], - 'text/javascript': ['js', 'mjs'], - 'text/jsx': ['jsx'], - 'text/less': ['less'], - 'text/markdown': ['markdown', 'md'], - 'text/mathml': ['mml'], - 'text/n3': ['n3'], - 'text/plain': ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini'], - 'text/prs.lines.tag': ['dsc'], - 'text/richtext': ['rtx'], - 'text/rtf': ['rtf'], - 'text/sgml': ['sgml', 'sgm'], - 'text/shex': ['shex'], - 'text/slim': ['slim', 'slm'], - 'text/spdx': ['spdx'], - 'text/stylus': ['stylus', 'styl'], - 'text/tab-separated-values': ['tsv'], - 'text/troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'], - 'text/turtle': ['ttl'], - 'text/uri-list': ['uri', 'uris', 'urls'], - 'text/vcard': ['vcard'], - 'text/vnd.curl': ['curl'], - 'text/vnd.curl.dcurl': ['dcurl'], - 'text/vnd.curl.mcurl': ['mcurl'], - 'text/vnd.curl.scurl': ['scurl'], - 'text/vnd.dvb.subtitle': ['sub'], - 'text/vnd.fly': ['fly'], - 'text/vnd.fmi.flexstor': ['flx'], - 'text/vnd.graphviz': ['gv'], - 'text/vnd.in3d.3dml': ['3dml'], - 'text/vnd.in3d.spot': ['spot'], - 'text/vnd.sun.j2me.app-descriptor': ['jad'], - 'text/vnd.wap.wml': ['wml'], - 'text/vnd.wap.wmlscript': ['wmls'], - 'text/vtt': ['vtt'], - 'text/x-asm': ['s', 'asm'], - 'text/x-bibtex': ['bib'], - 'text/x-boo': ['boo'], - 'text/x-c': ['c', 'cc', 'cxx', 'cpp', 'h', 'hh', 'dic'], - 'text/x-c++hdr': ['hpp', 'h++', 'hxx', 'hh'], - 'text/x-c++src': ['cpp', 'c++', 'cc', 'cxx'], - 'text/x-chdr': ['h'], - 'text/x-component': ['htc'], - 'text/x-csh': ['csh'], - 'text/x-csrc': ['c'], - 'text/x-dart': ['dart'], - 'text/x-dbus-service': ['service'], - 'text/x-dcl': ['dcl'], - 'text/x-diff': ['diff', 'patch'], - 'text/x-dsrc': ['d', 'di'], - 'text/x-dtd': ['dtd'], - 'text/x-eiffel': ['e', 'eif'], - 'text/x-emacs-lisp': ['el'], - 'text/x-erlang': ['erl'], - 'text/x-fortran': ['f', 'for', 'f77', 'f90'], - 'text/x-gcode': ['gcode'], - 'text/x-genie': ['gs'], - 'text/x-gettext-translation': ['po'], - 'text/x-gherkin': ['feature'], - 'text/x-go': ['go'], - 'text/x-gradle': ['gradle'], - 'text/x-groovy': ['groovy', 'gvy', 'gy', 'gsh'], - 'text/x-handlebars-template': ['hbs'], - 'text/x-haskell': ['hs'], - 'text/x-idl': ['idl'], - 'text/x-imelody': ['imy'], - 'text/x-iptables': ['iptables'], - 'text/x-java': ['java'], - 'text/x-java-source': ['java'], - 'text/x-koka': ['kk', 'kki'], - 'text/x-kotlin': ['kt'], - 'text/x-ldif': ['ldif'], - 'text/x-lilypond': ['ly'], - 'text/x-literate-haskell': ['lhs'], - 'text/x-log': ['log'], - 'text/x-lua': ['lua'], - 'text/x-makefile': ['mak', 'mk'], - 'text/x-matlab': ['m'], - 'text/x-meson': ['meson.build'], - 'text/x-modelica': ['mo'], - 'text/x-mof': ['mof'], - 'text/x-mpsub': ['sub'], - 'text/x-msdos-batch': ['bat', 'cmd'], - 'text/x-msil': ['il'], - 'text/x-nfo': ['nfo'], - 'text/x-objcsrc': ['m', 'mm'], - 'text/x-ocaml': ['ml', 'mli', 'mll', 'mly'], - 'text/x-opml': ['opml'], - 'text/x-pascal': ['p', 'pas'], - 'text/x-patch': ['diff', 'patch'], - 'text/x-perl': ['pl', 'pm', 't', 'pod'], - 'text/x-php': ['php', 'php3', 'php4', 'php5', 'phps', 'phtml'], - 'text/x-processing': ['pde'], - 'text/x-python': ['py', 'pyi'], - 'text/x-qml': ['qml', 'qbs'], - 'text/x-R': ['r'], - 'text/x-reject': ['rej'], - 'text/x-rfc822-headers': ['eml'], - 'text/x-rpm-spec': ['spec'], - 'text/x-rst': ['rst'], - 'text/x-ruby': ['rb'], - 'text/x-sass': ['sass'], - 'text/x-scala': ['scala', 'sc'], - 'text/x-scheme': ['scm', 'ss'], - 'text/x-scss': ['scss'], - 'text/x-setext': ['etx'], - 'text/x-sfv': ['sfv'], - 'text/x-sh': ['sh'], - 'text/x-shellscript': ['sh'], - 'text/x-sql': ['sql'], - 'text/x-suse-ymp': ['ymp'], - 'text/x-systemd-unit': [ - 'automount', - 'device', - 'mount', - 'path', - 'scope', - 'service', - 'slice', - 'socket', - 'swap', - 'target', - 'timer' - ], - 'text/x-tcl': ['tcl', 'tk'], - 'text/x-tex': ['tex', 'ltx', 'sty', 'cls', 'dtx', 'ins', 'latex'], - 'text/x-texinfo': ['texinfo', 'texi'], - 'text/x-troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'], - 'text/x-txt2tags': ['t2t'], - 'text/x-uil': ['uil'], - 'text/x-uuencode': ['uu'], - 'text/x-vala': ['vala', 'vapi'], - 'text/x-vcalendar': ['vcs'], - 'text/x-vcard': ['vcf'], - 'text/x-verilog': ['v'], - 'text/x-vhdl': ['vhd', 'vhdl'], - 'text/x-xmi': ['xmi'], - 'text/x-xslfo': ['fo', 'xslfo'], - 'text/x-yaml': ['yaml', 'yml'], - 'video/3gpp': ['3gp', '3gpp'], - 'video/3gpp2': ['3g2'], - 'video/annodex': ['axv'], - 'video/divx': ['divx'], - 'video/h261': ['h261'], - 'video/h263': ['h263'], - 'video/h264': ['h264'], - 'video/iso.segment': ['m4s'], - 'video/jpeg': ['jpgv'], - 'video/jpm': ['jpm', 'jpgm'], - 'video/mj2': ['mj2', 'mjp2'], - 'video/mp2t': ['ts'], - 'video/mp4': ['mp4', 'mp4v', 'mpg4'], - 'video/mpeg': ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'], - 'video/ogg': ['ogv'], - 'video/quicktime': ['qt', 'mov'], - 'video/vnd.dece.hd': ['uvh', 'uvvh'], - 'video/vnd.dece.mobile': ['uvm', 'uvvm'], - 'video/vnd.dece.pd': ['uvp', 'uvvp'], - 'video/vnd.dece.sd': ['uvs', 'uvvs'], - 'video/vnd.dece.video': ['uvv', 'uvvv'], - 'video/vnd.dvb.file': ['dvb'], - 'video/vnd.fvt': ['fvt'], - 'video/vnd.mpegurl': ['mxu', 'm4u'], - 'video/vnd.ms-playready.media.pyv': ['pyv'], - 'video/vnd.uvvu.mp4': ['uvu', 'uvvu'], - 'video/vnd.vivo': ['viv'], - 'video/webm': ['webm'], - 'video/x-f4v': ['f4v'], - 'video/x-fli': ['fli'], - 'video/x-flv': ['flv'], - 'video/x-m4v': ['m4v'], - 'video/x-matroska': ['mkv', 'mk3d', 'mks'], - 'video/x-mng': ['mng'], - 'video/x-ms-asf': ['asf', 'asx'], - 'video/x-ms-vob': ['vob'], - 'video/x-ms-wm': ['wm'], - 'video/x-ms-wmv': ['wmv'], - 'video/x-ms-wmx': ['wmx'], - 'video/x-ms-wvx': ['wvx'], - 'video/x-msvideo': ['avi'], - 'video/x-nsv': ['nsv'], - 'video/x-ogm+ogg': ['ogm'], - 'video/x-sgi-movie': ['movie'], - 'video/x-smv': ['smv'], - 'x-conference/x-cooltalk': ['ice'], - 'x-epoc/x-sisx-app': ['sisx'], - 'x-world/x-vrml': ['vrm', 'vrml', 'wrl'], - }; - - /// A utility class for handling MIME types and file extensions. - /// - /// This class provides methods to: - /// - Get file extensions for a given MIME type - /// - Get MIME types for a given file extension - /// - Guess the MIME type for a given file path - /// - Check if MIME type guessing is supported - static final Map> reverseMap = { - '2': ['application/x-stuffit'], - '3g2': ['audio/3gpp2', 'video/3gpp2'], - '3ga': ['video/3gpp'], - '3gp': [ - 'application/vnd.3gpp.pic-bw-large', - 'application/vnd.3gpp.pic-bw-small', - 'application/vnd.3gpp.pic-bw-var', - 'audio/3gpp', - 'audio/3gpp2', - 'video/3gpp', - 'video/3gpp2' - ], - '3gpp': ['audio/3gpp', 'video/3gpp'], - '3gpp2': ['audio/3gpp2', 'video/3gpp2'], - '3mf': ['application/vnd.ms-3mfdocument', 'model/3mf'], - '602': ['application/x-t602'], - '669': ['audio/x-mod'], - '7z': ['application/x-7z-compressed'], - '7z.001': ['application/x-7z-compressed'], - 'BLEND': ['application/x-blender'], - 'C': ['text/x-c++src'], - 'PAR2': ['application/x-par2'], - 'PL': ['application/x-perl', 'text/x-perl'], - 'Z': ['application/x-compress'], - 'a': ['application/x-archive'], - 'a26': ['application/x-atari-2600-rom'], - 'a78': ['application/x-atari-7800-rom'], - 'aa': ['audio/vnd.audible', 'audio/x-pn-audibleaudio'], - 'aab': ['application/x-authorware-bin'], - 'aac': ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'], - 'aam': ['application/x-authorware-map'], - 'aas': ['application/x-authorware-seg'], - 'aax': [ - 'audio/vnd.audible', - 'audio/vnd.audible.aax', - 'audio/x-pn-audibleaudio' - ], - 'aaxc': ['audio/vnd.audible.aaxc'], - 'abw': ['application/x-abiword'], - 'abw.CRASHED': ['application/x-abiword'], - 'abw.gz': ['application/x-abiword'], - 'ac': ['application/pkix-attr-cert', 'application/vnd.nokia.n-gage.ac+xml'], - 'ac3': ['audio/ac3'], - 'acc': ['application/vnd.americandynamics.acc'], - 'ace': ['application/x-ace', 'application/x-ace-compressed'], - 'acu': ['application/vnd.acucobol'], - 'acutc': ['application/vnd.acucorp'], - 'adb': ['text/x-adasrc'], - 'adf': ['application/x-amiga-disk-format'], - 'adp': ['audio/adpcm'], - 'ads': ['text/x-adasrc'], - 'adts': ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'], - 'aep': ['application/vnd.audiograph'], - 'afm': ['application/x-font-afm', 'application/x-font-type1'], - 'afp': ['application/vnd.ibm.modcap'], - 'ag': ['image/x-applix-graphics'], - 'agb': ['application/x-gba-rom'], - 'age': ['application/vnd.age'], - 'ahead': ['application/vnd.ahead.space'], - 'ai': [ - 'application/illustrator', - 'application/postscript', - 'application/vnd.adobe.illustrator' - ], - 'aif': ['audio/x-aiff'], - 'aifc': ['audio/x-aifc', 'audio/x-aiff', 'audio/x-aiffc'], - 'aiff': ['audio/x-aiff'], - 'aiffc': ['audio/x-aifc', 'audio/x-aiffc'], - 'air': ['application/vnd.adobe.air-application-installer-package+zip'], - 'ait': ['application/vnd.dvb.ait'], - 'al': ['application/x-perl', 'text/x-perl'], - 'alz': ['application/x-alz'], - 'ami': ['application/vnd.amiga.ami'], - 'amr': ['audio/amr', 'audio/amr-encrypted'], - 'amz': ['audio/x-amzxml'], - 'ani': ['application/x-navi-animation'], - 'anim1': ['video/x-anim'], - 'anim2': ['video/x-anim'], - 'anim3': ['video/x-anim'], - 'anim4': ['video/x-anim'], - 'anim5': ['video/x-anim'], - 'anim6': ['video/x-anim'], - 'anim7': ['video/x-anim'], - 'anim8': ['video/x-anim'], - 'anim9': ['video/x-anim'], - 'animj': ['video/x-anim'], - 'anx': ['application/annodex', 'application/x-annodex'], - 'ape': ['audio/x-ape'], - 'apk': ['application/vnd.android.package-archive'], - 'apng': ['image/apng', 'image/vnd.mozilla.apng'], - 'appcache': ['text/cache-manifest'], - 'appimage': ['application/vnd.appimage', 'application/x-iso9660-appimage'], - 'appinstaller': ['application/appinstaller'], - 'application': ['application/x-ms-application'], - 'appx': ['application/appx'], - 'appxbundle': ['application/appxbundle'], - 'apr': ['application/vnd.lotus-approach'], - 'ar': ['application/x-archive'], - 'arc': ['application/x-freearc'], - 'arj': ['application/x-arj'], - 'arw': ['image/x-sony-arw'], - 'as': ['application/x-applix-spreadsheet'], - 'asar': ['application/x-asar'], - 'asc': [ - 'application/pgp', - 'application/pgp-encrypted', - 'application/pgp-keys', - 'application/pgp-signature', - 'text/plain' - ], - 'asd': ['text/x-common-lisp'], - 'asf': [ - 'application/vnd.ms-asf', - 'video/x-ms-asf', - 'video/x-ms-asf-plugin', - 'video/x-ms-wm' - ], - 'asice': ['application/vnd.etsi.asic-e+zip'], - 'asm': ['text/x-asm'], - 'aso': ['application/vnd.accpac.simply.aso'], - 'asp': ['application/x-asp'], - 'ass': ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts', 'text/x-ssa'], - 'astc': ['image/astc'], - 'asx': [ - 'application/x-ms-asx', - 'audio/x-ms-asx', - 'video/x-ms-asf', - 'video/x-ms-wax', - 'video/x-ms-wmx', - 'video/x-ms-wvx' - ], - 'atc': ['application/vnd.acucorp'], - 'atom': ['application/atom+xml'], - 'atomcat': ['application/atomcat+xml'], - 'atomdeleted': ['application/atomdeleted+xml'], - 'atomsvc': ['application/atomsvc+xml'], - 'atx': ['application/vnd.antix.game-component'], - 'au': ['audio/basic'], - 'automount': ['text/x-systemd-unit'], - 'avci': ['image/avci'], - 'avcs': ['image/avcs'], - 'avf': [ - 'video/avi', - 'video/divx', - 'video/msvideo', - 'video/vnd.avi', - 'video/vnd.divx', - 'video/x-avi', - 'video/x-msvideo' - ], - 'avi': [ - 'video/avi', - 'video/divx', - 'video/msvideo', - 'video/vnd.avi', - 'video/vnd.divx', - 'video/x-avi', - 'video/x-msvideo' - ], - 'avif': ['image/avif', 'image/avif-sequence'], - 'avifs': ['image/avif', 'image/avif-sequence'], - 'aw': ['application/applixware', 'application/x-applix-word'], - 'awb': ['audio/amr-wb', 'audio/amr-wb-encrypted'], - 'awk': ['application/x-awk'], - 'axa': ['audio/annodex', 'audio/x-annodex'], - 'axv': ['video/annodex', 'video/x-annodex'], - 'azf': ['application/vnd.airzip.filesecure.azf'], - 'azs': ['application/vnd.airzip.filesecure.azs'], - 'azv': ['image/vnd.airzip.accelerator.azv'], - 'azw': ['application/vnd.amazon.ebook'], - 'azw3': ['application/vnd.amazon.mobi8-ebook', 'application/x-mobi8-ebook'], - 'b16': ['image/vnd.pco.b16'], - 'bak': ['application/x-trash'], - 'bas': ['text/x-basic'], - 'bat': ['application/bat', 'application/x-bat', 'application/x-msdownload'], - 'bcpio': ['application/x-bcpio'], - 'bdf': ['application/x-font-bdf'], - 'bdm': ['application/vnd.syncml.dm+wbxml', 'video/mp2t'], - 'bdmv': ['video/mp2t'], - 'bdoc': ['application/bdoc', 'application/x-bdoc'], - 'bed': ['application/vnd.realvnc.bed'], - 'bh2': ['application/vnd.fujitsu.oasysprs'], - 'bib': ['text/x-bibtex'], - 'bik': ['video/vnd.radgamettools.bink'], - 'bin': ['application/octet-stream'], - 'bk2': ['video/vnd.radgamettools.bink'], - 'blb': ['application/x-blorb'], - 'blend': ['application/x-blender'], - 'blender': ['application/x-blender'], - 'blorb': ['application/x-blorb'], - 'blp': ['text/x-blueprint'], - 'bmi': ['application/vnd.bmi'], - 'bmml': ['application/vnd.balsamiq.bmml+xml'], - 'bmp': ['image/bmp', 'image/x-bmp', 'image/x-ms-bmp'], - 'book': ['application/vnd.framemaker'], - 'box': ['application/vnd.previewsystems.box'], - 'boz': ['application/x-bzip2'], - 'bps': ['application/x-bps-patch'], - 'brk': ['chemical/x-pdb'], - 'bsdiff': ['application/x-bsdiff'], - 'bsp': ['model/vnd.valve.source.compiled-map'], - 'btif': ['image/prs.btif'], - 'bz': ['application/bzip2', 'application/x-bzip', 'application/x-bzip1'], - 'bz2': [ - 'application/x-bz2', - 'application/bzip2', - 'application/x-bzip', - 'application/x-bzip2' - ], - 'bz3': ['application/x-bzip3'], - 'c': ['text/x-c', 'text/x-csrc'], - 'c++': ['text/x-c++src'], - 'c11amc': ['application/vnd.cluetrust.cartomobile-config'], - 'c11amz': ['application/vnd.cluetrust.cartomobile-config-pkg'], - 'c4d': ['application/vnd.clonk.c4group'], - 'c4f': ['application/vnd.clonk.c4group'], - 'c4g': ['application/vnd.clonk.c4group'], - 'c4p': ['application/vnd.clonk.c4group'], - 'c4u': ['application/vnd.clonk.c4group'], - 'cab': [ - 'application/vnd.ms-cab-compressed', - 'zz-application/zz-winassoc-cab' - ], - 'caf': ['audio/x-caf'], - 'cap': [ - 'application/pcap', - 'application/vnd.tcpdump.pcap', - 'application/x-pcap' - ], - 'car': ['application/vnd.curl.car'], - 'cat': ['application/vnd.ms-pki.seccat'], - 'cb7': ['application/x-cb7', 'application/x-cbr'], - 'cba': ['application/x-cbr'], - 'cbl': ['text/x-cobol'], - 'cbor': ['application/cbor'], - 'cbr': ['application/vnd.comicbook-rar', 'application/x-cbr'], - 'cbt': ['application/x-cbr', 'application/x-cbt'], - 'cbz': [ - 'application/vnd.comicbook+zip', - 'application/x-cbr', - 'application/x-cbz' - ], - 'cc': ['text/x-c', 'text/x-c++src'], - 'cci': ['application/x-nintendo-3ds-rom'], - 'ccmx': ['application/x-ccmx'], - 'cco': ['application/x-cocoa'], - 'cct': ['application/x-director'], - 'ccxml': ['application/ccxml+xml'], - 'cdbcmsg': ['application/vnd.contact.cmsg'], - 'cdf': ['application/x-netcdf'], - 'cdfx': ['application/cdfx+xml'], - 'cdi': ['application/x-discjuggler-cd-image'], - 'cdkey': ['application/vnd.mediastation.cdkey'], - 'cdmia': ['application/cdmi-capability'], - 'cdmic': ['application/cdmi-container'], - 'cdmid': ['application/cdmi-domain'], - 'cdmio': ['application/cdmi-object'], - 'cdmiq': ['application/cdmi-queue'], - 'cdr': [ - 'application/cdr', - 'application/coreldraw', - 'application/vnd.corel-draw', - 'application/x-cdr', - 'application/x-coreldraw', - 'image/cdr', - 'image/x-cdr', - 'zz-application/zz-winassoc-cdr' - ], - 'cdx': ['chemical/x-cdx'], - 'cdxml': ['application/vnd.chemdraw+xml'], - 'cdy': ['application/vnd.cinderella'], - 'cer': ['application/pkix-cert'], - 'cert': ['application/x-x509-ca-cert'], - 'cfs': ['application/x-cfs-compressed'], - 'cgb': ['application/x-gameboy-color-rom'], - 'cgm': ['image/cgm'], - 'chat': ['application/x-chat'], - 'chd': ['application/x-mame-chd'], - 'chm': ['application/vnd.ms-htmlhelp', 'application/x-chm'], - 'chrt': ['application/vnd.kde.kchart', 'application/x-kchart'], - 'cif': ['chemical/x-cif'], - 'cii': ['application/vnd.anser-web-certificate-issue-initiation'], - 'cil': ['application/vnd.ms-artgalry'], - 'cjs': ['application/node'], - 'cl': ['text/x-opencl-src'], - 'cla': ['application/vnd.claymore'], - 'class': [ - 'application/java', - 'application/java-byte-code', - 'application/java-vm', - 'application/x-java', - 'application/x-java-class', - 'application/x-java-vm' - ], - 'clkk': ['application/vnd.crick.clicker.keyboard'], - 'clkp': ['application/vnd.crick.clicker.palette'], - 'clkt': ['application/vnd.crick.clicker.template'], - 'clkw': ['application/vnd.crick.clicker.wordbank'], - 'clkx': ['application/vnd.crick.clicker'], - 'clp': ['application/x-msclip'], - 'clpi': ['video/mp2t'], - 'cls': ['application/x-tex', 'text/x-tex'], - 'cmake': ['text/x-cmake'], - 'cmc': ['application/vnd.cosmocaller'], - 'cmdf': ['chemical/x-cmdf'], - 'cml': ['chemical/x-cml'], - 'cmp': ['application/vnd.yellowriver-custom-menu'], - 'cmx': ['image/x-cmx'], - 'cob': ['text/x-cobol'], - 'cod': ['application/vnd.rim.cod'], - 'coffee': ['application/vnd.coffeescript', 'text/coffeescript'], - 'com': ['application/x-msdownload'], - 'conf': ['text/plain'], - 'cpi': ['video/mp2t'], - 'cpio': ['application/x-cpio'], - 'cpio.gz': ['application/x-cpio-compressed'], - 'cpl': [ - 'application/cpl+xml', - 'application/vnd.microsoft.portable-executable', - 'application/x-ms-dos-executable', - 'application/x-ms-ne-executable', - 'application/x-msdownload' - ], - 'cpp': ['text/x-c', 'text/x-c++src'], - 'cpt': ['application/mac-compactpro'], - 'cr': ['text/crystal', 'text/x-crystal'], - 'cr2': ['image/x-canon-cr2'], - 'cr3': ['image/x-canon-cr3'], - 'crd': ['application/x-mscardfile'], - 'crdownload': ['application/x-partial-download'], - 'crl': ['application/pkix-crl'], - 'crt': ['application/x-x509-ca-cert'], - 'crw': ['image/x-canon-crw'], - 'crx': ['application/x-chrome-extension'], - 'cryptonote': ['application/vnd.rig.cryptonote'], - 'cs': ['text/x-csharp'], - 'csh': ['application/x-csh'], - 'csl': ['application/vnd.citationstyles.style+xml'], - 'csml': ['chemical/x-csml'], - 'cso': ['application/x-compressed-iso'], - 'csp': ['application/vnd.commonspace'], - 'css': ['text/css'], - 'cst': ['application/x-director'], - 'csv': [ - 'text/csv', - 'application/csv', - 'text/x-comma-separated-values', - 'text/x-csv' - ], - 'csvs': ['text/csv-schema'], - 'cu': ['application/cu-seeme'], - 'cue': ['application/x-cue'], - 'cur': ['image/x-win-bitmap'], - 'curl': ['text/vnd.curl'], - 'cwk': ['application/x-appleworks-document'], - 'cww': ['application/prs.cww'], - 'cxt': ['application/x-director'], - 'cxx': ['text/x-c', 'text/x-c++src'], - 'd': ['text/x-dsrc'], - 'dae': ['model/vnd.collada+xml'], - 'daf': ['application/vnd.mobius.daf'], - 'dar': ['application/x-dar'], - 'dart': ['application/vnd.dart', 'text/x-dart'], - 'dataless': ['application/vnd.fdsn.seed'], - 'davmount': ['application/davmount+xml'], - 'dbf': [ - 'application/dbase', - 'application/dbf', - 'application/vnd.dbf', - 'application/x-dbase', - 'application/x-dbf' - ], - 'dbk': [ - 'application/docbook+xml', - 'application/vnd.oasis.docbook+xml', - 'application/x-docbook+xml' - ], - 'dc': ['application/x-dc-rom'], - 'dcl': ['text/x-dcl'], - 'dcm': ['application/dicom'], - 'dcr': ['application/x-director', 'image/x-kodak-dcr'], - 'dcurl': ['text/vnd.curl.dcurl'], - 'dd2': ['application/vnd.oma.dd2+xml'], - 'ddd': ['application/vnd.fujixerox.ddd'], - 'ddf': ['application/vnd.syncml.dmddf+xml'], - 'dds': ['image/vnd.ms-dds', 'image/x-dds'], - 'deb': [ - 'application/vnd.debian.binary-package', - 'application/x-deb', - 'application/x-debian-package' - ], - 'def': ['text/plain'], - 'der': ['application/x-x509-ca-cert'], - 'desktop': ['application/x-desktop', 'application/x-gnome-app-info'], - 'device': ['text/x-systemd-unit'], - 'dfac': ['application/vnd.dreamfactory'], - 'dff': ['audio/dff', 'audio/x-dff'], - 'dgc': ['application/x-dgc-compressed'], - 'di': ['text/x-dsrc'], - 'dia': ['application/x-dia-diagram'], - 'dib': ['image/bmp', 'image/x-bmp', 'image/x-ms-bmp'], - 'dic': ['text/x-c'], - 'diff': ['text/x-diff', 'text/x-patch'], - 'dir': ['application/x-director'], - 'dis': ['application/vnd.mobius.dis'], - 'disposition-notification': ['message/disposition-notification'], - 'divx': [ - 'video/avi', - 'video/divx', - 'video/msvideo', - 'video/vnd.avi', - 'video/vnd.divx', - 'video/x-avi', - 'video/x-msvideo' - ], - 'djv': [ - 'image/vnd.djvu', - 'image/vnd.djvu+multipage', - 'image/x-djvu', - 'image/x.djvu' - ], - 'djvu': [ - 'image/vnd.djvu', - 'image/vnd.djvu+multipage', - 'image/x-djvu', - 'image/x.djvu' - ], - 'dll': [ - 'application/vnd.microsoft.portable-executable', - 'application/x-ms-dos-executable', - 'application/x-ms-ne-executable', - 'application/x-msdownload' - ], - 'dmg': ['application/x-apple-diskimage'], - 'dmp': [ - 'application/pcap', - 'application/vnd.tcpdump.pcap', - 'application/x-pcap' - ], - 'dna': ['application/vnd.dna'], - 'dng': ['image/x-adobe-dng'], - 'doc': [ - 'application/msword', - 'application/vnd.ms-word', - 'application/x-msword', - 'zz-application/zz-winassoc-doc' - ], - 'docbook': [ - 'application/docbook+xml', - 'application/vnd.oasis.docbook+xml', - 'application/x-docbook+xml' - ], - 'docm': ['application/vnd.ms-word.document.macroenabled.12'], - 'docx': [ - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' - ], - 'dot': [ - 'application/msword', - 'application/msword-template', - 'text/vnd.graphviz' - ], - 'dotm': ['application/vnd.ms-word.template.macroenabled.12'], - 'dotx': [ - 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' - ], - 'dp': ['application/vnd.osgi.dp'], - 'dpg': ['application/vnd.dpgraph'], - 'dra': ['audio/vnd.dra'], - 'drl': ['application/x-excellon'], - 'drle': ['image/dicom-rle'], - 'drv': [ - 'application/vnd.microsoft.portable-executable', - 'application/x-ms-dos-executable', - 'application/x-ms-ne-executable', - 'application/x-msdownload' - ], - 'dsc': ['text/prs.lines.tag'], - 'dsf': ['audio/dsd', 'audio/dsf', 'audio/x-dsd', 'audio/x-dsf'], - 'dsl': ['text/x-dsl'], - 'dssc': ['application/dssc+der'], - 'dtb': ['application/x-dtbook+xml', 'text/x-devicetree-binary'], - 'dtd': ['application/xml-dtd', 'text/x-dtd'], - 'dts': ['audio/vnd.dts', 'audio/x-dts', 'text/x-devicetree-source'], - 'dtshd': ['audio/vnd.dts.hd', 'audio/x-dtshd'], - 'dtsi': ['text/x-devicetree-source'], - 'dtx': ['application/x-tex', 'text/x-tex'], - 'dv': ['video/dv'], - 'dvb': ['video/vnd.dvb.file'], - 'dvi': ['application/x-dvi'], - 'dvi.bz2': ['application/x-bzdvi'], - 'dvi.gz': ['application/x-gzdvi'], - 'dwd': ['application/atsc-dwd+xml'], - 'dwf': ['model/vnd.dwf'], - 'dwg': ['image/vnd.dwg'], - 'dxf': ['image/vnd.dxf'], - 'dxp': ['application/vnd.spotfire.dxp'], - 'dxr': ['application/x-director'], - 'e': ['text/x-eiffel'], - 'ear': ['application/java-archive'], - 'ecelp4800': ['audio/vnd.nuera.ecelp4800'], - 'ecelp7470': ['audio/vnd.nuera.ecelp7470'], - 'ecelp9600': ['audio/vnd.nuera.ecelp9600'], - 'ecma': ['application/ecmascript'], - 'edm': ['application/vnd.novadigm.edm'], - 'edx': ['application/vnd.novadigm.edx'], - 'efi': ['application/vnd.microsoft.portable-executable'], - 'efif': ['application/vnd.picsel'], - 'egon': ['application/x-egon'], - 'ei6': ['application/vnd.pg.osasli'], - 'eif': ['text/x-eiffel'], - 'el': ['text/x-emacs-lisp'], - 'emf': [ - 'application/emf', - 'application/x-emf', - 'application/x-msmetafile', - 'image/emf', - 'image/x-emf' - ], - 'eml': ['message/rfc822'], - 'emma': ['application/emma+xml'], - 'emotionml': ['application/emotionml+xml'], - 'emp': ['application/vnd.emusic-emusic_package'], - 'emz': ['application/x-msmetafile'], - 'ent': [ - 'application/xml-external-parsed-entity', - 'text/xml-external-parsed-entity' - ], - 'eol': ['audio/vnd.digital-winds'], - 'eot': ['application/vnd.ms-fontobject'], - 'eps': ['application/postscript', 'image/x-eps'], - 'eps.bz2': ['image/x-bzeps'], - 'eps.gz': ['image/x-gzeps'], - 'epsf': ['image/x-eps'], - 'epsf.bz2': ['image/x-bzeps'], - 'epsf.gz': ['image/x-gzeps'], - 'epsi': ['image/x-eps'], - 'epsi.bz2': ['image/x-bzeps'], - 'epsi.gz': ['image/x-gzeps'], - 'epub': ['application/epub+zip'], - 'eris': ['application/x-eris-link+cbor'], - 'erl': ['text/x-erlang'], - 'es': ['application/ecmascript', 'text/ecmascript'], - 'es3': ['application/vnd.eszigno3+xml'], - 'esa': ['application/vnd.osgi.subsystem'], - 'escn': ['application/x-godot-scene'], - 'esf': ['application/vnd.epson.esf'], - 'et3': ['application/vnd.eszigno3+xml'], - 'etheme': ['application/x-e-theme'], - 'etx': ['text/x-setext'], - 'eva': ['application/x-eva'], - 'evy': ['application/x-envoy'], - 'ex': ['text/x-elixir'], - 'exe': [ - 'application/vnd.microsoft.portable-executable', - 'application/x-dosexec', - 'application/x-ms-dos-executable', - 'application/x-ms-ne-executable', - 'application/x-msdos-program', - 'application/x-msdownload' - ], - 'exi': ['application/exi'], - 'exp': ['application/express'], - 'exr': ['image/aces', 'image/x-exr'], - 'exs': ['text/x-elixir'], - 'ext': ['application/vnd.novadigm.ext'], - 'ez': ['application/andrew-inset'], - 'ez2': ['application/vnd.ezpix-album'], - 'ez3': ['application/vnd.ezpix-package'], - 'f': ['text/x-fortran'], - 'f4a': ['audio/m4a', 'audio/mp4', 'audio/x-m4a'], - 'f4b': ['audio/x-m4b'], - 'f4v': ['video/mp4', 'video/mp4v-es', 'video/x-f4v', 'video/x-m4v'], - 'f77': ['text/x-fortran'], - 'f90': ['text/x-fortran'], - 'f95': ['text/x-fortran'], - 'fasl': ['text/x-common-lisp'], - 'fb2': ['application/x-fictionbook', 'application/x-fictionbook+xml'], - 'fb2.zip': ['application/x-zip-compressed-fb2'], - 'fbs': ['image/vnd.fastbidsheet'], - 'fcdt': ['application/vnd.adobe.formscentral.fcdt'], - 'fcs': ['application/vnd.isac.fcs'], - 'fd': ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], - 'fdf': ['application/vnd.fdf'], - 'fds': ['application/x-fds-disk'], - 'fdt': ['application/fdt+xml'], - 'fe_launch': ['application/vnd.denovo.fcselayout-link'], - 'feature': ['text/x-gherkin'], - 'fg5': ['application/vnd.fujitsu.oasysgp'], - 'fgd': ['application/x-director'], - 'fh': ['image/x-freehand'], - 'fh4': ['image/x-freehand'], - 'fh5': ['image/x-freehand'], - 'fh7': ['image/x-freehand'], - 'fhc': ['image/x-freehand'], - 'fig': ['application/x-xfig', 'image/x-xfig'], - 'fish': ['application/x-fishscript', 'text/x-fish'], - 'fit': ['application/fits', 'image/fits', 'image/x-fits'], - 'fits': ['application/fits', 'image/fits', 'image/x-fits'], - 'fl': ['application/x-fluid'], - 'flac': ['audio/flac', 'audio/x-flac'], - 'flatpak': ['application/vnd.flatpak', 'application/vnd.xdgapp'], - 'flatpakref': ['application/vnd.flatpak.ref'], - 'flatpakrepo': ['application/vnd.flatpak.repo'], - 'flc': ['video/fli', 'video/x-fli', 'video/x-flic'], - 'fli': ['video/fli', 'video/x-fli', 'video/x-flic'], - 'flo': ['application/vnd.micrografx.flo'], - 'flv': [ - 'video/x-flv', - 'application/x-flash-video', - 'flv-application/octet-stream', - 'video/flv' - ], - 'flw': ['application/vnd.kde.kivio', 'application/x-kivio'], - 'flx': ['text/vnd.fmi.flexstor'], - 'fly': ['text/vnd.fly'], - 'fm': ['application/vnd.framemaker', 'application/x-frame'], - 'fnc': ['application/vnd.frogans.fnc'], - 'fo': ['application/vnd.software602.filler.form+xml', 'text/x-xslfo'], - 'fodg': ['application/vnd.oasis.opendocument.graphics-flat-xml'], - 'fodp': ['application/vnd.oasis.opendocument.presentation-flat-xml'], - 'fods': ['application/vnd.oasis.opendocument.spreadsheet-flat-xml'], - 'fodt': ['application/vnd.oasis.opendocument.text-flat-xml'], - 'for': ['text/x-fortran'], - 'fpx': ['image/vnd.fpx'], - 'frame': ['application/vnd.framemaker'], - 'fsc': ['application/vnd.fsc.weblaunch'], - 'fst': ['image/vnd.fst'], - 'ftc': ['application/vnd.fluxtime.clip'], - 'fti': ['application/vnd.anser-web-funds-transfer-initiation'], - 'fts': ['application/fits', 'image/fits', 'image/x-fits'], - 'fvt': ['video/vnd.fvt'], - 'fxm': ['video/x-javafx'], - 'fxp': ['application/vnd.adobe.fxp'], - 'fxpl': ['application/vnd.adobe.fxp'], - 'fzs': ['application/vnd.fuzzysheet'], - 'g2w': ['application/vnd.geoplan'], - 'g3': ['image/fax-g3', 'image/g3fax'], - 'g3w': ['application/vnd.geospace'], - 'gac': ['application/vnd.groove-account'], - 'gam': ['application/x-tads'], - 'gb': ['application/x-gameboy-rom'], - 'gba': ['application/x-gba-rom'], - 'gbc': ['application/x-gameboy-color-rom'], - 'gbr': [ - 'application/rpki-ghostbusters', - 'application/vnd.gerber', - 'application/x-gerber', - 'image/x-gimp-gbr' - ], - 'gbrjob': ['application/x-gerber-job'], - 'gca': ['application/x-gca-compressed'], - 'gcode': ['text/x.gcode'], - 'gcrd': ['text/directory', 'text/vcard', 'text/x-vcard'], - 'gd': ['application/x-gdscript'], - 'gdi': ['application/x-gd-rom-cue'], - 'gdl': ['model/vnd.gdl'], - 'gdoc': ['application/vnd.google-apps.document'], - 'gdshader': ['application/x-godot-shader'], - 'ged': [ - 'application/x-gedcom', - 'text/gedcom', - 'text/vnd.familysearch.gedcom' - ], - 'gedcom': [ - 'application/x-gedcom', - 'text/gedcom', - 'text/vnd.familysearch.gedcom' - ], - 'gem': ['application/x-gtar', 'application/x-tar'], - 'gen': ['application/x-genesis-rom'], - 'geo': ['application/vnd.dynageo'], - 'geo.json': ['application/geo+json', 'application/vnd.geo+json'], - 'geojson': ['application/geo+json', 'application/vnd.geo+json'], - 'gex': ['application/vnd.geometry-explorer'], - 'gf': ['application/x-tex-gf'], - 'gg': ['application/x-gamegear-rom'], - 'ggb': ['application/vnd.geogebra.file'], - 'ggt': ['application/vnd.geogebra.tool'], - 'ghf': ['application/vnd.groove-help'], - 'gif': ['image/gif'], - 'gih': ['image/x-gimp-gih'], - 'gim': ['application/vnd.groove-identity-message'], - 'glade': ['application/x-glade'], - 'glb': ['model/gltf-binary'], - 'gltf': ['model/gltf+json'], - 'gml': ['application/gml+xml'], - 'gmo': ['application/x-gettext-translation'], - 'gmx': ['application/vnd.gmx'], - 'gnc': ['application/x-gnucash'], - 'gnd': ['application/gnunet-directory'], - 'gnucash': ['application/x-gnucash'], - 'gnumeric': ['application/x-gnumeric'], - 'gnuplot': ['application/x-gnuplot'], - 'go': ['text/x-go'], - 'gp': ['application/x-gnuplot'], - 'gpg': [ - 'application/pgp', - 'application/pgp-encrypted', - 'application/pgp-keys', - 'application/pgp-signature' - ], - 'gph': ['application/vnd.flographit'], - 'gplt': ['application/x-gnuplot'], - 'gpx': [ - 'application/gpx', - 'application/gpx+xml', - 'application/x-gpx', - 'application/x-gpx+xml' - ], - 'gqf': ['application/vnd.grafeq'], - 'gqs': ['application/vnd.grafeq'], - 'gra': ['application/x-graphite'], - 'gradle': ['text/x-gradle'], - 'gram': ['application/srgs'], - 'gramps': ['application/x-gramps-xml'], - 'gre': ['application/vnd.geometry-explorer'], - 'groovy': ['text/x-groovy'], - 'grv': ['application/vnd.groove-injector'], - 'grxml': ['application/srgs+xml'], - 'gs': ['text/x-genie'], - 'gsf': ['application/x-font-ghostscript', 'application/x-font-type1'], - 'gsh': ['text/x-groovy'], - 'gsheet': ['application/vnd.google-apps.spreadsheet'], - 'gslides': ['application/vnd.google-apps.presentation'], - 'gsm': ['audio/x-gsm'], - 'gtar': ['application/x-gtar', 'application/x-tar'], - 'gtm': ['application/vnd.groove-tool-message'], - 'gtw': ['model/vnd.gtw'], - 'gv': ['text/vnd.graphviz'], - 'gvp': ['text/google-video-pointer', 'text/x-google-video-pointer'], - 'gvy': ['text/x-groovy'], - 'gx': ['text/x-gcode-gx'], - 'gxf': ['application/gxf'], - 'gxt': ['application/vnd.geonext'], - 'gy': ['text/x-groovy'], - 'gz': ['application/x-gzip', 'application/gzip'], - 'h': ['text/x-c', 'text/x-chdr'], - 'h++': ['text/x-c++hdr'], - 'h261': ['video/h261'], - 'h263': ['video/h263'], - 'h264': ['video/h264'], - 'h4': ['application/x-hdf'], - 'h5': ['application/x-hdf'], - 'hal': ['application/vnd.hal+xml'], - 'hbci': ['application/vnd.hbci'], - 'hbs': ['text/x-handlebars-template'], - 'hdd': ['application/x-virtualbox-hdd'], - 'hdf': ['application/x-hdf'], - 'hdf4': ['application/x-hdf'], - 'hdf5': ['application/x-hdf'], - 'hdp': ['image/jxr', 'image/vnd.ms-photo'], - 'heic': [ - 'image/heic', - 'image/heic-sequence', - 'image/heif', - 'image/heif-sequence' - ], - 'heics': ['image/heic-sequence'], - 'heif': [ - 'image/heic', - 'image/heic-sequence', - 'image/heif', - 'image/heif-sequence' - ], - 'heifs': ['image/heif-sequence'], - 'hej2': ['image/hej2k'], - 'held': ['application/atsc-held+xml'], - 'hfe': ['application/x-hfe-file', 'application/x-hfe-floppy-image'], - 'hh': ['text/x-c', 'text/x-c++hdr'], - 'hif': [ - 'image/heic', - 'image/heic-sequence', - 'image/heif', - 'image/heif-sequence' - ], - 'hjson': ['application/hjson'], - 'hlp': ['application/winhlp', 'zz-application/zz-winassoc-hlp'], - 'hp': ['text/x-c++hdr'], - 'hpgl': ['application/vnd.hp-hpgl'], - 'hpid': ['application/vnd.hp-hpid'], - 'hpp': ['text/x-c++hdr'], - 'hps': ['application/vnd.hp-hps'], - 'hqx': ['application/stuffit', 'application/mac-binhex40'], - 'hs': ['text/x-haskell'], - 'hsj2': ['image/hsj2'], - 'hta': ['application/hta'], - 'htc': ['text/x-component'], - 'htke': ['application/vnd.kenameaapp'], - 'htm': ['text/html', 'application/xhtml+xml'], - 'html': ['text/html', 'application/xhtml+xml'], - 'hvd': ['application/vnd.yamaha.hv-dic'], - 'hvp': ['application/vnd.yamaha.hv-voice'], - 'hvs': ['application/vnd.yamaha.hv-script'], - 'hwp': ['application/vnd.haansoft-hwp', 'application/x-hwp'], - 'hwt': ['application/vnd.haansoft-hwt', 'application/x-hwt'], - 'hxx': ['text/x-c++hdr'], - 'i2g': ['application/vnd.intergeo'], - 'ica': ['application/x-ica'], - 'icb': [ - 'application/tga', - 'application/x-targa', - 'application/x-tga', - 'image/targa', - 'image/tga', - 'image/x-icb', - 'image/x-targa', - 'image/x-tga' - ], - 'icc': ['application/vnd.iccprofile'], - 'ice': ['x-conference/x-cooltalk'], - 'icm': ['application/vnd.iccprofile'], - 'icns': ['image/x-icns'], - 'ico': [ - 'application/ico', - 'image/ico', - 'image/icon', - 'image/vnd.microsoft.icon', - 'image/x-ico', - 'image/x-icon', - 'text/ico' - ], - 'ics': ['application/ics', 'text/calendar', 'text/x-vcalendar'], - 'idl': ['text/x-idl'], - 'ief': ['image/ief'], - 'ifb': ['text/calendar'], - 'iff': ['image/x-iff', 'image/x-ilbm'], - 'ifm': ['application/vnd.shana.informed.formdata'], - 'iges': ['model/iges'], - 'igl': ['application/vnd.igloader'], - 'igm': ['application/vnd.insors.igm'], - 'igs': ['model/iges'], - 'igx': ['application/vnd.micrografx.igx'], - 'iif': ['application/vnd.shana.informed.interchange'], - 'ilbm': ['image/x-iff', 'image/x-ilbm'], - 'ime': ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], - 'img': ['application/vnd.efi.img', 'application/x-raw-disk-image'], - 'img.xz': ['application/x-raw-disk-image-xz-compressed'], - 'imp': ['application/vnd.accpac.simply.imp'], - 'ims': ['application/vnd.ms-ims'], - 'imy': ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], - 'in': ['text/plain'], - 'ini': ['text/plain'], - 'ink': ['application/inkml+xml'], - 'inkml': ['application/inkml+xml'], - 'ins': ['application/x-tex', 'text/x-tex'], - 'install': ['application/x-install-instructions'], - 'iota': ['application/vnd.astraea-software.iota'], - 'ipfix': ['application/ipfix'], - 'ipk': ['application/vnd.shana.informed.package'], - 'ips': ['application/x-ips-patch'], - 'iptables': ['text/x-iptables'], - 'ipynb': ['application/x-ipynb+json'], - 'irm': ['application/vnd.ibm.rights-management'], - 'irp': ['application/vnd.irepository.package+xml'], - 'iso': [ - 'application/vnd.efi.iso', - 'application/x-cd-image', - 'application/x-dreamcast-rom', - 'application/x-gamecube-iso-image', - 'application/x-gamecube-rom', - 'application/x-iso9660-image', - 'application/x-saturn-rom', - 'application/x-sega-cd-rom', - 'application/x-sega-pico-rom', - 'application/x-wbfs', - 'application/x-wia', - 'application/x-wii-iso-image', - 'application/x-wii-rom' - ], - 'iso9660': [ - 'application/vnd.efi.iso', - 'application/x-cd-image', - 'application/x-iso9660-image' - ], - 'it': ['audio/x-it'], - 'it87': ['application/x-it87'], - 'itp': ['application/vnd.shana.informed.formtemplate'], - 'its': ['application/its+xml'], - 'ivp': ['application/vnd.immervision-ivp'], - 'ivu': ['application/vnd.immervision-ivu'], - 'j2c': ['image/x-jp2-codestream'], - 'j2k': ['image/x-jp2-codestream'], - 'jad': ['text/vnd.sun.j2me.app-descriptor'], - 'jade': ['text/jade'], - 'jam': ['application/vnd.jam'], - 'jar': [ - 'application/x-java-archive', - 'application/java-archive', - 'application/x-jar' - ], - 'jardiff': ['application/x-java-archive-diff'], - 'java': ['text/x-java', 'text/x-java-source'], - 'jceks': ['application/x-java-jce-keystore'], - 'jfif': ['image/jpeg', 'image/pjpeg'], - 'jhc': ['image/jphc'], - 'jisp': ['application/vnd.jisp'], - 'jks': ['application/x-java-keystore'], - 'jl': ['text/julia'], - 'jls': ['image/jls'], - 'jlt': ['application/vnd.hp-jlyt'], - 'jng': ['image/x-jng'], - 'jnlp': ['application/x-java-jnlp-file'], - 'joda': ['application/vnd.joost.joda-archive'], - 'jp2': [ - 'image/jp2', - 'image/jpeg2000', - 'image/jpeg2000-image', - 'image/x-jpeg2000-image' - ], - 'jpc': ['image/x-jp2-codestream'], - 'jpe': ['image/jpeg', 'image/pjpeg'], - 'jpeg': ['image/jpeg', 'image/pjpeg'], - 'jpf': ['image/jpx'], - 'jpg': ['image/jpeg', 'image/pjpeg'], - 'jpg2': [ - 'image/jp2', - 'image/jpeg2000', - 'image/jpeg2000-image', - 'image/x-jpeg2000-image' - ], - 'jpgm': ['image/jpm', 'video/jpm'], - 'jpgv': ['video/jpeg'], - 'jph': ['image/jph'], - 'jpm': ['image/jpm', 'video/jpm'], - 'jpr': ['application/x-jbuilder-project'], - 'jpx': ['application/x-jbuilder-project', 'image/jpx'], - 'jrd': ['application/jrd+json'], - 'js': [ - 'text/javascript', - 'application/javascript', - 'application/x-javascript', - 'text/jscript' - ], - 'jse': ['text/jscript.encode'], - 'jsm': [ - 'application/javascript', - 'application/x-javascript', - 'text/javascript', - 'text/jscript' - ], - 'json': ['application/json', 'application/schema+json'], - 'json-patch': ['application/json-patch+json'], - 'json5': ['application/json5'], - 'jsonld': ['application/ld+json'], - 'jsonml': ['application/jsonml+json'], - 'jsx': ['text/jsx'], - 'jxl': ['image/jxl'], - 'jxr': ['image/jxr', 'image/vnd.ms-photo'], - 'jxra': ['image/jxra'], - 'jxrs': ['image/jxrs'], - 'jxs': ['image/jxs'], - 'jxsc': ['image/jxsc'], - 'jxsi': ['image/jxsi'], - 'jxss': ['image/jxss'], - 'k25': ['image/x-kodak-k25'], - 'k7': ['application/x-thomson-cassette'], - 'kar': ['audio/midi', 'audio/x-midi'], - 'karbon': ['application/vnd.kde.karbon', 'application/x-karbon'], - 'kdbx': ['application/x-keepass2'], - 'kdc': ['image/x-kodak-kdc'], - 'kdelnk': ['application/x-desktop', 'application/x-gnome-app-info'], - 'kexi': [ - 'application/x-kexiproject-sqlite', - 'application/x-kexiproject-sqlite2', - 'application/x-kexiproject-sqlite3', - 'application/x-vnd.kde.kexi' - ], - 'kexic': ['application/x-kexi-connectiondata'], - 'kexis': ['application/x-kexiproject-shortcut'], - 'key': [ - 'application/vnd.apple.keynote', - 'application/pgp-keys', - 'application/x-iwork-keynote-sffkey' - ], - 'keynote': ['application/vnd.apple.keynote'], - 'kfo': ['application/vnd.kde.kformula', 'application/x-kformula'], - 'kfx': ['application/vnd.amazon.mobi8-ebook', 'application/x-mobi8-ebook'], - 'kia': ['application/vnd.kidspiration'], - 'kil': ['application/x-killustrator'], - 'kino': ['application/smil', 'application/smil+xml'], - 'kml': ['application/vnd.google-earth.kml+xml'], - 'kmz': ['application/vnd.google-earth.kmz'], - 'kne': ['application/vnd.kinar'], - 'knp': ['application/vnd.kinar'], - 'kon': ['application/vnd.kde.kontour', 'application/x-kontour'], - 'kpm': ['application/x-kpovmodeler'], - 'kpr': ['application/vnd.kde.kpresenter', 'application/x-kpresenter'], - 'kpt': ['application/vnd.kde.kpresenter', 'application/x-kpresenter'], - 'kpxx': ['application/vnd.ds-keypoint'], - 'kra': ['application/x-krita'], - 'krz': ['application/x-krita'], - 'ks': ['application/x-java-keystore'], - 'ksp': ['application/vnd.kde.kspread', 'application/x-kspread'], - 'ksy': ['text/x-kaitai-struct'], - 'kt': ['text/x-kotlin'], - 'ktr': ['application/vnd.kahootz'], - 'ktx': ['image/ktx'], - 'ktx2': ['image/ktx2'], - 'ktz': ['application/vnd.kahootz'], - 'kud': ['application/x-kugar'], - 'kwd': ['application/vnd.kde.kword', 'application/x-kword'], - 'kwt': ['application/vnd.kde.kword', 'application/x-kword'], - 'la': ['application/x-shared-library-la'], - 'lasxml': ['application/vnd.las.las+xml'], - 'latex': ['application/x-latex', 'application/x-tex', 'text/x-tex'], - 'lbd': ['application/vnd.llamagraphics.life-balance.desktop'], - 'lbe': ['application/vnd.llamagraphics.life-balance.exchange+xml'], - 'lbm': ['image/x-iff', 'image/x-ilbm'], - 'ldif': ['text/x-ldif'], - 'les': ['application/vnd.hhe.lesson-player'], - 'less': ['text/less'], - 'lgr': ['application/lgr+xml'], - 'lha': ['application/x-lha', 'application/x-lzh-compressed'], - 'lhs': ['text/x-literate-haskell'], - 'lhz': ['application/x-lhz'], - 'lib': ['application/vnd.microsoft.portable-executable'], - 'link66': ['application/vnd.route66.link66+xml'], - 'lisp': ['text/x-common-lisp'], - 'list': ['text/plain'], - 'list3820': ['application/vnd.ibm.modcap'], - 'listafp': ['application/vnd.ibm.modcap'], - 'litcoffee': ['text/coffeescript'], - 'lmdb': ['application/x-lmdb'], - 'lnk': ['application/x-ms-shortcut', 'application/x-win-lnk'], - 'lnx': ['application/x-atari-lynx-rom'], - 'loas': ['audio/usac'], - 'log': ['text/plain', 'text/x-log'], - 'lostxml': ['application/lost+xml'], - 'lrm': ['application/vnd.ms-lrm'], - 'lrv': ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], - 'lrz': ['application/x-lrzip'], - 'ltf': ['application/vnd.frogans.ltf'], - 'ltx': ['application/x-tex', 'text/x-tex'], - 'lua': ['text/x-lua'], - 'luac': ['application/x-lua-bytecode'], - 'lvp': ['audio/vnd.lucent.voice'], - 'lwo': ['image/x-lwo'], - 'lwob': ['image/x-lwo'], - 'lwp': ['application/vnd.lotus-wordpro'], - 'lws': ['image/x-lws'], - 'ly': ['text/x-lilypond'], - 'lyx': ['application/x-lyx', 'text/x-lyx'], - 'lz': ['application/x-lzip'], - 'lz4': ['application/x-lz4'], - 'lzh': ['application/x-lha', 'application/x-lzh-compressed'], - 'lzma': ['application/x-lzma'], - 'lzo': ['application/x-lzop'], - 'm': ['text/x-matlab', 'text/x-objcsrc', 'text/x-octave'], - 'm13': ['application/x-msmediaview'], - 'm14': ['application/x-msmediaview'], - 'm15': ['audio/x-mod'], - 'm1u': ['video/vnd.mpegurl', 'video/x-mpegurl'], - 'm1v': ['video/mpeg'], - 'm21': ['application/mp21'], - 'm2a': ['audio/mpeg'], - 'm2t': ['video/mp2t'], - 'm2ts': ['video/mp2t'], - 'm2v': ['video/mpeg'], - 'm3a': ['audio/mpeg'], - 'm3u': [ - 'audio/x-mpegurl', - 'application/m3u', - 'application/vnd.apple.mpegurl', - 'audio/m3u', - 'audio/mpegurl', - 'audio/x-m3u', - 'audio/x-mp3-playlist' - ], - 'm3u8': [ - 'application/m3u', - 'application/vnd.apple.mpegurl', - 'audio/m3u', - 'audio/mpegurl', - 'audio/x-m3u', - 'audio/x-mp3-playlist', - 'audio/x-mpegurl' - ], - 'm4': ['application/x-m4'], - 'm4a': ['audio/mp4', 'audio/m4a', 'audio/x-m4a'], - 'm4b': ['audio/x-m4b'], - 'm4p': ['application/mp4'], - 'm4r': ['audio/x-m4r'], - 'm4s': ['video/iso.segment'], - 'm4u': ['video/vnd.mpegurl', 'video/x-mpegurl'], - 'm4v': ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], - 'm7': ['application/x-thomson-cartridge-memo7'], - 'ma': ['application/mathematica'], - 'mab': ['application/x-markaby'], - 'mads': ['application/mads+xml'], - 'maei': ['application/mmt-aei+xml'], - 'mag': ['application/vnd.ecowin.chart'], - 'mak': ['text/x-makefile'], - 'maker': ['application/vnd.framemaker'], - 'man': ['application/x-troff-man', 'text/troff'], - 'manifest': ['text/cache-manifest'], - 'map': ['application/json'], - 'markdown': ['text/markdown', 'text/x-markdown'], - 'mathml': ['application/mathml+xml'], - 'mb': ['application/mathematica'], - 'mbk': ['application/vnd.mobius.mbk'], - 'mbox': ['application/mbox'], - 'mc1': ['application/vnd.medcalcdata'], - 'mc2': ['text/vnd.senx.warpscript'], - 'mcd': ['application/vnd.mcd'], - 'mcurl': ['text/vnd.curl.mcurl'], - 'md': ['text/markdown', 'text/x-markdown'], - 'mdb': [ - 'application/x-msaccess', - 'application/mdb', - 'application/msaccess', - 'application/vnd.ms-access', - 'application/vnd.msaccess', - 'application/x-lmdb', - 'application/x-mdb', - 'zz-application/zz-winassoc-mdb' - ], - 'mdi': ['image/vnd.ms-modi'], - 'mdx': ['application/x-genesis-32x-rom', 'text/mdx'], - 'me': ['text/troff', 'text/x-troff-me'], - 'med': ['audio/x-mod'], - 'mesh': ['model/mesh'], - 'meta4': ['application/metalink4+xml'], - 'metalink': ['application/metalink+xml'], - 'mets': ['application/mets+xml'], - 'mfm': ['application/vnd.mfmp'], - 'mft': ['application/rpki-manifest'], - 'mgp': [ - 'application/vnd.osgeo.mapguide.package', - 'application/x-magicpoint' - ], - 'mgz': ['application/vnd.proteus.magazine'], - 'mht': ['message/rfc822'], - 'mhtml': ['message/rfc822'], - 'mid': ['audio/midi', 'audio/x-midi'], - 'midi': ['audio/midi', 'audio/x-midi'], - 'mie': ['application/x-mie'], - 'mif': ['application/vnd.mif', 'application/x-mif'], - 'mime': ['message/rfc822'], - 'minipsf': ['audio/x-minipsf'], - 'mj2': ['video/mj2'], - 'mjp2': ['video/mj2'], - 'mjs': ['application/javascript', 'text/javascript'], - 'mk': ['text/x-makefile'], - 'mk3d': ['video/x-matroska', 'video/x-matroska-3d'], - 'mka': ['audio/x-matroska'], - 'mkd': ['text/markdown', 'text/x-markdown'], - 'mks': ['video/x-matroska'], - 'mkv': ['video/x-matroska'], - 'ml': ['text/x-ocaml'], - 'mli': ['text/x-ocaml'], - 'mlp': ['application/vnd.dolby.mlp'], - 'mm': ['application/x-freemind', 'text/x-troff-mm'], - 'mmd': ['application/vnd.chipnuts.karaoke-mmd'], - 'mmf': ['application/vnd.smaf'], - 'mml': ['application/mathml+xml', 'text/mathml'], - 'mmr': ['image/vnd.fujixerox.edmics-mmr'], - 'mng': ['video/x-mng'], - 'mny': ['application/x-msmoney'], - 'mo': ['application/x-gettext-translation'], - 'mo3': ['audio/x-mo3'], - 'mobi': ['application/x-mobipocket-ebook'], - 'moc': ['text/x-moc'], - 'mod': ['audio/x-mod'], - 'mods': ['application/mods+xml'], - 'mof': ['text/x-mof'], - 'mol': ['chemical/x-mdl-molfile'], - 'mol2': ['chemical/x-mol2'], - 'moo': ['chemical/x-mopac-out'], - 'moov': ['video/quicktime'], - 'mount': ['text/x-systemd-unit'], - 'mov': ['video/quicktime'], - 'movie': ['video/x-sgi-movie'], - 'mp2': [ - 'audio/mpeg', - 'audio/x-mpeg', - 'video/mpeg', - 'video/x-mpeg', - 'video/mp2t' - ], - 'mp21': ['application/mp21'], - 'mp2a': ['audio/mpeg'], - 'mp3': ['audio/mpeg', 'audio/x-mp3', 'audio/x-mpg'], - 'mp4': ['video/mp4', 'application/mp4'], - 'mp4a': ['audio/mp4'], - 'mp4s': ['application/mp4'], - 'mp4v': ['video/mp4'], - 'mpc': ['application/vnd.mophun.certificate', 'audio/x-musepack'], - 'mpe': ['video/mpeg'], - 'mpeg': ['video/mpeg'], - 'mpega': ['audio/mpeg'], - 'mpg': ['video/mpeg'], - 'mpg4': ['video/mp4'], - 'mpga': ['audio/mpeg'], - 'mpkg': ['application/vnd.apple.installer+xml'], - 'mpl': ['text/x-mpl2-playlist', 'video/mp2t'], - 'mpls': ['video/mp2t'], - 'mpm': ['application/vnd.blueice.multipass'], - 'mpn': ['application/vnd.mophun.application'], - 'mpp': ['application/vnd.ms-project'], - 'mpt': ['application/vnd.ms-project'], - 'mpy': ['application/vnd.ibm.minipay'], - 'mqy': ['application/vnd.mobius.mqy'], - 'mrc': ['application/marc'], - 'mrcx': ['application/marcxml+xml'], - 'ms': ['text/troff', 'text/x-troff-ms'], - 'mscml': ['application/mediaservercontrol+xml'], - 'mseed': ['application/vnd.fdsn.mseed'], - 'mseq': ['application/vnd.mseq'], - 'msf': ['application/vnd.epson.msf'], - 'msh': ['model/mesh'], - 'msi': ['application/x-msi', 'application/x-msdownload'], - 'msl': ['application/vnd.mobius.msl'], - 'msod': ['image/x-msod'], - 'msty': ['application/vnd.muvee.style'], - 'msx': ['application/x-msx-rom'], - 'mtl': ['model/mtl', 'text/x-mtl'], - 'mtm': ['audio/x-mod'], - 'mts': ['model/vnd.mts', 'video/mp2t'], - 'mup': ['text/x-mup'], - 'mus': ['application/vnd.musician'], - 'musicxml': ['application/vnd.recordare.musicxml+xml'], - 'mvb': ['application/x-msmediaview'], - 'mwf': ['application/vnd.mfer'], - 'mxf': ['application/mxf'], - 'mxl': ['application/vnd.recordare.musicxml'], - 'mxmf': ['audio/mobile-xmf'], - 'mxml': ['application/xv+xml'], - 'mxs': ['application/vnd.triscape.mxs'], - 'mxu': ['video/vnd.mpegurl', 'video/x-mpegurl'], - 'n-gage': ['application/vnd.nokia.n-gage.symbian.install'], - 'n3': ['text/n3'], - 'n64': ['application/x-n64-rom'], - 'nb': [ - 'application/mathematica', - 'application/vnd.wolfram.mathematica', - 'application/x-mathematica' - ], - 'nbp': ['application/vnd.wolfram.player'], - 'nc': ['application/x-netcdf'], - 'ncx': ['application/x-dtbncx+xml'], - 'nds': ['application/x-nintendo-ds-rom'], - 'nef': ['image/x-nikon-nef'], - 'nes': ['application/x-nes-rom'], - 'nez': ['application/x-nes-rom'], - 'nfo': ['text/x-nfo'], - 'ngc': ['application/x-neo-geo-pocket-color-rom'], - 'ngdat': ['application/vnd.nokia.n-gage.data'], - 'ngp': ['application/x-neo-geo-pocket-rom'], - 'nitf': ['application/vnd.nitf'], - 'nlu': ['application/vnd.neurolanguage.nlu'], - 'nml': ['application/vnd.enliven'], - 'nnd': ['application/vnd.noblenet-directory'], - 'nns': ['application/vnd.noblenet-sealer'], - 'nnw': ['application/vnd.noblenet-web'], - 'not': ['text/x-mup'], - 'npx': ['image/vnd.net-fpx'], - 'nsc': ['application/x-conference', 'application/x-netshow-channel'], - 'nsf': ['application/vnd.lotus-notes'], - 'ntf': ['application/vnd.nitf'], - 'numbers': [ - 'application/vnd.apple.numbers', - 'application/x-iwork-numbers-sffnumbers' - ], - 'nwc': ['application/x-nwc'], - 'nzb': ['application/x-nzb'], - 'o': ['application/x-object'], - 'oa2': ['application/vnd.fujitsu.oasys2'], - 'oa3': ['application/vnd.fujitsu.oasys3'], - 'oas': ['application/vnd.fujitsu.oasys'], - 'obd': ['application/x-msbinder'], - 'obj': ['application/x-tgif', 'model/obj'], - 'ocl': ['text/x-ocl'], - 'oda': ['application/oda'], - 'odb': ['application/vnd.oasis.opendocument.database'], - 'odc': ['application/vnd.oasis.opendocument.chart'], - 'odf': ['application/vnd.oasis.opendocument.formula'], - 'odft': ['application/vnd.oasis.opendocument.formula-template'], - 'odg': ['application/vnd.oasis.opendocument.graphics'], - 'odi': ['application/vnd.oasis.opendocument.image'], - 'odm': ['application/vnd.oasis.opendocument.text-master'], - 'odp': ['application/vnd.oasis.opendocument.presentation'], - 'ods': ['application/vnd.oasis.opendocument.spreadsheet'], - 'odt': ['application/vnd.oasis.opendocument.text'], - 'oga': ['audio/ogg', 'audio/x-vorbis+ogg'], - 'ogg': [ - 'audio/ogg', - 'audio/x-ogg', - 'audio/x-vorbis+ogg', - 'video/ogg', - 'video/x-ogg' - ], - 'ogm': ['video/x-ogm', 'video/x-ogm+ogg'], - 'ogv': ['video/ogg'], - 'ogx': ['application/ogg'], - 'old': ['application/x-trash'], - 'oleo': ['application/x-oleo'], - 'omf': ['application/x-omf'], - 'onepkg': ['application/onenote'], - 'onetmp': ['application/onenote'], - 'onetoc': ['application/onenote'], - 'onetoc2': ['application/onenote'], - 'ooc': ['text/x-ooc'], - 'opf': ['application/oebps-package+xml'], - 'opml': ['text/x-opml', 'text/x-opml+xml'], - 'oprc': ['application/vnd.palm'], - 'opus': ['audio/ogg', 'audio/x-ogg'], - 'ora': ['image/openraster'], - 'orf': ['image/x-olympus-orf'], - 'org': ['application/vnd.lotus-organizer', 'text/org'], - 'osf': ['application/vnd.yamaha.openscoreformat'], - 'osfpvg': ['application/vnd.yamaha.openscoreformat.osfpvg+xml'], - 'otc': ['application/vnd.oasis.opendocument.chart-template'], - 'otf': ['application/vnd.oasis.opendocument.formula-template', 'font/otf'], - 'otg': ['application/vnd.oasis.opendocument.graphics-template'], - 'oth': ['application/vnd.oasis.opendocument.text-web'], - 'oti': ['application/vnd.oasis.opendocument.image-template'], - 'otp': ['application/vnd.oasis.opendocument.presentation-template'], - 'ots': ['application/vnd.oasis.opendocument.spreadsheet-template'], - 'ott': ['application/vnd.oasis.opendocument.text-template'], - 'ova': ['application/ovf', 'application/x-virtualbox-ova'], - 'ovf': ['application/x-virtualbox-ovf'], - 'owl': ['application/rdf+xml'], - 'oxps': ['application/oxps'], - 'oxt': ['application/vnd.openofficeorg.extension'], - 'p': ['text/x-pascal'], - 'p10': ['application/pkcs10'], - 'p12': ['application/pkcs12', 'application/x-pkcs12'], - 'p65': ['application/x-pagemaker'], - 'p7b': ['application/x-pkcs7-certificates'], - 'p7c': ['application/pkcs7-mime'], - 'p7m': ['application/pkcs7-mime'], - 'p7r': ['application/x-pkcs7-certreqresp'], - 'p7s': ['application/pkcs7-signature'], - 'p8': ['application/pkcs8'], - 'p8e': ['application/pkcs8-encrypted'], - 'pack': ['application/x-java-pack200'], - 'pages': [ - 'application/vnd.apple.pages', - 'application/x-iwork-pages-sffpages' - ], - 'pak': ['application/x-pak'], - 'palm': ['application/vnd.palm'], - 'pam': ['application/x-php-arc-managed'], - 'paq': ['application/x-par2'], - 'par': ['application/x-par2'], - 'par2': ['application/x-par2'], - 'pas': ['text/x-pascal'], - 'pat': ['image/x-coreldrawpattern'], - 'patch': ['text/x-diff', 'text/x-patch'], - 'path': ['text/x-systemd-unit'], - 'paw': ['application/vnd.pawaafile'], - 'pbd': ['application/vnd.powerbuilder6'], - 'pbm': ['image/x-portable-bitmap'], - 'pcap': [ - 'application/pcap', - 'application/vnd.tcpdump.pcap', - 'application/x-pcap' - ], - 'pcd': ['image/x-photo-cd'], - 'pce': ['application/x-pc-engine-rom'], - 'pcf': ['application/x-cisco-vpn-settings', 'application/x-font-pcf'], - 'pcf.gz': ['application/x-font-pcf'], - 'pcf.z': ['application/x-font-pcf'], - 'pcl': ['application/vnd.hp-pcl'], - 'pclxl': ['application/vnd.hp-pclxl'], - 'pct': ['image/x-pict'], - 'pcurl': ['application/vnd.curl.pcurl'], - 'pcx': ['image/pcx', 'image/vnd.zbrush.pcx', 'image/x-pcx'], - 'pdb': [ - 'application/vnd.palm', - 'application/x-aportisdoc', - 'application/x-palm-database', - 'application/x-pilot', - 'chemical/x-pdb' - ], - 'pdc': ['application/x-aportisdoc'], - 'pdf': ['application/pdf', 'application/x-pdf'], - 'pdf.bz2': ['application/x-bzpdf'], - 'pdf.gz': ['application/x-gzpdf'], - 'pef': ['image/x-pentax-pef'], - 'pem': ['application/x-x509-ca-cert'], - 'perl': ['application/x-perl'], - 'pfa': ['application/x-font-type1'], - 'pfb': ['application/x-font-type1'], - 'pfm': ['application/x-font-type1'], - 'pfr': ['application/font-tdpfr'], - 'pfx': ['application/x-pkcs12'], - 'pgm': ['image/x-portable-graymap'], - 'pgn': ['application/x-chess-pgn'], - 'pgp': [ - 'application/pgp', - 'application/pgp-encrypted', - 'application/pgp-keys', - 'application/pgp-signature' - ], - 'php': ['application/x-httpd-php', 'application/x-php'], - 'php3': ['application/x-httpd-php3', 'application/x-php'], - 'php4': ['application/x-httpd-php4', 'application/x-php'], - 'php5': ['application/x-httpd-php5'], - 'phps': ['application/x-httpd-php-source'], - 'pht': ['application/x-httpd-php'], - 'phtml': ['application/x-httpd-php'], - 'pic': ['image/x-pict'], - 'pict': ['image/pict', 'image/x-pict'], - 'pkg': ['application/x-newton-compatible-pkg'], - 'pki': ['application/pkixcmp'], - 'pkipath': ['application/pkix-pkipath'], - 'pkpass': ['application/vnd.apple.pkpass'], - 'pl': ['application/x-perl', 'text/x-perl'], - 'plb': ['application/vnd.3gpp.pic-bw-large'], - 'plc': ['application/vnd.mobius.plc'], - 'plf': ['application/vnd.pocketlearn'], - 'pln': ['application/x-planperfect'], - 'pls': ['application/pls+xml', 'audio/x-scpls'], - 'plt': ['application/vnd.hp-hpgl'], - 'pm': ['application/x-perl', 'text/x-perl'], - 'pmd': ['application/x-pagemaker'], - 'pml': ['application/vnd.ctc-posml'], - 'png': ['image/png'], - 'pnm': ['image/x-portable-anymap'], - 'pntg': ['image/x-macpaint'], - 'po': ['text/x-gettext-translation'], - 'pod': ['application/x-perl'], - 'por': ['application/x-spss-por'], - 'portpkg': ['application/vnd.macports.portpkg'], - 'pot': [ - 'application/mspowerpoint', - 'application/vnd.ms-powerpoint', - 'text/x-gettext-translation-template' - ], - 'potm': ['application/vnd.ms-powerpoint.template.macroenabled.12'], - 'potx': [ - 'application/vnd.openxmlformats-officedocument.presentationml.template' - ], - 'ppam': ['application/vnd.ms-powerpoint.addin.macroenabled.12'], - 'ppd': ['application/vnd.cups-ppd'], - 'ppm': ['image/x-portable-pixmap'], - 'pps': ['application/mspowerpoint', 'application/vnd.ms-powerpoint'], - 'ppsm': ['application/vnd.ms-powerpoint.slideshow.macroenabled.12'], - 'ppsx': [ - 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' - ], - 'ppt': [ - 'application/mspowerpoint', - 'application/powerpoint', - 'application/vnd.ms-powerpoint', - 'application/x-mspowerpoint' - ], - 'pptm': ['application/vnd.ms-powerpoint.presentation.macroenabled.12'], - 'pptx': [ - 'application/vnd.openxmlformats-officedocument.presentationml.presentation' - ], - 'ppz': ['application/mspowerpoint'], - 'pqa': ['application/vnd.palm'], - 'prc': [ - 'application/vnd.palm', - 'application/x-mobipocket-ebook', - 'application/x-palm-database' - ], - 'pre': ['application/vnd.lotus-freelance'], - 'prf': ['application/pics-rules'], - 'ps': ['application/postscript'], - 'ps.bz2': ['application/x-bzpostscript'], - 'ps.gz': ['application/x-gzpostscript'], - 'psb': ['application/vnd.3gpp.pic-bw-small'], - 'psd': ['application/x-photoshop', 'image/vnd.adobe.photoshop'], - 'psf': ['application/x-font-linux-psf', 'audio/x-psf'], - 'psf.gz': ['application/x-gz-font-linux-psf'], - 'psflib': ['audio/x-psflib'], - 'psid': ['audio/prs.sid'], - 'pskcxml': ['application/pskc+xml'], - 'psw': ['application/x-pocket-word'], - 'ptid': ['application/vnd.pvi.ptid1'], - 'pub': ['application/vnd.ms-publisher', 'application/x-mspublisher'], - 'pvb': ['application/vnd.3gpp.pic-bw-var'], - 'pvu': ['paleovu/x-pv'], - 'pw': ['application/x-pw'], - 'pwn': ['application/vnd.3m.post-it-notes'], - 'pya': ['audio/vnd.ms-playready.media.pya'], - 'pyc': ['application/x-python-code'], - 'pyo': ['application/x-python-code'], - 'pyscript': ['text/pyscript'], - 'pyv': ['video/vnd.ms-playready.media.pyv'], - 'qam': ['application/vnd.epson.quickanime'], - 'qbo': ['application/vnd.intu.qbo'], - 'qcow': ['application/x-qemu-disk'], - 'qcow2': ['application/x-qemu-disk'], - 'qd': ['application/x-qed'], - 'qed': ['application/x-qed'], - 'qfx': ['application/vnd.intu.qfx'], - 'qif': ['application/x-qw', 'image/x-quicktime'], - 'qml': ['text/x-qml'], - 'qmlproject': ['text/x-qml'], - 'qmltypes': ['text/x-qml'], - 'qom': ['application/x-qed'], - 'qps': ['application/vnd.publishare-delta-tree'], - 'qs': ['application/sparql-query'], - 'qt': ['video/quicktime'], - 'qti': ['application/x-qtiplot'], - 'qti.gz': ['application/x-qtiplot'], - 'qtif': ['image/x-quicktime'], - 'qtl': ['application/x-quicktimeplayer'], - 'qwd': ['application/vnd.quark.quarkxpress'], - 'qwt': ['application/vnd.quark.quarkxpress'], - 'qxb': ['application/vnd.quark.quarkxpress'], - 'qxd': ['application/vnd.quark.quarkxpress'], - 'qxl': ['application/vnd.quark.quarkxpress'], - 'qxt': ['application/vnd.quark.quarkxpress'], - 'ra': [ - 'audio/vnd.rn-realaudio', - 'audio/x-pn-realaudio', - 'audio/x-realaudio' - ], - 'raf': ['image/x-fuji-raf'], - 'ram': ['application/ram', 'audio/x-pn-realaudio'], - 'raml': ['application/raml+yaml'], - 'rar': [ - 'application/rar', - 'application/vnd.rar', - 'application/x-rar', - 'application/x-rar-compressed' - ], - 'ras': ['image/x-cmu-raster'], - 'raw': ['image/x-panasonic-raw'], - 'rax': ['audio/vnd.rn-realaudio'], - 'rb': ['application/x-ruby', 'text/ruby'], - 'rbw': ['application/x-ruby'], - 'rcprofile': ['application/vnd.ipunplugged.rcprofile'], - 'rdf': ['application/rdf+xml'], - 'rdfs': ['application/rdf+xml'], - 'rdz': ['application/vnd.data-vision.rdz'], - 'reg': ['text/x-ms-regedit'], - 'rexx': ['text/x-script.rexx'], - 'rez': ['application/x-rezfile'], - 'rf64': ['audio/x-rf64'], - 'rgb': ['image/x-rgb'], - 'rhtml': ['application/x-httpd-eruby'], - 'rip': ['audio/vnd.rip'], - 'ris': ['application/x-research-info-systems'], - 'rl': ['application/resource-lists+xml'], - 'rlc': ['image/vnd.fujixerox.edmics-rlc'], - 'rld': ['application/resource-lists-diff+xml'], - 'rm': ['application/vnd.rn-realmedia', 'audio/x-pn-realaudio'], - 'rmi': ['audio/midi'], - 'rmj': ['application/vnd.rn-realmedia'], - 'rmm': ['audio/x-pn-realaudio'], - 'rmp': ['audio/x-pn-realaudio', 'audio/x-pn-realaudio-plugin'], - 'rms': ['application/vnd.jcp.javame.midlet-rms', 'video/vnd.rn-realvideo'], - 'rmvb': [ - 'application/vnd.rn-realmedia', - 'application/vnd.rn-realmedia-vbr' - ], - 'rmx': ['application/vnd.rn-realmedia'], - 'rnc': ['application/relax-ng-compact-syntax'], - 'rng': ['application/xml'], - 'roa': ['application/rpki-roa'], - 'roff': ['application/x-troff', 'text/troff'], - 'rp': ['image/vnd.rn-realpix'], - 'rp9': ['application/vnd.cloanto.rp9'], - 'rpm': ['application/x-redhat-package-manager', 'application/x-rpm'], - 'rpss': ['application/vnd.nokia.radio-presets'], - 'rpst': ['application/vnd.nokia.radio-preset'], - 'rq': ['application/sparql-query'], - 'rs': ['application/rls-services+xml', 'text/rust'], - 'rsd': ['application/rsd+xml'], - 'rss': ['application/rss+xml'], - 'rst': ['text/x-rst'], - 'rtf': ['application/rtf'], - 'rtx': ['text/richtext'], - 'run': ['application/x-makeself'], - 'rusd': ['application/route-usd+xml'], - 'rv': ['video/vnd.rn-realvideo'], - 'rvx': ['video/vnd.rn-realvideo'], - 'rw2': ['image/x-panasonic-rw2'], - 's': ['text/x-asm'], - 's3m': ['audio/s3m', 'audio/x-s3m'], - 'saf': ['application/vnd.yamaha.smaf-audio'], - 'sage': ['text/x-sagemath'], - 'sam': ['application/x-amipro'], - 'sami': ['application/x-sami'], - 'sap': ['application/x-sap-file'], - 'sass': ['text/x-sass'], - 'sat': ['application/x-sat'], - 'sb': ['application/x-scratch'], - 'sbml': ['application/sbml+xml'], - 'sc': ['application/vnd.ibm.secure-container', 'text/x-scala'], - 'scd': ['application/x-msschedule'], - 'scm': [ - 'application/vnd.lotus-screencam', - 'application/x-lothaire', - 'text/x-scheme' - ], - 'scn': ['application/x-godot-scene'], - 'scq': ['application/scvp-cv-request'], - 'scs': ['application/scvp-cv-response'], - 'scss': ['text/x-scss'], - 'sct': ['text/scriptlet'], - 'scurl': ['text/vnd.curl.scurl'], - 'sda': ['application/vnd.stardivision.draw'], - 'sdc': ['application/vnd.stardivision.calc'], - 'sdd': ['application/vnd.stardivision.impress'], - 'sdkd': ['application/vnd.solent.sdkm+xml'], - 'sdkm': ['application/vnd.solent.sdkm+xml'], - 'sdp': [ - 'application/sdp', - 'application/vnd.stardivision.impress', - 'application/x-sdp' - ], - 'sds': ['application/vnd.stardivision.chart'], - 'sdw': ['application/vnd.stardivision.writer'], - 'sea': ['application/x-sea'], - 'see': ['application/vnd.seemail'], - 'seed': ['application/vnd.fdsn.seed'], - 'sema': ['application/vnd.sema'], - 'semd': ['application/vnd.semd'], - 'semf': ['application/vnd.semf'], - 'ser': ['application/java-serialized-object'], - 'service': ['text/x-dbus-service', 'text/x-systemd-unit'], - 'setpay': ['application/set-payment-initiation'], - 'setreg': ['application/set-registration-initiation'], - 'sfd': ['application/vnd.font-fontforge-sfd'], - 'sfd-hdstx': ['application/vnd.hydrostatix.sof-data'], - 'sfg': ['application/vnd.spotfire.sfg'], - 'sfs': ['application/vnd.spotfire.sfs'], - 'sfv': ['text/x-sfv'], - 'sg': ['application/x-sg1000-rom'], - 'sgb': ['application/x-gameboy-rom'], - 'sgd': ['application/x-genesis-32x-rom'], - 'sgf': ['application/x-go-sgf'], - 'sgi': ['image/sgi', 'image/x-sgi'], - 'sgl': ['application/vnd.stardivision.writer-global'], - 'sgm': ['text/sgml'], - 'sgml': ['text/sgml'], - 'sh': ['application/x-sh', 'application/x-shellscript', 'text/x-sh'], - 'shape': ['application/x-dia-shape'], - 'shar': ['application/x-shar'], - 'shf': ['application/shf+xml'], - 'shn': ['application/x-shorten'], - 'siag': ['application/x-siag'], - 'sid': ['audio/prs.sid', 'image/x-mrsid-image'], - 'sig': ['application/pgp-signature'], - 'sik': ['application/x-trash'], - 'sil': ['audio/silk'], - 'silo': ['model/mesh'], - 'sis': ['application/vnd.symbian.install'], - 'sisx': ['application/vnd.symbian.install', 'x-epoc/x-sisx-app'], - 'sit': ['application/x-stuffit'], - 'sitx': ['application/x-stuffitx'], - 'siv': ['application/sieve'], - 'sk': ['image/x-skencil'], - 'sk1': ['image/x-skencil'], - 'skd': ['application/x-koan'], - 'skm': ['application/x-koan'], - 'skp': ['application/x-koan'], - 'skt': ['application/x-koan'], - 'sla': ['application/vnd.scribus'], - 'slaz': ['application/vnd.scribus'], - 'slk': ['text/spreadsheet'], - 'sldm': ['application/vnd.ms-powerpoint.slide.macroenabled.12'], - 'sldx': [ - 'application/vnd.openxmlformats-officedocument.presentationml.slide' - ], - 'slim': ['text/slim'], - 'slm': ['text/slim'], - 'sln': ['text/plain'], - 'slt': ['application/vnd.epson.salt'], - 'sm': ['application/vnd.stepmania.stepchart'], - 'smf': ['application/vnd.stardivision.math'], - 'smi': ['application/smil', 'application/smil+xml', 'application/x-sami'], - 'smil': ['application/smil', 'application/smil+xml'], - 'smk': ['video/vnd.radgamettools.smacker'], - 'sml': ['application/smil', 'application/smil+xml'], - 'sms': ['application/x-sms-rom'], - 'smv': ['video/x-smv'], - 'smzip': ['application/vnd.stepmania.package'], - 'snap': ['application/vnd.snap'], - 'snd': ['audio/basic'], - 'snf': ['application/x-font-snf'], - 'so': ['application/x-sharedlib'], - 'spc': ['application/x-pkcs7-certificates', 'chemical/x-galactic-spc'], - 'spd': ['application/x-font-speedo'], - 'spec': ['text/x-rpm-spec'], - 'spf': ['application/vnd.yamaha.smaf-phrase'], - 'spl': [ - 'application/futuresplash', - 'application/x-futuresplash', - 'application/x-shockwave-flash' - ], - 'spot': ['text/vnd.in3d.spot'], - 'spp': ['application/scvp-vp-response'], - 'spq': ['application/scvp-vp-request'], - 'spx': [ - 'application/xspf+xml', - 'audio/ogg', - 'audio/x-speex', - 'audio/x-speex+ogg' - ], - 'sql': ['application/sql', 'application/x-sql', 'text/x-sql'], - 'sqlite2': ['application/x-sqlite2'], - 'sqlite3': ['application/vnd.sqlite3', 'application/x-sqlite3'], - 'sqsh': ['application/vnd.squashfs'], - 'sr2': ['image/x-sony-sr2'], - 'src': ['application/x-wais-source'], - 'src.rpm': ['application/x-source-rpm'], - 'srf': ['image/x-sony-srf'], - 'srt': ['application/x-subrip'], - 'sru': ['application/sru+xml'], - 'srx': ['application/sparql-results+xml'], - 'ss': ['text/x-scheme'], - 'ssa': ['text/x-ssa'], - 'ssdl': ['application/ssdl+xml'], - 'sse': ['application/vnd.kodak-descriptor'], - 'ssf': ['application/vnd.epson.ssf'], - 'ssml': ['application/ssml+xml'], - 'st': ['application/vnd.sailingtracker.track'], - 'stc': ['application/vnd.sun.xml.calc.template'], - 'std': ['application/vnd.sun.xml.draw.template'], - 'stf': ['application/vnd.wt.stf'], - 'sti': ['application/vnd.sun.xml.impress.template'], - 'stk': ['application/hyperstudio'], - 'stl': [ - 'application/sla', - 'application/vnd.ms-pki.stl', - 'application/x-navistyle', - 'model/stl' - ], - 'stm': ['audio/x-stm'], - 'stp': ['application/step', 'application/x-step', 'model/step'], - 'str': ['application/vnd.pg.format'], - 'stw': ['application/vnd.sun.xml.writer.template'], - 'sub': ['image/vnd.dvb.subtitle', 'text/vnd.dvb.subtitle'], - 'sun': ['image/x-sun-raster'], - 'sus': ['application/vnd.sus-calendar'], - 'susp': ['application/vnd.sus-calendar'], - 'sv4cpio': ['application/x-sv4cpio'], - 'sv4crc': ['application/x-sv4crc'], - 'svc': ['application/vnd.dvb.service'], - 'svd': ['application/vnd.svd'], - 'svg': ['image/svg+xml'], - 'svgz': ['image/svg+xml', 'image/svg+xml-compressed'], - 'swa': ['application/x-director'], - 'swf': [ - 'application/vnd.adobe.flash.movie', - 'application/x-shockwave-flash' - ], - 'swi': ['application/vnd.aristanetworks.swi'], - 'swidtag': ['application/swid+xml'], - 'sxc': ['application/vnd.sun.xml.calc'], - 'sxd': ['application/vnd.sun.xml.draw'], - 'sxg': ['application/vnd.sun.xml.writer.global'], - 'sxi': ['application/vnd.sun.xml.impress'], - 'sxm': ['application/vnd.sun.xml.math'], - 'sxw': ['application/vnd.sun.xml.writer'], - 'sylk': ['text/spreadsheet'], - 't': ['application/x-troff', 'text/troff'], - 't2t': ['text/x-txt2tags'], - 't3': ['application/x-t3vm-image'], - 'taglet': ['application/vnd.mynfc'], - 'tao': ['application/vnd.tao.intent-module-archive'], - 'tar': ['application/x-tar'], - 'tar.bz2': ['application/x-bzip-compressed-tar'], - 'tar.gz': ['application/x-compressed-tar'], - 'tar.lzma': ['application/x-lzma-compressed-tar'], - 'tar.lzo': ['application/x-tzo'], - 'tar.xz': ['application/x-xz-compressed-tar'], - 'tar.z': ['application/x-tarz'], - 'tar.zst': ['application/x-zstd-compressed-tar'], - 'targa': [ - 'application/targa', - 'application/x-targa', - 'application/x-tga', - 'image/targa', - 'image/tga', - 'image/x-icb', - 'image/x-targa', - 'image/x-tga' - ], - 'tcap': ['application/vnd.3gpp2.tcap'], - 'tcl': ['application/x-tcl', 'text/tcl'], - 'teacher': ['application/vnd.smart.teacher'], - 'tei': ['application/tei+xml'], - 'teicorpus': ['application/tei+xml'], - 'tex': ['application/x-tex', 'text/x-tex'], - 'texi': ['application/x-texinfo'], - 'texinfo': ['application/x-texinfo'], - 'text': ['text/plain'], - 'tfi': ['application/thraud+xml'], - 'tfm': ['application/x-tex-tfm'], - 'tga': [ - 'application/targa', - 'application/x-targa', - 'application/x-tga', - 'image/targa', - 'image/tga', - 'image/x-icb', - 'image/x-targa', - 'image/x-tga' - ], - 'tgz': ['application/x-compressed-tar'], - 'theme': ['application/x-theme'], - 'themepack': ['application/x-windows-themepack'], - 'thmx': ['application/vnd.ms-officetheme'], - 'tif': ['image/tiff'], - 'tiff': ['image/tiff'], - 'timer': ['text/x-systemd-unit'], - 'tk': ['text/tcl'], - 'tmo': ['application/vnd.tmobile-livetv'], - 'tnef': ['application/vnd.ms-tnef'], - 'tnf': ['application/vnd.ms-tnef'], - 'toc': ['application/x-cdrdao-toc'], - 'toml': ['application/toml'], - 'torrent': ['application/x-bittorrent'], - 'tpic': ['image/x-tga'], - 'tpl': ['application/vnd.groove-tool-template'], - 'tpt': ['application/vnd.trid.tpt'], - 'tr': ['application/x-troff', 'text/troff'], - 'tra': ['application/vnd.trueapp'], - 'trig': ['application/trig', 'application/x-trig'], - 'trm': ['application/x-msterminal'], - 'ts': ['text/vnd.trolltech.linguist', 'video/mp2t'], - 'tsd': ['application/timestamped-data'], - 'tsv': ['text/tab-separated-values'], - 'tta': ['audio/x-tta'], - 'ttc': ['application/x-font-ttf', 'font/collection'], - 'ttf': ['application/x-font-ttf', 'font/ttf'], - 'ttl': ['text/turtle'], - 'ttml': ['application/ttml+xml'], - 'twd': ['application/vnd.simtech-mindmapper'], - 'twds': ['application/vnd.simtech-mindmapper'], - 'txd': ['application/vnd.genomatix.tuxedo'], - 'txf': ['application/vnd.mobius.txf'], - 'txt': ['text/plain'], - 'u32': ['application/x-authorware-bin'], - 'udeb': [ - 'application/vnd.debian.binary-package', - 'application/x-debian-package' - ], - 'ufd': ['application/vnd.ufdl'], - 'ufdl': ['application/vnd.ufdl'], - 'ufraw': ['application/x-ufraw'], - 'ui': ['application/x-designer', 'application/x-gtk-builder'], - 'uil': ['text/x-uil'], - 'ult': ['audio/x-mod'], - 'ulx': ['application/x-glulx'], - 'umj': ['application/vnd.umajin'], - 'unf': [ - 'application/realaudio-secure', - 'application/x-uss-secure', - 'application/x-uss-stream-audio' - ], - 'unidata': ['application/x-asus-undidata'], - 'unif': ['application/x-nes-rom'], - 'unityweb': ['application/vnd.unity'], - 'uoml': ['application/vnd.uoml+xml'], - 'uri': ['text/uri-list'], - 'uris': ['text/uri-list'], - 'urls': ['text/uri-list'], - 'ustar': ['application/x-ustar'], - 'utz': ['application/vnd.uiq.theme'], - 'uu': ['text/x-uuencode'], - 'uue': ['text/x-uuencode'], - 'uva': ['audio/vnd.dece.audio'], - 'uvd': ['application/vnd.dece.data'], - 'uvf': ['application/vnd.dece.data'], - 'uvg': ['image/vnd.dece.graphic'], - 'uvh': ['video/vnd.dece.hd'], - 'uvi': ['image/vnd.dece.graphic'], - 'uvm': ['video/vnd.dece.mobile'], - 'uvp': ['video/vnd.dece.pd'], - 'uvs': ['video/vnd.dece.sd'], - 'uvt': ['application/vnd.dece.ttml+xml'], - 'uvu': ['video/vnd.uvvu.mp4'], - 'uvv': ['video/vnd.dece.video'], - 'uvva': ['audio/vnd.dece.audio'], - 'uvvd': ['application/vnd.dece.data'], - 'uvvf': ['application/vnd.dece.data'], - 'uvvg': ['image/vnd.dece.graphic'], - 'uvvh': ['video/vnd.dece.hd'], - 'uvvi': ['image/vnd.dece.graphic'], - 'uvvm': ['video/vnd.dece.mobile'], - 'uvvp': ['video/vnd.dece.pd'], - 'uvvs': ['video/vnd.dece.sd'], - 'uvvt': ['application/vnd.dece.ttml+xml'], - 'uvvu': ['video/vnd.uvvu.mp4'], - 'uvvv': ['video/vnd.dece.video'], - 'uvvx': ['application/vnd.dece.unspecified'], - 'uvvz': ['application/vnd.dece.zip'], - 'uvx': ['application/vnd.dece.unspecified'], - 'uvz': ['application/vnd.dece.zip'], - 'vala': ['text/x-vala'], - 'vapi': ['text/x-vala'], - 'vb': ['text/x-vb'], - 'vbd': ['application/vnd.videobeans'], - 'vbox': ['application/x-virtualbox-vbox'], - 'vbox-extpack': ['application/x-virtualbox-vbox-extpack'], - 'vbs': ['text/vbscript'], - 'vcard': ['text/directory', 'text/vcard', 'text/x-vcard'], - 'vcd': ['application/x-cdlink'], - 'vcf': ['text/directory', 'text/vcard', 'text/x-vcard'], - 'vcg': ['application/vnd.groove-vcard'], - 'vcs': ['text/calendar', 'text/x-vcalendar'], - 'vct': ['text/directory', 'text/vcard', 'text/x-vcard'], - 'vcx': ['application/vnd.vcx'], - 'vdi': ['application/x-virtualbox-vdi'], - 'vds': ['model/vnd.sap.vds'], - 'vhd': ['application/x-virtualbox-vhd'], - 'vhdx': ['application/x-virtualbox-vhdx'], - 'vis': ['application/vnd.visionary'], - 'viv': ['video/vnd.vivo', 'video/vivo'], - 'vivo': ['video/vnd.vivo', 'video/vivo'], - 'vlc': ['audio/x-mpegurl'], - 'vmd': ['application/vocaltec-media-desc'], - 'vmdk': ['application/x-virtualbox-vmdk'], - 'vmi': ['application/x-dreamcast-vms-info'], - 'vms': ['application/x-dreamcast-vms'], - 'vob': ['video/mpeg', 'video/x-ms-vob'], - 'voc': ['audio/voc', 'audio/x-voc'], - 'vor': ['application/vnd.stardivision.writer'], - 'vox': ['application/x-authorware-bin'], - 'vrm': ['model/vrml', 'x-world/x-vrml'], - 'vsd': ['application/vnd.visio'], - 'vsf': ['application/vnd.vsf'], - 'vss': ['application/vnd.visio'], - 'vst': ['application/vnd.visio', 'image/x-tga'], - 'vsw': ['application/vnd.visio'], - 'vtf': ['image/vnd.valve.source.texture'], - 'vtt': ['text/vtt'], - 'vtu': ['model/vnd.vtu'], - 'vxml': ['application/voicexml+xml'], - 'w3d': ['application/x-director'], - 'wad': ['application/x-doom', 'application/x-wii-wad'], - 'wav': ['audio/wav', 'audio/vnd.wave', 'audio/wave', 'audio/x-wav'], - 'wax': [ - 'audio/x-ms-asx', - 'audio/x-ms-wax', - 'video/x-ms-wax', - 'video/x-ms-wvx' - ], - 'wbmp': ['image/vnd.wap.wbmp'], - 'wbs': ['application/vnd.criticaltools.wbs+xml'], - 'wbxml': ['application/vnd.wap.wbxml'], - 'wcm': ['application/vnd.ms-works'], - 'wdb': ['application/vnd.ms-works'], - 'wdp': ['image/vnd.ms-photo'], - 'weba': ['audio/webm'], - 'webm': ['video/webm'], - 'webmanifest': ['application/manifest+json'], - 'webp': ['image/webp'], - 'wg': ['application/vnd.pmi.widget'], - 'wgt': ['application/widget'], - 'wim': ['application/x-ms-wim'], - 'wk': ['application/x-123'], - 'wks': ['application/vnd.ms-works'], - 'wm': ['video/x-ms-wm'], - 'wma': ['audio/x-ms-wma'], - 'wmd': ['application/x-ms-wmd'], - 'wmf': [ - 'application/x-msmetafile', - 'application/x-wmf', - 'image/wmf', - 'image/x-wmf' - ], - 'wml': ['text/vnd.wap.wml'], - 'wmlc': ['application/vnd.wap.wmlc'], - 'wmls': ['text/vnd.wap.wmlscript'], - 'wmlsc': ['application/vnd.wap.wmlscriptc'], - 'wmv': ['video/x-ms-wmv'], - 'wmx': [ - 'audio/x-ms-asx', - 'video/x-ms-wax', - 'video/x-ms-wmx', - 'video/x-ms-wvx' - ], - 'wmz': ['application/x-ms-wmz', 'application/x-msmetafile'], - 'woff': ['application/font-woff', 'font/woff'], - 'woff2': ['application/font-woff2', 'font/woff2'], - 'wpd': [ - 'application/vnd.wordperfect', - 'application/wordperfect', - 'application/x-wpd', - 'application/x-wordperfect' - ], - 'wpl': ['application/vnd.ms-wpl'], - 'wps': ['application/vnd.ms-works'], - 'wqd': ['application/vnd.wqd'], - 'wri': ['application/mswrite', 'application/x-mswrite'], - 'wrl': ['model/vrml', 'x-world/x-vrml'], - 'wsc': ['text/scriptlet'], - 'wsdl': ['application/wsdl+xml'], - 'wspolicy': ['application/wspolicy+xml'], - 'wsrc': ['application/x-wais-source'], - 'wtb': ['application/vnd.webturbo'], - 'wv': ['audio/x-wavpack'], - 'wvc': ['audio/x-wavpack-correction'], - 'wvp': ['audio/x-wavpack'], - 'wvx': ['audio/x-ms-asx', 'video/x-ms-wax', 'video/x-ms-wvx'], - 'wwf': ['application/x-wwf'], - 'x32': ['application/x-authorware-bin'], - 'x3d': ['model/x3d+xml'], - 'x3db': ['model/x3d+binary'], - 'x3dbz': ['model/x3d+binary'], - 'x3dv': ['model/x3d+vrml'], - 'x3dvz': ['model/x3d+vrml'], - 'x3dz': ['model/x3d+xml'], - 'x3f': ['image/x-sigma-x3f'], - 'xaml': ['application/xaml+xml'], - 'xap': ['application/x-silverlight-app'], - 'xar': ['application/vnd.xara', 'application/x-xar'], - 'xbap': ['application/x-ms-xbap'], - 'xbd': ['application/vnd.fujixerox.docuworks.binder'], - 'xbel': ['application/x-xbel'], - 'xbm': ['image/x-xbitmap'], - 'xbw': ['application/vnd.fuzzysheet'], - 'xdf': ['application/xcap-diff+xml'], - 'xdgapp': ['application/vnd.flatpak', 'application/vnd.xdgapp'], - 'xdm': ['application/vnd.syncml.dm+xml'], - 'xdp': ['application/vnd.adobe.xdp+xml'], - 'xdssc': ['application/dssc+xml'], - 'xdw': ['application/vnd.fujixerox.docuworks'], - 'xeb': ['application/x-ebook+zip'], - 'xenc': ['application/xenc+xml'], - 'xer': ['application/patch-ops-error+xml'], - 'xfdf': ['application/vnd.adobe.xfdf'], - 'xfdl': ['application/vnd.xfdl'], - 'xht': ['application/xhtml+xml'], - 'xhtml': ['application/xhtml+xml'], - 'xhvml': ['application/xv+xml'], - 'xi': ['audio/x-xi'], - 'xif': ['image/vnd.xiff'], - 'xla': [ - 'application/excel', - 'application/vnd.ms-excel', - 'application/x-excel', - 'application/x-msexcel' - ], - 'xlam': ['application/vnd.ms-excel.addin.macroenabled.12'], - 'xlb': [ - 'application/excel', - 'application/vnd.ms-excel', - 'application/x-excel' - ], - 'xlc': [ - 'application/excel', - 'application/vnd.ms-excel', - 'application/x-excel' - ], - 'xlf': ['application/x-xliff+xml'], - 'xliff': ['application/x-xliff+xml'], - 'xll': [ - 'application/excel', - 'application/vnd.ms-excel', - 'application/x-excel' - ], - 'xlm': [ - 'application/excel', - 'application/vnd.ms-excel', - 'application/x-excel' - ], - 'xls': [ - 'application/excel', - 'application/vnd.ms-excel', - 'application/x-excel', - 'application/x-msexcel' - ], - 'xlsb': ['application/vnd.ms-excel.sheet.binary.macroenabled.12'], - 'xlsm': ['application/vnd.ms-excel.sheet.macroenabled.12'], - 'xlsx': [ - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - ], - 'xlt': [ - 'application/excel', - 'application/vnd.ms-excel', - 'application/x-excel' - ], - 'xltm': ['application/vnd.ms-excel.template.macroenabled.12'], - 'xltx': [ - 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' - ], - 'xlw': [ - 'application/excel', - 'application/vnd.ms-excel', - 'application/x-excel', - 'application/x-msexcel' - ], - 'xm': ['audio/xm', 'audio/x-xm'], - 'xml': ['application/xml', 'text/xml'], - 'xmz': ['xgl/movie'], - 'xo': ['application/vnd.olpc-sugar'], - 'xoa': ['application/x-xodviewer'], - 'xop': ['application/xop+xml'], - 'xpi': ['application/x-xpinstall'], - 'xpl': ['application/xproc+xml'], - 'xpm': ['image/x-xpixmap'], - 'xpr': ['application/vnd.is-xpr'], - 'xps': ['application/vnd.ms-xpsdocument'], - 'xpw': ['application/vnd.intercon.formnet'], - 'xpx': ['application/vnd.intercon.formnet'], - 'xsd': ['application/xml'], - 'xsl': ['application/xml', 'application/xslt+xml'], - 'xslt': ['application/xslt+xml'], - 'xsm': ['application/vnd.syncml+xml'], - 'xspf': ['application/xspf+xml'], - 'xul': ['application/vnd.mozilla.xul+xml'], - 'xvm': ['application/xv+xml'], - 'xvml': ['application/xv+xml'], - 'xwd': ['image/x-xwindowdump'], - 'xyz': ['chemical/x-xyz'], - 'xz': ['application/x-xz'], - 'yaml': ['application/x-yaml', 'text/yaml'], - 'yang': ['application/yang'], - 'yin': ['application/yin+xml'], - 'yml': ['application/x-yaml', 'text/yaml'], - 'yt': ['application/vnd.youtube.yt'], - 'yurl': ['text/yurl'], - 'yuv': ['image/x-yuv'], - 'z': ['application/x-compress'], - 'z1': ['application/x-zmachine'], - 'z2': ['application/x-zmachine'], - 'z3': ['application/x-zmachine'], - 'z4': ['application/x-zmachine'], - 'z5': ['application/x-zmachine'], - 'z6': ['application/x-zmachine'], - 'z7': ['application/x-zmachine'], - 'z8': ['application/x-zmachine'], - 'zaz': ['application/vnd.zzazz.deck+xml'], - 'zip': [ - 'application/zip', - 'application/x-zip', - 'application/x-zip-compressed' - ], - 'zipx': [ - 'application/x-zip-compressed', - 'application/zip', - 'application/vnd.rar' - ], - 'zir': ['application/vnd.zul'], - 'zirz': ['application/vnd.zul'], - 'zmm': ['application/vnd.handheld-entertainment+xml'], - 'zst': ['application/zstd'], - 'zx': ['application/x-spectrum-rom'], - 'zz': ['application/zlib'], - }; - - MimeTypes([Map> map = const {}]) { - map.forEach((mimeType, extensions) { - _extensions[mimeType] = extensions; - for (var extension in extensions) { - _mimeTypes.putIfAbsent(extension, () => []).add(mimeType); - } - }); - - registerGuesser(FileBinaryMimeTypeGuesser()); - registerGuesser(FileInfoMimeTypeGuesser()); - } - - static void setDefault(MimeTypes defaultType) { - _default = defaultType; - } - - static MimeTypes getDefault() { - return _default ??= MimeTypes(); - } - - void registerGuesser(MimeTypeGuesserInterface guesser) { - _guessers.add(guesser); - } - - @override - List getExtensions(String mimeType) { - List? extensions; - if (_extensions.isNotEmpty) { - extensions = _extensions[mimeType] ?? _extensions[mimeType.toLowerCase()]; - } - return extensions ?? MAP[mimeType] ?? MAP[mimeType.toLowerCase()] ?? []; - } - - @override - List getMimeTypes(String ext) { - List? mimeTypes; - if (_mimeTypes.isNotEmpty) { - mimeTypes = _mimeTypes[ext] ?? _mimeTypes[ext.toLowerCase()]; - } - return mimeTypes ?? reverseMap[ext] ?? reverseMap[ext.toLowerCase()] ?? []; - } - - @override - Future guessMimeType(String path) async { - for (var guesser in _guessers.reversed) { - if (!guesser.isGuesserSupported()) { - continue; - } - String? mimeType = await guesser.guessMimeType(path); - if (mimeType != null) { - return mimeType; - } - } - if (!isGuesserSupported()) { - throw LogicException( - 'Unable to guess the MIME type as no guessers are available.'); - } - return null; - } - - @override - bool isGuesserSupported() { - for (var guesser in _guessers) { - if (guesser.isGuesserSupported()) { - return true; - } - } - return false; - } -} diff --git a/packages/mime/lib/src/mime_types_interface.dart b/packages/mime/lib/src/mime_types_interface.dart deleted file mode 100644 index 8039651..0000000 --- a/packages/mime/lib/src/mime_types_interface.dart +++ /dev/null @@ -1,21 +0,0 @@ -// This file is part of the Symfony package. -// -// (c) Fabien Potencier -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -import 'package:protevus_mime/mime.dart'; - -/// @author Fabien Potencier -abstract class MimeTypesInterface implements MimeTypeGuesserInterface { - /// Gets the extensions for the given MIME type in decreasing order of preference. - /// - /// Returns a list of strings representing file extensions. - List getExtensions(String mimeType); - - /// Gets the MIME types for the given extension in decreasing order of preference. - /// - /// Returns a list of strings representing MIME types. - List getMimeTypes(String ext); -} diff --git a/packages/mime/pubspec.yaml b/packages/mime/pubspec.yaml deleted file mode 100644 index b6cf485..0000000 --- a/packages/mime/pubspec.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: protevus_mime -description: The Mime Package for the Protevus Platform -version: 0.0.1 -homepage: https://protevus.com -documentation: https://docs.protevus.com -repository: https://github.com/protevus/platformo - -environment: - sdk: ^3.4.2 - -# Add regular dependencies here. -dependencies: - mime: ^1.0.5 - # path: ^1.8.0 - -dev_dependencies: - lints: ^3.0.0 - test: ^1.24.0