WIP: Proposal: remove deprecated packages #240
| @ -177,13 +177,13 @@ Then implements your data sources: | |||||||
| 
 | 
 | ||||||
| ```dart | ```dart | ||||||
| class PhotoApiDataSourceImpl extends PhotoRemoteDataSource { | class PhotoApiDataSourceImpl extends PhotoRemoteDataSource { | ||||||
|   final MiddlewareClient _client; |   final Client _client; | ||||||
| 
 | 
 | ||||||
|   PhotoApiDataSourceImpl(this._client); |   PhotoApiDataSourceImpl(this._client); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Future<Photo> getPhoto(int id) async { |   Future<Photo> getPhoto(int id) async { | ||||||
|     final response = await _client.get(Uri.parse('/photos/$id')); |     final response = await _client.get(Uri.parse('$kDefaultApiUrl/photos/$id')); | ||||||
|     final photo = |     final photo = | ||||||
|         PhotoModel.fromJson(jsonDecode(response.body) as Map<String, Object?>); |         PhotoModel.fromJson(jsonDecode(response.body) as Map<String, Object?>); | ||||||
|     return photo; |     return photo; | ||||||
| @ -197,7 +197,7 @@ class PhotoApiDataSourceImpl extends PhotoRemoteDataSource { | |||||||
|         (startQuery.isNotEmpty || limitQuery.isNotEmpty) ? '?' : ''; |         (startQuery.isNotEmpty || limitQuery.isNotEmpty) ? '?' : ''; | ||||||
|     final delimiter2 = |     final delimiter2 = | ||||||
|         (startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : ''; |         (startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : ''; | ||||||
|     final url = '/photos$delimiter1$startQuery$delimiter2$limitQuery'; |     final url = '$kDefaultApiUrl/photos$delimiter1$startQuery$delimiter2$limitQuery'; | ||||||
|     final response = await _client.get(Uri.parse(url)); |     final response = await _client.get(Uri.parse(url)); | ||||||
|     final photos = |     final photos = | ||||||
|         ListPhotoModel.fromJson({'photos': jsonDecode(response.body)}); |         ListPhotoModel.fromJson({'photos': jsonDecode(response.body)}); | ||||||
| @ -206,9 +206,7 @@ class PhotoApiDataSourceImpl extends PhotoRemoteDataSource { | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| > 1: Note that here we use `MiddlewareClient` from our http package. | > 1: You can create multiple implementations (one real and one mock for example). | ||||||
| 
 |  | ||||||
| > 2: You can create multiple implementations (one real and one mock for example). |  | ||||||
| 
 | 
 | ||||||
| And implement the repositories: | And implement the repositories: | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,20 +1,17 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP | // Copyright (C) 2024 WYATT GROUP | ||||||
| // Please see the AUTHORS file for details. | // Please see the AUTHORS file for details. | ||||||
| // | //  | ||||||
| // This program is free software: you can redistribute it and/or modify | // This program is free software: you can redistribute it and/or modify | ||||||
| // it under the terms of the GNU General Public License as published by | // it under the terms of the GNU General Public License as published by | ||||||
| // the Free Software Foundation, either version 3 of the License, or | // the Free Software Foundation, either version 3 of the License, or | ||||||
| // any later version. | // any later version. | ||||||
| // | //  | ||||||
| // This program is distributed in the hope that it will be useful, | // This program is distributed in the hope that it will be useful, | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
| // GNU General Public License for more details. | // GNU General Public License for more details. | ||||||
| // | //  | ||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| export 'middleware_context.dart'; | const String kDefaultApiUrl = 'https://jsonplaceholder.typicode.com/'; | ||||||
| export 'middleware_request.dart'; |  | ||||||
| export 'middleware_response.dart'; |  | ||||||
| export 'unfreezed_request.dart'; |  | ||||||
| @ -26,7 +26,6 @@ import 'package:architecture_example/domain/data_sources/local/favorite_local_da | |||||||
| import 'package:architecture_example/domain/data_sources/remote/album_remote_data_source.dart'; | import 'package:architecture_example/domain/data_sources/remote/album_remote_data_source.dart'; | ||||||
| import 'package:architecture_example/domain/data_sources/remote/photo_remote_data_source.dart'; | import 'package:architecture_example/domain/data_sources/remote/photo_remote_data_source.dart'; | ||||||
| import 'package:get_it/get_it.dart'; | import 'package:get_it/get_it.dart'; | ||||||
| import 'package:wyatt_http_client/wyatt_http_client.dart'; |  | ||||||
| 
 | 
 | ||||||
| final getIt = GetIt.I; | final getIt = GetIt.I; | ||||||
| 
 | 
 | ||||||
| @ -50,22 +49,11 @@ abstract class GetItInitializer { | |||||||
|       ..registerLazySingleton<FavoriteLocalDataSource>( |       ..registerLazySingleton<FavoriteLocalDataSource>( | ||||||
|         FavoriteHiveDataSource.new, |         FavoriteHiveDataSource.new, | ||||||
|       ) |       ) | ||||||
|       ..registerLazySingleton<MiddlewareClient>(() { |  | ||||||
|         final Pipeline pipeline = Pipeline() |  | ||||||
|           ..addMiddleware( |  | ||||||
|             const UriPrefixMiddleware( |  | ||||||
|               protocol: Protocols.https, |  | ||||||
|               authority: 'jsonplaceholder.typicode.com', |  | ||||||
|             ), |  | ||||||
|           ) |  | ||||||
|           ..addMiddleware(const BodyToJsonMiddleware()); |  | ||||||
|         return MiddlewareClient(pipeline: pipeline); |  | ||||||
|       }) |  | ||||||
|       ..registerLazySingleton<PhotoRemoteDataSource>( |       ..registerLazySingleton<PhotoRemoteDataSource>( | ||||||
|         () => PhotoApiDataSourceImpl(getIt()), |         PhotoApiDataSourceImpl.new, | ||||||
|       ) |       ) | ||||||
|       ..registerLazySingleton<AlbumRemoteDataSource>( |       ..registerLazySingleton<AlbumRemoteDataSource>( | ||||||
|         () => AlbumApiDataSourceImpl(getIt()), |         AlbumApiDataSourceImpl.new, | ||||||
|       ); |       ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,20 +16,25 @@ | |||||||
| 
 | 
 | ||||||
| import 'dart:convert'; | import 'dart:convert'; | ||||||
| 
 | 
 | ||||||
|  | import 'package:architecture_example/core/constants/constants.dart'; | ||||||
| import 'package:architecture_example/data/models/album_model.dart'; | import 'package:architecture_example/data/models/album_model.dart'; | ||||||
| import 'package:architecture_example/data/models/list_album_model.dart'; | import 'package:architecture_example/data/models/list_album_model.dart'; | ||||||
| import 'package:architecture_example/domain/data_sources/remote/album_remote_data_source.dart'; | import 'package:architecture_example/domain/data_sources/remote/album_remote_data_source.dart'; | ||||||
| import 'package:architecture_example/domain/entities/album.dart'; | import 'package:architecture_example/domain/entities/album.dart'; | ||||||
| import 'package:wyatt_http_client/wyatt_http_client.dart'; | import 'package:http/http.dart'; | ||||||
| import 'package:wyatt_type_utils/wyatt_type_utils.dart'; | import 'package:wyatt_type_utils/wyatt_type_utils.dart'; | ||||||
| 
 | 
 | ||||||
| class AlbumApiDataSourceImpl extends AlbumRemoteDataSource { | class AlbumApiDataSourceImpl extends AlbumRemoteDataSource { | ||||||
|   AlbumApiDataSourceImpl(this._client); |   AlbumApiDataSourceImpl({ | ||||||
|   final MiddlewareClient _client; |     Client? client, | ||||||
|  |   }) : _client = client ?? Client(); | ||||||
|  | 
 | ||||||
|  |   final Client _client; | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Future<Album> getAlbum(int id) async { |   Future<Album> getAlbum(int id) async { | ||||||
|     final response = await _client.get(Uri.parse('/albums/$id')); |     final response = await _client | ||||||
|  |         .get(Uri.parse('$kDefaultApiUrl/albums/$id')); | ||||||
|     final album = |     final album = | ||||||
|         AlbumModel.fromJson(jsonDecode(response.body) as Map<String, Object?>); |         AlbumModel.fromJson(jsonDecode(response.body) as Map<String, Object?>); | ||||||
|     return album; |     return album; | ||||||
| @ -43,7 +48,7 @@ class AlbumApiDataSourceImpl extends AlbumRemoteDataSource { | |||||||
|         (startQuery.isNotEmpty || limitQuery.isNotEmpty) ? '?' : ''; |         (startQuery.isNotEmpty || limitQuery.isNotEmpty) ? '?' : ''; | ||||||
|     final delimiter2 = |     final delimiter2 = | ||||||
|         (startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : ''; |         (startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : ''; | ||||||
|     final url = '/albums$delimiter1$startQuery$delimiter2$limitQuery'; |     final url = '$kDefaultApiUrl/albums$delimiter1$startQuery$delimiter2$limitQuery'; | ||||||
|     final response = await _client.get(Uri.parse(url)); |     final response = await _client.get(Uri.parse(url)); | ||||||
|     final albums = |     final albums = | ||||||
|         ListAlbumModel.fromJson({'albums': jsonDecode(response.body)}); |         ListAlbumModel.fromJson({'albums': jsonDecode(response.body)}); | ||||||
|  | |||||||
| @ -16,20 +16,24 @@ | |||||||
| 
 | 
 | ||||||
| import 'dart:convert'; | import 'dart:convert'; | ||||||
| 
 | 
 | ||||||
|  | import 'package:architecture_example/core/constants/constants.dart'; | ||||||
| import 'package:architecture_example/data/models/list_photo_model.dart'; | import 'package:architecture_example/data/models/list_photo_model.dart'; | ||||||
| import 'package:architecture_example/data/models/photo_model.dart'; | import 'package:architecture_example/data/models/photo_model.dart'; | ||||||
| import 'package:architecture_example/domain/data_sources/remote/photo_remote_data_source.dart'; | import 'package:architecture_example/domain/data_sources/remote/photo_remote_data_source.dart'; | ||||||
| import 'package:architecture_example/domain/entities/photo.dart'; | import 'package:architecture_example/domain/entities/photo.dart'; | ||||||
| import 'package:wyatt_http_client/wyatt_http_client.dart'; | import 'package:http/http.dart'; | ||||||
| import 'package:wyatt_type_utils/wyatt_type_utils.dart'; | import 'package:wyatt_type_utils/wyatt_type_utils.dart'; | ||||||
| 
 | 
 | ||||||
| class PhotoApiDataSourceImpl extends PhotoRemoteDataSource { | class PhotoApiDataSourceImpl extends PhotoRemoteDataSource { | ||||||
|   PhotoApiDataSourceImpl(this._client); |   PhotoApiDataSourceImpl({ | ||||||
|   final MiddlewareClient _client; |     Client? client, | ||||||
|  |   }) : _client = client ?? Client(); | ||||||
|  | 
 | ||||||
|  |   final Client _client; | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Future<Photo> getPhoto(int id) async { |   Future<Photo> getPhoto(int id) async { | ||||||
|     final response = await _client.get(Uri.parse('/photos/$id')); |     final response = await _client.get(Uri.parse('$kDefaultApiUrl/photos/$id')); | ||||||
|     final photo = |     final photo = | ||||||
|         PhotoModel.fromJson(jsonDecode(response.body) as Map<String, Object?>); |         PhotoModel.fromJson(jsonDecode(response.body) as Map<String, Object?>); | ||||||
|     return photo; |     return photo; | ||||||
| @ -43,7 +47,8 @@ class PhotoApiDataSourceImpl extends PhotoRemoteDataSource { | |||||||
|         (startQuery.isNotEmpty || limitQuery.isNotEmpty) ? '?' : ''; |         (startQuery.isNotEmpty || limitQuery.isNotEmpty) ? '?' : ''; | ||||||
|     final delimiter2 = |     final delimiter2 = | ||||||
|         (startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : ''; |         (startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : ''; | ||||||
|     final url = '/photos$delimiter1$startQuery$delimiter2$limitQuery'; |     final url = | ||||||
|  |         '$kDefaultApiUrl/photos$delimiter1$startQuery$delimiter2$limitQuery'; | ||||||
|     final response = await _client.get(Uri.parse(url)); |     final response = await _client.get(Uri.parse(url)); | ||||||
|     final photos = |     final photos = | ||||||
|         ListPhotoModel.fromJson({'photos': jsonDecode(response.body)}); |         ListPhotoModel.fromJson({'photos': jsonDecode(response.body)}); | ||||||
| @ -60,7 +65,8 @@ class PhotoApiDataSourceImpl extends PhotoRemoteDataSource { | |||||||
|     final limitQuery = limit.isNotNull ? '_limit=$limit' : ''; |     final limitQuery = limit.isNotNull ? '_limit=$limit' : ''; | ||||||
|     final delimiter = |     final delimiter = | ||||||
|         (startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : ''; |         (startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : ''; | ||||||
|     final url = '/photos?albumId=$albumId&$startQuery$delimiter$limitQuery'; |     final url = | ||||||
|  |         '$kDefaultApiUrl/photos?albumId=$albumId&$startQuery$delimiter$limitQuery'; | ||||||
|     final response = await _client.get(Uri.parse(url)); |     final response = await _client.get(Uri.parse(url)); | ||||||
|     final photos = |     final photos = | ||||||
|         ListPhotoModel.fromJson({'photos': jsonDecode(response.body)}); |         ListPhotoModel.fromJson({'photos': jsonDecode(response.body)}); | ||||||
|  | |||||||
| @ -45,12 +45,10 @@ dependencies: | |||||||
|   wyatt_bloc_helper: |   wyatt_bloc_helper: | ||||||
|     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
|     version: ^2.0.2 |     version: ^2.0.2 | ||||||
|   wyatt_http_client: |  | ||||||
|     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |  | ||||||
|     version: ^2.0.1 |  | ||||||
|   wyatt_type_utils: |   wyatt_type_utils: | ||||||
|     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub |     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub | ||||||
|     version: ^0.0.5 |     version: ^0.0.5 | ||||||
|  |   http: ^1.2.1 | ||||||
| 
 | 
 | ||||||
| dev_dependencies: | dev_dependencies: | ||||||
|   build_runner: ^2.3.2 |   build_runner: ^2.3.2 | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								packages/wyatt_http_client/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								packages/wyatt_http_client/.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1 +0,0 @@ | |||||||
| ../../.gitignore |  | ||||||
| @ -1 +0,0 @@ | |||||||
| ../../.pubignore |  | ||||||
| @ -1,24 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Copyright (C) 2022 WYATT GROUP |  | ||||||
|  * Please see the AUTHORS file for details. |  | ||||||
|  *  |  | ||||||
|  * This program is free software: you can redistribute it and/or modify |  | ||||||
|  * it under the terms of the GNU General Public License as published by |  | ||||||
|  * the Free Software Foundation, either version 3 of the License, or |  | ||||||
|  * any later version. |  | ||||||
|  *  |  | ||||||
|  * This program is distributed in the hope that it will be useful, |  | ||||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
|  * GNU General Public License for more details. |  | ||||||
|  *  |  | ||||||
|  * You should have received a copy of the GNU General Public License |  | ||||||
|  * along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| { |  | ||||||
|     "recommendations": [ |  | ||||||
|         "psioniq.psi-header", |  | ||||||
|         "blaugold.melos-code" |  | ||||||
|     ] |  | ||||||
| } |  | ||||||
							
								
								
									
										71
									
								
								packages/wyatt_http_client/.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								packages/wyatt_http_client/.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @ -1,71 +0,0 @@ | |||||||
| { |  | ||||||
|     "psi-header.changes-tracking": { |  | ||||||
|         "isActive": true |  | ||||||
|       }, |  | ||||||
|       "psi-header.config": { |  | ||||||
|         "blankLinesAfter": 1, |  | ||||||
|         "forceToTop": true |  | ||||||
|       }, |  | ||||||
|       "psi-header.lang-config": [ |  | ||||||
|         { |  | ||||||
|           "beforeHeader": [ |  | ||||||
|             "# -*- coding:utf-8 -*-", |  | ||||||
|             "#!/usr/bin/env python3" |  | ||||||
|           ], |  | ||||||
|           "begin": "###", |  | ||||||
|           "end": "###", |  | ||||||
|           "language": "python", |  | ||||||
|           "prefix": "# " |  | ||||||
|         }, |  | ||||||
|         { |  | ||||||
|           "beforeHeader": [ |  | ||||||
|             "#!/usr/bin/env sh", |  | ||||||
|             "" |  | ||||||
|           ], |  | ||||||
|           "language": "shellscript", |  | ||||||
|           "begin": "", |  | ||||||
|           "end": "", |  | ||||||
|           "prefix": "# " |  | ||||||
|         }, |  | ||||||
|         { |  | ||||||
|           "begin": "", |  | ||||||
|           "end": "", |  | ||||||
|           "language": "dart", |  | ||||||
|           "prefix": "// " |  | ||||||
|         }, |  | ||||||
|         { |  | ||||||
|           "begin": "", |  | ||||||
|           "end": "", |  | ||||||
|           "language": "yaml", |  | ||||||
|           "prefix": "# " |  | ||||||
|         }, |  | ||||||
|         { |  | ||||||
|           "begin": "<!--", |  | ||||||
|           "end": "-->", |  | ||||||
|           "language": "markdown", |  | ||||||
|         }, |  | ||||||
|       ], |  | ||||||
|       "psi-header.templates": [ |  | ||||||
|         { |  | ||||||
|           "language": "*", |  | ||||||
|           "template": [ |  | ||||||
|             "Copyright (C) <<year>> WYATT GROUP", |  | ||||||
|             "Please see the AUTHORS file for details.", |  | ||||||
|             "", |  | ||||||
|             "This program is free software: you can redistribute it and/or modify", |  | ||||||
|             "it under the terms of the GNU General Public License as published by", |  | ||||||
|             "the Free Software Foundation, either version 3 of the License, or", |  | ||||||
|             "any later version.", |  | ||||||
|             "", |  | ||||||
|             "This program is distributed in the hope that it will be useful,", |  | ||||||
|             "but WITHOUT ANY WARRANTY; without even the implied warranty of", |  | ||||||
|             "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", |  | ||||||
|             "GNU General Public License for more details.", |  | ||||||
|             "", |  | ||||||
|             "You should have received a copy of the GNU General Public License", |  | ||||||
|             "along with this program. If not, see <https://www.gnu.org/licenses/>." |  | ||||||
|           ], |  | ||||||
|         } |  | ||||||
|       ], |  | ||||||
|       "dart.runPubGetOnPubspecChanges": false, |  | ||||||
| } |  | ||||||
| @ -1 +0,0 @@ | |||||||
| ../../AUTHORS |  | ||||||
| @ -1,25 +0,0 @@ | |||||||
| ## 2.0.1 |  | ||||||
| 
 |  | ||||||
|  - **FIX**: apply dart fix --apply. |  | ||||||
| 
 |  | ||||||
| ## 2.0.0 |  | ||||||
| 
 |  | ||||||
| > Note: This release has breaking changes. |  | ||||||
| 
 |  | ||||||
|  - **DOCS**: add simple example. |  | ||||||
|  - **BREAKING** **REFACTOR**: fix cascade dart good practices + docs. |  | ||||||
| 
 |  | ||||||
| ## 1.2.0 |  | ||||||
| 
 |  | ||||||
|  - **FEAT**: add new middleware feature. |  | ||||||
|  - **FEAT**: implements doublelinked list for middlewares. |  | ||||||
|  - **FEAT**: [WIP] implements middleware system. |  | ||||||
|  - **FEAT**: [WIP] work on middleware feature. |  | ||||||
| 
 |  | ||||||
| ## 1.1.0 |  | ||||||
| 
 |  | ||||||
|  - **FEAT**: add oauth2 refresh token client. |  | ||||||
| 
 |  | ||||||
| ## 1.0.0 |  | ||||||
| 
 |  | ||||||
| - Initial version. |  | ||||||
| @ -1 +0,0 @@ | |||||||
| ../../LICENSE |  | ||||||
| @ -1,182 +0,0 @@ | |||||||
| <!-- |  | ||||||
|  * Copyright (C) 2022 WYATT GROUP |  | ||||||
|  * Please see the AUTHORS file for details. |  | ||||||
| 
 |  | ||||||
|  * This program is free software: you can redistribute it and/or modify |  | ||||||
|  * it under the terms of the GNU General Public License as published by |  | ||||||
|  * the Free Software Foundation, either version 3 of the License, or |  | ||||||
|  * any later version. |  | ||||||
| 
 |  | ||||||
|  * This program is distributed in the hope that it will be useful,  |  | ||||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
|  * GNU General Public License for more details. |  | ||||||
| 
 |  | ||||||
|  * You should have received a copy of the GNU General Public License |  | ||||||
|  * along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| --> |  | ||||||
| 
 |  | ||||||
| # HTTP Client |  | ||||||
| 
 |  | ||||||
| <p align="left"> |  | ||||||
|   <a href="https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_analysis"><img src="https://img.shields.io/badge/Style-Wyatt%20Analysis-blue.svg?style=flat-square" alt="Style: Wyatt Analysis" /></a> |  | ||||||
|   <img src="https://img.shields.io/badge/SDK-Dart%20%7C%20Flutter-blue?style=flat-square" alt="SDK: Dart & Flutter" /> |  | ||||||
| </p> |  | ||||||
| 
 |  | ||||||
| HTTP Client for Dart with Middlewares ! |  | ||||||
| 
 |  | ||||||
| ## Getting started |  | ||||||
| 
 |  | ||||||
| Simply add wyatt_http_client in pubspec.yaml, then |  | ||||||
| 
 |  | ||||||
| ```dart |  | ||||||
| import 'package:wyatt_http_client/wyatt_http_client.dart'; |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## Usage |  | ||||||
| 
 |  | ||||||
| Firstly you have to understand **Middleware** and **Pipeline** concepts. |  | ||||||
| 
 |  | ||||||
| In `wyatt_http_client` a middleware is an object where requests and responses  |  | ||||||
| pass through. And a pipeline is basicaly a list of middlewares. |  | ||||||
| 
 |  | ||||||
| In a pipeline with middlewares A and B, if request pass through A, then B,  |  | ||||||
| the response will pass through B then A. |  | ||||||
| 
 |  | ||||||
| > You can `print(pipeline)` to get full process order of a pipeline. |  | ||||||
| 
 |  | ||||||
| For example, if you want to log every request, and simplify an url you can use provided `SimpleLogger` and `UriPrefix` . |  | ||||||
| 
 |  | ||||||
| ```dart |  | ||||||
| // Create the Pipeline |  | ||||||
| final Pipeline pipeline = Pipeline() |  | ||||||
|     ..addMiddleware( |  | ||||||
|         const UriPrefixMiddleware( |  | ||||||
|             protocol: Protocols.http, |  | ||||||
|             authority: 'localhost:80', |  | ||||||
|         ), |  | ||||||
|     ) |  | ||||||
|     ..addMiddleware(const SimpleLoggerMiddleware()); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| Then if you print the pipeline,  |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| [Req] -> UriPrefix -> SimpleLogger |  | ||||||
| [Res] -> SimpleLogger |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| > The `response` doesn't pass through `UriPrefix` because it's an `OnRequestMiddleware` only. |  | ||||||
| 
 |  | ||||||
| And you can create a client. |  | ||||||
| 
 |  | ||||||
| ```dart |  | ||||||
| final client = MiddlewareClient(pipeline: pipeline); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| At this point you can use `client` like every Client from `package:http/http.dart` . |  | ||||||
| 
 |  | ||||||
| ## Recipes |  | ||||||
| 
 |  | ||||||
| ### Rest API with URL Authentication |  | ||||||
| 
 |  | ||||||
| Let's build a client for a REST API where the (bad) authentication is through the URL. |  | ||||||
| We need some middlewares: |  | ||||||
| 
 |  | ||||||
| * SimpleLogger, to log every request and response (useful for debug). |  | ||||||
| * BodyToJson, to automaticaly transform Map object to JSON. |  | ||||||
| * UriPrefix, to simplify the build of an API Object (save protocol and API prefix). |  | ||||||
| * UnsafeAuth, to use url based authentication. |  | ||||||
| 
 |  | ||||||
| Let's start by creating the Pipeline: |  | ||||||
| 
 |  | ||||||
| ```dart |  | ||||||
| final Pipeline pipeline = Pipeline() |  | ||||||
|     ..addMiddleware( |  | ||||||
|         const UriPrefixMiddleware( |  | ||||||
|             protocol: Protocols.http, |  | ||||||
|             authority: 'localhost:80', |  | ||||||
|         ), |  | ||||||
|     ) |  | ||||||
|     ..addMiddleware(const BodyToJsonMiddleware()) |  | ||||||
|     ..addMiddleware( |  | ||||||
|         const UnsafeAuthMiddleware( |  | ||||||
|             username: 'wyatt', |  | ||||||
|             password: 'motdepasse', |  | ||||||
|         ), |  | ||||||
|     ) |  | ||||||
|     ..addMiddleware(SimpleLoggerMiddleware()); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| Then simply create a client and make a call. |  | ||||||
| 
 |  | ||||||
| ```dart |  | ||||||
| final client = MiddlewareClient(pipeline: pipeline); |  | ||||||
| 
 |  | ||||||
| await client.get(Uri.parse('/protected')); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| > Here it make a `GET` call on `http://localhost:80/protected?username=wyatt&password=motdepasse` |  | ||||||
| 
 |  | ||||||
| And voilà. |  | ||||||
| 
 |  | ||||||
| ### Rest API with Oauth2 |  | ||||||
| 
 |  | ||||||
| So now we want a real authentication. |  | ||||||
| 
 |  | ||||||
| ```dart |  | ||||||
| final Pipeline pipeline = Pipeline() |  | ||||||
|     ..addMiddleware( |  | ||||||
|         const UriPrefixMiddleware( |  | ||||||
|             protocol: Protocols.http, |  | ||||||
|             authority: 'localhost:80', |  | ||||||
|         ), |  | ||||||
|     ) |  | ||||||
|     ..addMiddleware(const BodyToJsonMiddleware()) |  | ||||||
|     ..addMiddleware( |  | ||||||
|         RefreshTokenAuthMiddleware( |  | ||||||
|             authorizationEndpoint: '/auth/sign-in', |  | ||||||
|             tokenEndpoint: '/auth/refresh', |  | ||||||
|             accessTokenParser: (body) => body['access_token']! as String, |  | ||||||
|             refreshTokenParser: (body) => body['refresh_token']! as String, |  | ||||||
|             unauthorized: HttpStatus.forbidden, |  | ||||||
|         ), |  | ||||||
|     ) |  | ||||||
|     ..addMiddleware(const SimpleLoggerMiddleware()); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| > Here we just change `UnsafeAuthMiddleware` by `RefreshTokenAuthMiddleware` and the whole app while adapt to a new authentication system. |  | ||||||
| 
 |  | ||||||
| ### Create a new Middleware |  | ||||||
| 
 |  | ||||||
| You can create your own middleware by implementing `Middleware` class, and use mixins to add `OnRequest` and/or `OnResponse` methods. |  | ||||||
| 
 |  | ||||||
| ```dart |  | ||||||
| class SimpleLoggerMiddleware  |  | ||||||
|     with OnRequestMiddleware, OnResponseMiddleware  |  | ||||||
|     implements Middleware { |  | ||||||
|      |  | ||||||
|   const SimpleLoggerMiddleware(); |  | ||||||
|    |  | ||||||
|   @override |  | ||||||
|   String getName() => 'SimpleLogger'; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareRequest> onRequest( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareRequest request, |  | ||||||
|   ) async { |  | ||||||
|     print('${getName()}::OnRequest'); |  | ||||||
|     return request; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareResponse> onResponse( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareResponse response, |  | ||||||
|   ) async { |  | ||||||
|     print('${getName()}::OnResponse'); |  | ||||||
|     return response; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| @ -1 +0,0 @@ | |||||||
| include: package:wyatt_analysis/analysis_options.yaml |  | ||||||
| @ -1,78 +0,0 @@ | |||||||
| // Copyright (C) 2023 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/wyatt_http_client.dart'; |  | ||||||
| 
 |  | ||||||
| Future<void> testSimpleGet() async { |  | ||||||
|   print('testSimpleGet'); |  | ||||||
|   final pipeline = Pipeline() |  | ||||||
|     ..addMiddleware(const BodyToJsonMiddleware()) |  | ||||||
|     ..addMiddleware(const SimpleLoggerMiddleware()); |  | ||||||
| 
 |  | ||||||
|   final client = MiddlewareClient(pipeline: pipeline); |  | ||||||
| 
 |  | ||||||
|   final response = await client |  | ||||||
|       .get(Uri.parse('https://jsonplaceholder.typicode.com/todos/1')); |  | ||||||
|   print(response.body); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Future<void> testUriPrefix() async { |  | ||||||
|   print('testUriPrefix'); |  | ||||||
|   final pipeline = Pipeline() |  | ||||||
|     ..addMiddleware( |  | ||||||
|       const UriPrefixMiddleware( |  | ||||||
|         protocol: Protocols.https, |  | ||||||
|         authority: 'jsonplaceholder.typicode.com', |  | ||||||
|       ), |  | ||||||
|     ) |  | ||||||
|     ..addMiddleware(const BodyToJsonMiddleware()) |  | ||||||
|     ..addMiddleware(const SimpleLoggerMiddleware()); |  | ||||||
| 
 |  | ||||||
|   final client = MiddlewareClient(pipeline: pipeline); |  | ||||||
| 
 |  | ||||||
|   final response = await client.get(Uri.parse('/todos/1')); |  | ||||||
|   print(response.body); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Future<void> testBasicAuth() async { |  | ||||||
|   print('testBasicAuth'); |  | ||||||
|   final pipeline = Pipeline() |  | ||||||
|     ..addMiddleware( |  | ||||||
|       const BasicAuthMiddleware( |  | ||||||
|         username: 'guest', |  | ||||||
|         password: 'guest', |  | ||||||
|       ), |  | ||||||
|     ) |  | ||||||
|     ..addMiddleware(const BodyToJsonMiddleware()) |  | ||||||
|     ..addMiddleware(const SimpleLoggerMiddleware()); |  | ||||||
| 
 |  | ||||||
|   final client = MiddlewareClient(pipeline: pipeline); |  | ||||||
| 
 |  | ||||||
|   final response = |  | ||||||
|       await client.get(Uri.parse('https://jigsaw.w3.org/HTTP/Basic/')); |  | ||||||
| 
 |  | ||||||
|   if (HttpStatus.from(response.statusCode).isSuccess()) { |  | ||||||
|     print("🎉 You're in!"); |  | ||||||
|   } else { |  | ||||||
|     print("⭕️ Nope, you're not in."); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void main(List<String> args) { |  | ||||||
|   testSimpleGet(); |  | ||||||
|   testUriPrefix(); |  | ||||||
|   testBasicAuth(); |  | ||||||
| } |  | ||||||
| @ -1,48 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_context.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_response.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template middleware} |  | ||||||
| /// A middleware is a class that can intercept requests and responses |  | ||||||
| /// and modify them before they are sent to the server or before they |  | ||||||
| /// are returned to the client. |  | ||||||
| /// {@endtemplate} |  | ||||||
| abstract class Middleware { |  | ||||||
|   /// {@macro middleware} |  | ||||||
|   const Middleware(); |  | ||||||
| 
 |  | ||||||
|   /// The name of the middleware. |  | ||||||
|   String getName(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| mixin OnRequestMiddleware { |  | ||||||
|   /// Performs an action before the request is sent to the server. |  | ||||||
|   Future<MiddlewareRequest> onRequest( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareRequest request, |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| mixin OnResponseMiddleware { |  | ||||||
|   /// Performs an action before the response is returned to the client. |  | ||||||
|   Future<MiddlewareResponse> onResponse( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareResponse response, |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
| @ -1,134 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'dart:convert'; |  | ||||||
| 
 |  | ||||||
| import 'package:http/http.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_context.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_response.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/unfreezed_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/pipeline.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/http_methods.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template middleware_client} |  | ||||||
| /// A custom [Client] implementation that allows you to intercept requests |  | ||||||
| /// and responses and modify them before they are sent to the server or |  | ||||||
| /// before they are returned to the client. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class MiddlewareClient extends BaseClient { |  | ||||||
|   /// {@macro middleware_client} |  | ||||||
|   MiddlewareClient({ |  | ||||||
|     Pipeline? pipeline, |  | ||||||
|     Client? inner, |  | ||||||
|   })  : pipeline = pipeline ?? Pipeline(), |  | ||||||
|         inner = inner ?? Client(); |  | ||||||
| 
 |  | ||||||
|   /// The [Client] that will be used to send requests. |  | ||||||
|   final Client inner; |  | ||||||
| 
 |  | ||||||
|   /// The [Pipeline] that will be used to intercept requests and responses. |  | ||||||
|   final Pipeline pipeline; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Response> head(Uri url, {Map<String, String>? headers}) => |  | ||||||
|       _sendUnstreamed(HttpMethods.head.method, url, headers); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Response> get(Uri url, {Map<String, String>? headers}) => |  | ||||||
|       _sendUnstreamed(HttpMethods.get.method, url, headers); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Response> post( |  | ||||||
|     Uri url, { |  | ||||||
|     Map<String, String>? headers, |  | ||||||
|     Object? body, |  | ||||||
|     Encoding? encoding, |  | ||||||
|   }) => |  | ||||||
|       _sendUnstreamed(HttpMethods.post.method, url, headers, body, encoding); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Response> put( |  | ||||||
|     Uri url, { |  | ||||||
|     Map<String, String>? headers, |  | ||||||
|     Object? body, |  | ||||||
|     Encoding? encoding, |  | ||||||
|   }) => |  | ||||||
|       _sendUnstreamed(HttpMethods.put.method, url, headers, body, encoding); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Response> patch( |  | ||||||
|     Uri url, { |  | ||||||
|     Map<String, String>? headers, |  | ||||||
|     Object? body, |  | ||||||
|     Encoding? encoding, |  | ||||||
|   }) => |  | ||||||
|       _sendUnstreamed(HttpMethods.patch.method, url, headers, body, encoding); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<Response> delete( |  | ||||||
|     Uri url, { |  | ||||||
|     Map<String, String>? headers, |  | ||||||
|     Object? body, |  | ||||||
|     Encoding? encoding, |  | ||||||
|   }) => |  | ||||||
|       _sendUnstreamed(HttpMethods.delete.method, url, headers, body, encoding); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<StreamedResponse> send(BaseRequest request) => inner.send(request); |  | ||||||
| 
 |  | ||||||
|   Future<Response> _sendUnstreamed( |  | ||||||
|     String method, |  | ||||||
|     Uri url, |  | ||||||
|     Map<String, String>? headers, [ |  | ||||||
|     Object? body, |  | ||||||
|     Encoding? encoding, |  | ||||||
|   ]) async { |  | ||||||
|     final originalRequest = MiddlewareRequest( |  | ||||||
|       unfreezedRequest: UnfreezedRequest( |  | ||||||
|         method: method, |  | ||||||
|         url: url, |  | ||||||
|         headers: headers, |  | ||||||
|         body: body, |  | ||||||
|         encoding: encoding, |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|     final requestContext = MiddlewareContext( |  | ||||||
|       pipeline: pipeline, |  | ||||||
|       client: this, |  | ||||||
|       originalRequest: originalRequest, |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     final modifiedRequest = await pipeline.onRequest( |  | ||||||
|       requestContext, |  | ||||||
|       originalRequest.copyWith(), |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     final originalResponse = MiddlewareResponse( |  | ||||||
|       httpResponse: await Response.fromStream( |  | ||||||
|         await send(modifiedRequest.request), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     final responseContext = |  | ||||||
|         requestContext.copyWith(originalResponse: originalResponse); |  | ||||||
| 
 |  | ||||||
|     final modifiedResponse = |  | ||||||
|         await pipeline.onResponse(responseContext, originalResponse.copyWith()); |  | ||||||
| 
 |  | ||||||
|     return modifiedResponse.httpResponse as Response; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,65 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'dart:convert'; |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/middleware.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_context.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/authentication_methods.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/header_keys.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template basic_auth_middleware} |  | ||||||
| /// A middleware that adds basic authentication to the request. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class BasicAuthMiddleware with OnRequestMiddleware implements Middleware { |  | ||||||
|   /// {@macro basic_auth_middleware} |  | ||||||
|   const BasicAuthMiddleware({ |  | ||||||
|     this.username, |  | ||||||
|     this.password, |  | ||||||
|     this.authenticationHeader = HeaderKeys.authorization, |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   /// The username to use for authentication. |  | ||||||
|   final String? username; |  | ||||||
| 
 |  | ||||||
|   /// The password to use for authentication. |  | ||||||
|   final String? password; |  | ||||||
| 
 |  | ||||||
|   /// The header to use for authentication. |  | ||||||
|   final String authenticationHeader; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String getName() => 'BasicAuth'; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareRequest> onRequest( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareRequest request, |  | ||||||
|   ) async { |  | ||||||
|     if (username == null || password == null) { |  | ||||||
|       return request; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     final mutation = { |  | ||||||
|       authenticationHeader: '${AuthenticationMethods.basic} ' |  | ||||||
|           '${base64Encode(utf8.encode('$username:$password'))}', |  | ||||||
|     }; |  | ||||||
|     final Map<String, String> headers = request.headers..addAll(mutation); |  | ||||||
|     request.modifyRequest(request.unfreezedRequest.copyWith(headers: headers)); |  | ||||||
|     return request; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,50 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'dart:convert'; |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/middleware.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_context.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template body_to_json_middleware} |  | ||||||
| /// A middleware that transforms the body in json if it's a [Map]. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class BodyToJsonMiddleware with OnRequestMiddleware implements Middleware { |  | ||||||
|   /// {@macro body_to_json_middleware} |  | ||||||
|   const BodyToJsonMiddleware(); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String getName() => 'BodyToJson'; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareRequest> onRequest( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareRequest request, |  | ||||||
|   ) async { |  | ||||||
|     final mutation = { |  | ||||||
|       'content-type': 'application/json; charset=utf-8', |  | ||||||
|     }; |  | ||||||
|     if (request.body is Map) { |  | ||||||
|       final Map<String, String> headers = request.headers..addAll(mutation); |  | ||||||
|       request.modifyRequest( |  | ||||||
|         request.unfreezedRequest |  | ||||||
|             .copyWith(headers: headers, body: jsonEncode(request.body)), |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|     return request; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,28 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/middleware.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template default_middleware} |  | ||||||
| /// A default middleware that does nothing. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class DefaultMiddleware implements Middleware { |  | ||||||
|   /// {@macro default_middleware} |  | ||||||
|   const DefaultMiddleware(); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String getName() => 'DefaultMiddleware'; |  | ||||||
| } |  | ||||||
| @ -1,87 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/middleware.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_context.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_response.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/digest_auth.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/header_keys.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/http_status.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template digest_auth_middleware} |  | ||||||
| /// A middleware that handles digest authentication. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class DigestAuthMiddleware |  | ||||||
|     with OnRequestMiddleware, OnResponseMiddleware |  | ||||||
|     implements Middleware { |  | ||||||
|   /// {@macro digest_auth_middleware} |  | ||||||
|   DigestAuthMiddleware({ |  | ||||||
|     required this.username, |  | ||||||
|     required this.password, |  | ||||||
|     this.authenticationHeader = HeaderKeys.authorization, |  | ||||||
|     this.wwwAuthenticateHeader = HeaderKeys.wwwAuthenticate, |  | ||||||
|     this.unauthorized = HttpStatus.unauthorized, |  | ||||||
|   }) : _digestAuth = DigestAuth(username, password); |  | ||||||
|   final String username; |  | ||||||
|   final String password; |  | ||||||
|   final DigestAuth _digestAuth; |  | ||||||
|   final String authenticationHeader; |  | ||||||
|   final String wwwAuthenticateHeader; |  | ||||||
|   final HttpStatus unauthorized; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String getName() => 'DigestAuth'; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareRequest> onRequest( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareRequest request, |  | ||||||
|   ) async { |  | ||||||
|     if (_digestAuth.isReady()) { |  | ||||||
|       final mutation = { |  | ||||||
|         authenticationHeader: _digestAuth.getAuthString( |  | ||||||
|           request.method, |  | ||||||
|           request.url, |  | ||||||
|         ), |  | ||||||
|       }; |  | ||||||
|       final Map<String, String> headers = request.headers..addAll(mutation); |  | ||||||
|       request |  | ||||||
|           .modifyRequest(request.unfreezedRequest.copyWith(headers: headers)); |  | ||||||
|     } |  | ||||||
|     return request; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareResponse> onResponse( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareResponse response, |  | ||||||
|   ) async { |  | ||||||
|     if (response.status == unauthorized) { |  | ||||||
|       final authInfo = |  | ||||||
|           response.headers[HeaderKeys.wwwAuthenticate.toLowerCase()]; |  | ||||||
|       _digestAuth.initFromAuthenticateHeader(authInfo); |  | ||||||
| 
 |  | ||||||
|       final MiddlewareRequest? newRequest = context.lastRequest?.copyWith(); |  | ||||||
| 
 |  | ||||||
|       if (newRequest != null) { |  | ||||||
|         final newResponse = await context.client.send(newRequest.request); |  | ||||||
|         return MiddlewareResponse(httpResponse: newResponse); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return response; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,26 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| // All built-in middlewares |  | ||||||
| 
 |  | ||||||
| export 'basic_auth_middleware.dart'; |  | ||||||
| export 'body_to_json_middleware.dart'; |  | ||||||
| export 'default_middleware.dart'; |  | ||||||
| export 'digest_auth_middleware.dart'; |  | ||||||
| export 'refresh_token_auth_middleware.dart'; |  | ||||||
| export 'simple_logger_middleware.dart'; |  | ||||||
| export 'unsafe_auth_middleware.dart'; |  | ||||||
| export 'uri_prefix_middleware.dart'; |  | ||||||
| @ -1,184 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'dart:convert'; |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/middleware.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/middleware_client.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_context.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_response.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/authentication_methods.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/delay.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/header_keys.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/http_status.dart'; |  | ||||||
| 
 |  | ||||||
| typedef TokenParser = String Function(Map<String, dynamic>); |  | ||||||
| 
 |  | ||||||
| /// {@template refresh_token_auth_middleware} |  | ||||||
| /// A middleware that refreshes the access token when it expires. |  | ||||||
| /// This middleware is useful for OAuth2. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class RefreshTokenAuthMiddleware |  | ||||||
|     with OnRequestMiddleware, OnResponseMiddleware |  | ||||||
|     implements Middleware { |  | ||||||
|   /// {@macro refresh_token_auth_middleware} |  | ||||||
|   RefreshTokenAuthMiddleware({ |  | ||||||
|     required this.authorizationEndpoint, |  | ||||||
|     required this.tokenEndpoint, |  | ||||||
|     required this.accessTokenParser, |  | ||||||
|     required this.refreshTokenParser, |  | ||||||
|     this.authenticationHeader = HeaderKeys.authorization, |  | ||||||
|     this.authenticationMethod = AuthenticationMethods.bearer, |  | ||||||
|     this.unauthorized = HttpStatus.unauthorized, |  | ||||||
|     this.maxAttempts = 8, |  | ||||||
|   }); |  | ||||||
|   final String authorizationEndpoint; |  | ||||||
|   final String tokenEndpoint; |  | ||||||
| 
 |  | ||||||
|   String? accessToken; |  | ||||||
|   final TokenParser accessTokenParser; |  | ||||||
|   String? refreshToken; |  | ||||||
|   final TokenParser refreshTokenParser; |  | ||||||
| 
 |  | ||||||
|   final String authenticationHeader; |  | ||||||
|   final String authenticationMethod; |  | ||||||
|   final HttpStatus unauthorized; |  | ||||||
|   final int maxAttempts; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String getName() => 'RefreshToken'; |  | ||||||
| 
 |  | ||||||
|   Future<MiddlewareRequest?> refresh(MiddlewareContext context) async { |  | ||||||
|     final subPipeline = context.pipeline.sub(this); |  | ||||||
|     final httpClient = MiddlewareClient( |  | ||||||
|       pipeline: subPipeline, |  | ||||||
|       inner: context.client.inner, |  | ||||||
|     ); |  | ||||||
|     final headers = { |  | ||||||
|       authenticationHeader: '$authenticationMethod $refreshToken', |  | ||||||
|     }; |  | ||||||
|     final response = MiddlewareResponse( |  | ||||||
|       httpResponse: await httpClient.get( |  | ||||||
|         Uri.parse(tokenEndpoint), |  | ||||||
|         headers: headers, |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|     if (response.status.isSuccess()) { |  | ||||||
|       final body = jsonDecode(response.body) as Map<String, dynamic>; |  | ||||||
|       accessToken = accessTokenParser(body); |  | ||||||
| 
 |  | ||||||
|       // Then modify current request with accessToken |  | ||||||
|       final mutation = { |  | ||||||
|         authenticationHeader: '$authenticationMethod $accessToken', |  | ||||||
|       }; |  | ||||||
|       final Map<String, String>? headers = context.lastRequest?.headers |  | ||||||
|         ?..addAll(mutation); |  | ||||||
|       final newRequest = context.lastRequest?.copyWith( |  | ||||||
|         unfreezedRequest: |  | ||||||
|             context.lastRequest?.unfreezedRequest.copyWith(headers: headers), |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       return newRequest; |  | ||||||
|     } |  | ||||||
|     return null; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   Future<MiddlewareRequest?> retry(MiddlewareContext context) async { |  | ||||||
|     // Retry |  | ||||||
|     int attempt = 1; |  | ||||||
|     while (attempt <= maxAttempts) { |  | ||||||
|       // Delayed before retry |  | ||||||
|       await Future<void>.delayed(Delay.getRetryDelay(attempt)); |  | ||||||
| 
 |  | ||||||
|       final newRequest = await refresh(context); |  | ||||||
|       if (newRequest != null) { |  | ||||||
|         return newRequest; |  | ||||||
|       } |  | ||||||
|       attempt++; |  | ||||||
|     } |  | ||||||
|     return null; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareRequest> onRequest( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareRequest request, |  | ||||||
|   ) async { |  | ||||||
|     // Check if it is authorization |  | ||||||
|     if (context.originalRequest?.url == Uri.parse(authorizationEndpoint)) { |  | ||||||
|       return request; |  | ||||||
|     } |  | ||||||
|     // Check if it is refresh |  | ||||||
|     if (context.originalRequest?.url == Uri.parse(tokenEndpoint)) { |  | ||||||
|       return request; |  | ||||||
|     } |  | ||||||
|     // If AccessToken not null then return request with authorization header |  | ||||||
|     if (accessToken != null) { |  | ||||||
|       final mutation = { |  | ||||||
|         authenticationHeader: '$authenticationMethod $accessToken', |  | ||||||
|       }; |  | ||||||
|       final Map<String, String> headers = request.headers..addAll(mutation); |  | ||||||
|       request |  | ||||||
|           .modifyRequest(request.unfreezedRequest.copyWith(headers: headers)); |  | ||||||
|       return request; |  | ||||||
|     } |  | ||||||
|     // If AccessToken is null BUT there is a refreshToken, then try refreshing |  | ||||||
|     if (refreshToken != null) { |  | ||||||
|       MiddlewareRequest? newRequest = await refresh(context); |  | ||||||
|       newRequest ??= await retry(context); |  | ||||||
|       return newRequest ?? request; |  | ||||||
|     } |  | ||||||
|     // Pass |  | ||||||
|     return request; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareResponse> onResponse( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareResponse response, |  | ||||||
|   ) async { |  | ||||||
|     // Check if it is authorization |  | ||||||
|     if (context.originalRequest?.url == Uri.parse(authorizationEndpoint)) { |  | ||||||
|       // If success, then update tokens |  | ||||||
|       if (response.status.isSuccess()) { |  | ||||||
|         final body = jsonDecode(response.body) as Map<String, dynamic>; |  | ||||||
|         final accessToken = accessTokenParser(body); |  | ||||||
|         final refreshToken = refreshTokenParser(body); |  | ||||||
| 
 |  | ||||||
|         if (accessToken.isNotEmpty) { |  | ||||||
|           this.accessToken = accessToken; |  | ||||||
|         } |  | ||||||
|         if (refreshToken.isNotEmpty) { |  | ||||||
|           this.refreshToken = refreshToken; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (response.status == unauthorized) { |  | ||||||
|       // Refresh |  | ||||||
|       MiddlewareRequest? newRequest = await refresh(context); |  | ||||||
|       newRequest ??= await retry(context); |  | ||||||
| 
 |  | ||||||
|       if (newRequest != null) { |  | ||||||
|         return response.copyWith( |  | ||||||
|           httpResponse: await context.client.send(newRequest.request), |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return response; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,72 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/middleware.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_context.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_response.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template simple_logger_middleware} |  | ||||||
| /// A simple logger middleware that logs the request and response. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class SimpleLoggerMiddleware |  | ||||||
|     with OnRequestMiddleware, OnResponseMiddleware |  | ||||||
|     implements Middleware { |  | ||||||
|   /// {@macro simple_logger_middleware} |  | ||||||
|   const SimpleLoggerMiddleware(); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String getName() => 'SimpleLogger'; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareRequest> onRequest( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareRequest request, |  | ||||||
|   ) async { |  | ||||||
|     final log = StringBuffer() |  | ||||||
|       ..writeln('${getName()}::OnRequest') |  | ||||||
|       ..writeln('>> ${request.method} ${request.url}'); |  | ||||||
|     if (request.headers.isNotEmpty) { |  | ||||||
|       log.writeln('>> Headers:'); |  | ||||||
|       request.headers.forEach((key, value) { |  | ||||||
|         log.writeln('>>   $key: $value'); |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|     if (request.encodedBody.isNotEmpty) { |  | ||||||
|       log |  | ||||||
|         ..writeln('>> Body:') |  | ||||||
|         ..writeln(request.encodedBody); |  | ||||||
|     } |  | ||||||
|     print(log); |  | ||||||
| 
 |  | ||||||
|     return request; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareResponse> onResponse( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareResponse response, |  | ||||||
|   ) async { |  | ||||||
|     final log = StringBuffer() |  | ||||||
|       ..writeln('${getName()}::OnResponse') |  | ||||||
|       ..writeln('>> Status: ${response.status.name.toUpperCase()}') |  | ||||||
|       ..writeln('>> Length: ${response.contentLength ?? '0'} bytes'); |  | ||||||
| 
 |  | ||||||
|     print(log); |  | ||||||
| 
 |  | ||||||
|     return response; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,56 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/middleware.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_context.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/convert.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template unsafe_auth_middleware} |  | ||||||
| /// A middleware that appends the username and password to the URL. |  | ||||||
| /// |  | ||||||
| /// This is not recommended to use in production. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class UnsafeAuthMiddleware with OnRequestMiddleware implements Middleware { |  | ||||||
|   const UnsafeAuthMiddleware({ |  | ||||||
|     this.username, |  | ||||||
|     this.password, |  | ||||||
|     this.usernameField = 'username', |  | ||||||
|     this.passwordField = 'password', |  | ||||||
|   }); |  | ||||||
|   final String? username; |  | ||||||
|   final String? password; |  | ||||||
| 
 |  | ||||||
|   final String usernameField; |  | ||||||
|   final String passwordField; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String getName() => 'UnsafeAuth'; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareRequest> onRequest( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareRequest request, |  | ||||||
|   ) async { |  | ||||||
|     if (username == null || password == null) { |  | ||||||
|       return request; |  | ||||||
|     } |  | ||||||
|     final Uri uri = |  | ||||||
|         request.url + '?$usernameField=$username&$passwordField=$password'; |  | ||||||
|     request.modifyRequest(request.unfreezedRequest.copyWith(url: uri)); |  | ||||||
|     return request; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,50 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/middleware.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_context.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/protocols.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template uri_prefix_middleware} |  | ||||||
| /// A middleware that adds a prefix to the request's URI. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class UriPrefixMiddleware with OnRequestMiddleware implements Middleware { |  | ||||||
|   /// {@macro uri_prefix_middleware} |  | ||||||
|   const UriPrefixMiddleware({ |  | ||||||
|     required this.protocol, |  | ||||||
|     required this.authority, |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   /// The protocol of the prefix. |  | ||||||
|   final Protocols protocol; |  | ||||||
| 
 |  | ||||||
|   /// The authority of the prefix. |  | ||||||
|   final String? authority; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String getName() => 'UriPrefix'; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Future<MiddlewareRequest> onRequest( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareRequest request, |  | ||||||
|   ) async { |  | ||||||
|     final Uri uri = Uri.parse('${protocol.scheme}$authority${request.url}'); |  | ||||||
|     request.modifyRequest(request.unfreezedRequest.copyWith(url: uri)); |  | ||||||
|     return request; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,78 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/middleware_client.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_response.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/pipeline.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template middleware_context} |  | ||||||
| /// A class that contains the context of the middleware. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class MiddlewareContext { |  | ||||||
|   /// {@macro middleware_context} |  | ||||||
|   const MiddlewareContext({ |  | ||||||
|     required this.pipeline, |  | ||||||
|     required this.client, |  | ||||||
|     this.originalRequest, |  | ||||||
|     this.lastRequest, |  | ||||||
|     this.originalResponse, |  | ||||||
|     this.lastResponse, |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   /// The pipeline that the middleware is in. |  | ||||||
|   final Pipeline pipeline; |  | ||||||
| 
 |  | ||||||
|   /// The client that the middleware is in. |  | ||||||
|   final MiddlewareClient client; |  | ||||||
| 
 |  | ||||||
|   /// The original request that the middleware is in. |  | ||||||
|   final MiddlewareRequest? originalRequest; |  | ||||||
| 
 |  | ||||||
|   /// The last request that the middleware is in. |  | ||||||
|   final MiddlewareRequest? lastRequest; |  | ||||||
| 
 |  | ||||||
|   /// The original response that the middleware is in. |  | ||||||
|   final MiddlewareResponse? originalResponse; |  | ||||||
| 
 |  | ||||||
|   /// The last response that the middleware is in. |  | ||||||
|   final MiddlewareResponse? lastResponse; |  | ||||||
| 
 |  | ||||||
|   /// Create a copy of this [MiddlewareContext] with the given fields replaced |  | ||||||
|   /// with the new values. |  | ||||||
|   MiddlewareContext copyWith({ |  | ||||||
|     Pipeline? pipeline, |  | ||||||
|     MiddlewareClient? client, |  | ||||||
|     MiddlewareRequest? originalRequest, |  | ||||||
|     MiddlewareRequest? lastRequest, |  | ||||||
|     MiddlewareResponse? originalResponse, |  | ||||||
|     MiddlewareResponse? lastResponse, |  | ||||||
|   }) => |  | ||||||
|       MiddlewareContext( |  | ||||||
|         pipeline: pipeline ?? this.pipeline, |  | ||||||
|         client: client ?? this.client, |  | ||||||
|         originalRequest: originalRequest ?? this.originalRequest, |  | ||||||
|         lastRequest: lastRequest ?? this.lastRequest, |  | ||||||
|         originalResponse: originalResponse ?? this.originalResponse, |  | ||||||
|         lastResponse: lastResponse ?? this.lastResponse, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String toString() => |  | ||||||
|       'MiddlewareContext(pipeline: $pipeline, client: $client, ' |  | ||||||
|       'originalRequest: $originalRequest, lastRequest: $lastRequest, ' |  | ||||||
|       'originalResponse: $originalResponse, lastResponse: $lastResponse)'; |  | ||||||
| } |  | ||||||
| @ -1,102 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'dart:convert'; |  | ||||||
| 
 |  | ||||||
| import 'package:http/http.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/unfreezed_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/convert.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/request_utils.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template middleware_request} |  | ||||||
| /// A class that represents a middleware request. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class MiddlewareRequest { |  | ||||||
|   /// {@macro middleware_request} |  | ||||||
|   MiddlewareRequest({ |  | ||||||
|     required this.unfreezedRequest, |  | ||||||
|   }) : _httpRequest = Request(unfreezedRequest.method, unfreezedRequest.url); |  | ||||||
| 
 |  | ||||||
|   /// The unfreezed request. |  | ||||||
|   UnfreezedRequest unfreezedRequest; |  | ||||||
| 
 |  | ||||||
|   Request _httpRequest; |  | ||||||
| 
 |  | ||||||
|   /// The http request. (Read-only) |  | ||||||
|   Request get request => _httpRequest; |  | ||||||
| 
 |  | ||||||
|   /// The request method (proxy, read-only). |  | ||||||
|   String get method => _httpRequest.method; |  | ||||||
| 
 |  | ||||||
|   /// The request url (proxy, read-only). |  | ||||||
|   Uri get url => _httpRequest.url; |  | ||||||
| 
 |  | ||||||
|   /// The request headers (proxy, read-only). |  | ||||||
|   Map<String, String> get headers => _httpRequest.headers; |  | ||||||
| 
 |  | ||||||
|   /// The request body (proxy, read-only). |  | ||||||
|   Encoding get encoding => _httpRequest.encoding; |  | ||||||
| 
 |  | ||||||
|   /// The request body (proxy, read-only). |  | ||||||
|   String get encodedBody => _httpRequest.body; |  | ||||||
| 
 |  | ||||||
|   /// The request body (proxy, read-only). |  | ||||||
|   Object? get body => unfreezedRequest.body; |  | ||||||
| 
 |  | ||||||
|   /// Copies this request and returns a new request with the given |  | ||||||
|   /// [unfreezedRequest]. |  | ||||||
|   MiddlewareRequest copyWith({ |  | ||||||
|     UnfreezedRequest? unfreezedRequest, |  | ||||||
|   }) => |  | ||||||
|       MiddlewareRequest( |  | ||||||
|         unfreezedRequest: unfreezedRequest ?? this.unfreezedRequest, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|   /// Modifies the request with the given [unfreezedRequest]. |  | ||||||
|   void modifyRequest(UnfreezedRequest unfreezedRequest) { |  | ||||||
|     String? body; |  | ||||||
|     if (unfreezedRequest.body != null) { |  | ||||||
|       var body = unfreezedRequest.body; |  | ||||||
|       if (body is String) { |  | ||||||
|         body = body; |  | ||||||
|       } else if (body is List) { |  | ||||||
|         body = String.fromCharCodes(body.cast<int>()); |  | ||||||
|       } else if (body is Map) { |  | ||||||
|         body = Convert.mapToQuery(body.cast<String, String>()); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     _httpRequest = RequestUtils.copyRequestWith( |  | ||||||
|       _httpRequest, |  | ||||||
|       method: unfreezedRequest.method, |  | ||||||
|       url: unfreezedRequest.url, |  | ||||||
|       headers: unfreezedRequest.headers, |  | ||||||
|       body: body, |  | ||||||
|     ) as Request; |  | ||||||
|     if (unfreezedRequest.encoding != null) { |  | ||||||
|       _httpRequest.encoding = unfreezedRequest.encoding!; |  | ||||||
|     } |  | ||||||
|     this.unfreezedRequest = unfreezedRequest; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Applies the changes made to the request by modifying it with the |  | ||||||
|   /// [unfreezedRequest]. |  | ||||||
|   void apply() { |  | ||||||
|     modifyRequest(unfreezedRequest); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String toString() => 'MiddlewareRequest(unfreezedRequest: $unfreezedRequest)'; |  | ||||||
| } |  | ||||||
| @ -1,63 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:http/http.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/http_status.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template middleware_response} |  | ||||||
| /// A class that represents a middleware response. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class MiddlewareResponse { |  | ||||||
|   /// {@macro middleware_response} |  | ||||||
|   const MiddlewareResponse({ |  | ||||||
|     required this.httpResponse, |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   /// {@macro middleware_response} |  | ||||||
|   final BaseResponse httpResponse; |  | ||||||
| 
 |  | ||||||
|   /// The status code of the response. (proxy) |  | ||||||
|   int get statusCode => httpResponse.statusCode; |  | ||||||
| 
 |  | ||||||
|   /// The status of the response. (proxy) |  | ||||||
|   HttpStatus get status => HttpStatus.from(statusCode); |  | ||||||
| 
 |  | ||||||
|   /// The body of the response. (proxy or empty string) |  | ||||||
|   String get body { |  | ||||||
|     if (httpResponse is Response) { |  | ||||||
|       return (httpResponse as Response).body; |  | ||||||
|     } else { |  | ||||||
|       return ''; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// The content length of the response. (proxy) |  | ||||||
|   int? get contentLength => httpResponse.contentLength; |  | ||||||
| 
 |  | ||||||
|   /// The headers of the response. (proxy) |  | ||||||
|   Map<String, String> get headers => httpResponse.headers; |  | ||||||
| 
 |  | ||||||
|   /// Returns a copy of this response with the given [httpResponse]. |  | ||||||
|   MiddlewareResponse copyWith({ |  | ||||||
|     BaseResponse? httpResponse, |  | ||||||
|   }) => |  | ||||||
|       MiddlewareResponse( |  | ||||||
|         httpResponse: httpResponse ?? this.httpResponse, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String toString() => 'MiddlewareResponse(httpResponse: $httpResponse)'; |  | ||||||
| } |  | ||||||
| @ -1,69 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'dart:convert'; |  | ||||||
| 
 |  | ||||||
| /// {@template unfreezed_request} |  | ||||||
| /// A class that represents an unfreezed request. |  | ||||||
| /// It is used to unfreeze a Request object, and allows you to |  | ||||||
| /// modify the request before sending it. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class UnfreezedRequest { |  | ||||||
|   /// {@macro unfreezed_request} |  | ||||||
|   const UnfreezedRequest({ |  | ||||||
|     required this.method, |  | ||||||
|     required this.url, |  | ||||||
|     this.headers, |  | ||||||
|     this.body, |  | ||||||
|     this.encoding, |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   /// The request method. |  | ||||||
|   final String method; |  | ||||||
| 
 |  | ||||||
|   /// The request url. |  | ||||||
|   final Uri url; |  | ||||||
| 
 |  | ||||||
|   /// The request headers. |  | ||||||
|   final Map<String, String>? headers; |  | ||||||
| 
 |  | ||||||
|   /// The request body. |  | ||||||
|   final Object? body; |  | ||||||
| 
 |  | ||||||
|   /// The request encoding. |  | ||||||
|   final Encoding? encoding; |  | ||||||
| 
 |  | ||||||
|   /// Copies this request and returns a new request with the given [method], |  | ||||||
|   /// [url], [headers], [body] and [encoding]. |  | ||||||
|   UnfreezedRequest copyWith({ |  | ||||||
|     String? method, |  | ||||||
|     Uri? url, |  | ||||||
|     Map<String, String>? headers, |  | ||||||
|     Object? body, |  | ||||||
|     Encoding? encoding, |  | ||||||
|   }) => |  | ||||||
|       UnfreezedRequest( |  | ||||||
|         method: method ?? this.method, |  | ||||||
|         url: url ?? this.url, |  | ||||||
|         headers: headers ?? this.headers, |  | ||||||
|         body: body ?? this.body, |  | ||||||
|         encoding: encoding ?? this.encoding, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String toString() => 'UnfreezedRequest(method: $method, url: $url, headers: ' |  | ||||||
|       '$headers, body: $body, encoding: $encoding)'; |  | ||||||
| } |  | ||||||
| @ -1,122 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/middleware.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_context.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_request.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/models/middleware_response.dart'; |  | ||||||
| 
 |  | ||||||
| /// {@template pipeline} |  | ||||||
| /// A [Pipeline] is a list of [Middleware]s that are executed in order. |  | ||||||
| /// {@endtemplate} |  | ||||||
| class Pipeline { |  | ||||||
|   /// {@macro pipeline} |  | ||||||
|   Pipeline() : _middlewares = <Middleware>[]; |  | ||||||
| 
 |  | ||||||
|   /// {@macro pipeline} |  | ||||||
|   Pipeline.fromIterable(Iterable<Middleware> middlewares) |  | ||||||
|       : _middlewares = middlewares.toList(); |  | ||||||
| 
 |  | ||||||
|   final List<Middleware> _middlewares; |  | ||||||
| 
 |  | ||||||
|   /// The length of the [Pipeline]. |  | ||||||
|   /// |  | ||||||
|   /// This is the number of [Middleware]s in the [Pipeline]. |  | ||||||
|   int get length => _middlewares.length; |  | ||||||
| 
 |  | ||||||
|   /// Add a [Middleware] to this [Pipeline] |  | ||||||
|   void addMiddleware(Middleware middleware) { |  | ||||||
|     _middlewares.add(middleware); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Create new [Pipeline] from the start or end to a specified [Middleware]. |  | ||||||
|   Pipeline sub( |  | ||||||
|     Middleware middleware, { |  | ||||||
|     bool include = false, |  | ||||||
|     bool fromEnd = false, |  | ||||||
|   }) { |  | ||||||
|     final nodes = <Middleware>[]; |  | ||||||
|     final list = fromEnd ? _middlewares.reversed : _middlewares; |  | ||||||
|     for (final m in list) { |  | ||||||
|       if (m != middleware) { |  | ||||||
|         nodes.add(m); |  | ||||||
|       } |  | ||||||
|       if (m == middleware) { |  | ||||||
|         if (include) { |  | ||||||
|           nodes.add(m); |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return Pipeline.fromIterable(fromEnd ? nodes.reversed : nodes); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Call the [onRequest] method of all [OnRequestMiddleware]s in the |  | ||||||
|   /// [Pipeline]. |  | ||||||
|   /// |  | ||||||
|   /// The [MiddlewareRequest] returned by the last [OnRequestMiddleware] is |  | ||||||
|   /// returned. |  | ||||||
|   Future<MiddlewareRequest> onRequest( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareRequest request, |  | ||||||
|   ) async { |  | ||||||
|     MiddlewareRequest req = request..apply(); |  | ||||||
|     MiddlewareContext ctx = context.copyWith(lastRequest: req); |  | ||||||
|     for (final middleware in _middlewares) { |  | ||||||
|       if (middleware is OnRequestMiddleware) { |  | ||||||
|         req = await (middleware as OnRequestMiddleware).onRequest(ctx, request); |  | ||||||
|         ctx = context.copyWith(lastRequest: req); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return req; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Call the [onResponse] method of all [OnResponseMiddleware]s in the |  | ||||||
|   /// [Pipeline]. |  | ||||||
|   /// |  | ||||||
|   /// The [MiddlewareResponse] returned by the last [OnResponseMiddleware] is |  | ||||||
|   /// returned. |  | ||||||
|   Future<MiddlewareResponse> onResponse( |  | ||||||
|     MiddlewareContext context, |  | ||||||
|     MiddlewareResponse response, |  | ||||||
|   ) async { |  | ||||||
|     MiddlewareResponse res = response; |  | ||||||
|     MiddlewareContext ctx = context.copyWith(lastResponse: res); |  | ||||||
|     for (final middleware in _middlewares.reversed) { |  | ||||||
|       if (middleware is OnResponseMiddleware) { |  | ||||||
|         res = await (middleware as OnResponseMiddleware) |  | ||||||
|             .onResponse(ctx, response); |  | ||||||
|         ctx = context.copyWith(lastResponse: res); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return res; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   String toString() { |  | ||||||
|     final req = <String>[]; |  | ||||||
|     final res = <String>[]; |  | ||||||
|     for (final middleware in _middlewares) { |  | ||||||
|       if (middleware is OnRequestMiddleware) { |  | ||||||
|         req.add(middleware.getName()); |  | ||||||
|       } |  | ||||||
|       if (middleware is OnResponseMiddleware) { |  | ||||||
|         res.insert(0, middleware.getName()); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return '[Req] -> ${req.join(' -> ')}\n[Res] -> ${res.join(' -> ')}'; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,27 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| /// Defines some authentication methods |  | ||||||
| abstract class AuthenticationMethods { |  | ||||||
|   /// The `Basic` authentication method. |  | ||||||
|   static const String basic = 'Basic'; |  | ||||||
| 
 |  | ||||||
|   /// The `Bearer` authentication method. |  | ||||||
|   static const String bearer = 'Bearer'; |  | ||||||
| 
 |  | ||||||
|   /// The `Digest` authentication method. |  | ||||||
|   static const String digest = 'Digest'; |  | ||||||
| } |  | ||||||
| @ -1,62 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'dart:convert'; |  | ||||||
| 
 |  | ||||||
| /// Defines some convert functions. |  | ||||||
| abstract class Convert { |  | ||||||
|   /// Converts a list of bytes to a hex string. |  | ||||||
|   /// |  | ||||||
|   /// If [upperCase] is `true`, the hex string will be in uppercase. |  | ||||||
|   static String toHex(List<int> bytes, {bool upperCase = false}) { |  | ||||||
|     final buffer = StringBuffer(); |  | ||||||
|     for (final int part in bytes) { |  | ||||||
|       if (part & 0xff != part) { |  | ||||||
|         throw const FormatException('Non-byte integer detected'); |  | ||||||
|       } |  | ||||||
|       buffer.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}'); |  | ||||||
|     } |  | ||||||
|     if (upperCase) { |  | ||||||
|       return buffer.toString().toUpperCase(); |  | ||||||
|     } else { |  | ||||||
|       return buffer.toString(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Converts a map to a query string. |  | ||||||
|   /// |  | ||||||
|   /// If [encoding] is `null`, the default encoding is `utf8`. |  | ||||||
|   /// |  | ||||||
|   /// For example, the map `{a: 1, b: 2}` will be converted to `a=1&b=2`. |  | ||||||
|   static String mapToQuery(Map<String, String> map, {Encoding? encoding}) { |  | ||||||
|     final pairs = <List<String>>[]; |  | ||||||
|     map.forEach( |  | ||||||
|       (key, value) => pairs.add([ |  | ||||||
|         Uri.encodeQueryComponent(key, encoding: encoding ?? utf8), |  | ||||||
|         Uri.encodeQueryComponent(value, encoding: encoding ?? utf8), |  | ||||||
|       ]), |  | ||||||
|     ); |  | ||||||
|     return pairs.map((pair) => '${pair[0]}=${pair[1]}').join('&'); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| extension UriX on Uri { |  | ||||||
|   /// Returns a new [Uri] by appending the given [path] to this [Uri]. |  | ||||||
|   Uri operator +(String path) { |  | ||||||
|     final thisPath = toString(); |  | ||||||
|     return Uri.parse(thisPath + path); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,30 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'dart:convert'; |  | ||||||
| 
 |  | ||||||
| import 'package:crypto/crypto.dart'; |  | ||||||
| 
 |  | ||||||
| /// Defines some crypto functions. |  | ||||||
| abstract class Crypto { |  | ||||||
|   /// Hash a string using MD5 |  | ||||||
|   static String md5Hash(String data) { |  | ||||||
|     final content = const Utf8Encoder().convert(data); |  | ||||||
|     const md5Crypto = md5; |  | ||||||
|     final digest = md5Crypto.convert(content).toString(); |  | ||||||
|     return digest; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,38 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'dart:core'; |  | ||||||
| import 'dart:math'; |  | ||||||
| 
 |  | ||||||
| /// Defines some delay functions. |  | ||||||
| abstract class Delay { |  | ||||||
|   /// Returns a delay based on the [attempt]. |  | ||||||
|   static Duration getRetryDelay(int attempt) { |  | ||||||
|     assert(attempt >= 0, 'attempt cannot be negative'); |  | ||||||
|     if (attempt <= 0) { |  | ||||||
|       return Duration.zero; |  | ||||||
|     } |  | ||||||
|     final rand = Random(); |  | ||||||
|     const Duration delayFactor = Duration(milliseconds: 200); |  | ||||||
|     const double randomizationFactor = 0.25; |  | ||||||
|     const Duration maxDelay = Duration(seconds: 30); |  | ||||||
| 
 |  | ||||||
|     final rf = randomizationFactor * (rand.nextDouble() * 2 - 1) + 1; |  | ||||||
|     final exp = min(attempt, 31); // prevent overflows. |  | ||||||
|     final delay = delayFactor * pow(2.0, exp) * rf; |  | ||||||
|     return delay < maxDelay ? delay : maxDelay; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,196 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'dart:math'; |  | ||||||
| 
 |  | ||||||
| import 'package:wyatt_http_client/src/utils/convert.dart'; |  | ||||||
| import 'package:wyatt_http_client/src/utils/crypto.dart'; |  | ||||||
| 
 |  | ||||||
| /// A class for digest authentication. |  | ||||||
| class DigestAuth { |  | ||||||
|   // request counter |  | ||||||
| 
 |  | ||||||
|   DigestAuth(this.username, this.password); |  | ||||||
|   final String username; |  | ||||||
|   final String password; |  | ||||||
| 
 |  | ||||||
|   // must get from first response |  | ||||||
|   String? _algorithm; |  | ||||||
|   String? _qop; |  | ||||||
|   String? _realm; |  | ||||||
|   String? _nonce; |  | ||||||
|   String? _opaque; |  | ||||||
| 
 |  | ||||||
|   int _nc = 0; |  | ||||||
| 
 |  | ||||||
|   /// Splits WWW-Authenticate header into a map. |  | ||||||
|   Map<String, String>? splitWWWAuthenticateHeader(String header) { |  | ||||||
|     if (!header.startsWith('Digest ')) { |  | ||||||
|       throw ArgumentError.value( |  | ||||||
|         header, |  | ||||||
|         'header', |  | ||||||
|         'Header must start with "Digest "', |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|     final h = header.substring(7); // remove 'Digest ' |  | ||||||
|     final ret = <String, String>{}; |  | ||||||
| 
 |  | ||||||
|     final components = h.split(',').map((token) => token.trim()); |  | ||||||
|     for (final component in components) { |  | ||||||
|       final kv = component.split('='); |  | ||||||
|       ret[kv[0]] = kv.getRange(1, kv.length).join('=').replaceAll('"', ''); |  | ||||||
|     } |  | ||||||
|     return ret; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   String _computeNonce() { |  | ||||||
|     final rnd = Random.secure(); |  | ||||||
|     final values = List<int>.generate(16, (i) => rnd.nextInt(256)); |  | ||||||
| 
 |  | ||||||
|     return Convert.toHex(values); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   String _formatNonceCount(int nc) => nc.toRadixString(16).padLeft(8, '0'); |  | ||||||
| 
 |  | ||||||
|   String _computeHA1( |  | ||||||
|     String realm, |  | ||||||
|     String? algorithm, |  | ||||||
|     String username, |  | ||||||
|     String password, |  | ||||||
|     String? nonce, |  | ||||||
|     String? cnonce, |  | ||||||
|   ) { |  | ||||||
|     if (algorithm == null || algorithm == 'MD5') { |  | ||||||
|       final token1 = '$username:$realm:$password'; |  | ||||||
|       return Crypto.md5Hash(token1); |  | ||||||
|     } else if (algorithm == 'MD5-sess') { |  | ||||||
|       final token1 = '$username:$realm:$password'; |  | ||||||
|       final md51 = Crypto.md5Hash(token1); |  | ||||||
|       final token2 = '$md51:$nonce:$cnonce'; |  | ||||||
|       return Crypto.md5Hash(token2); |  | ||||||
|     } else { |  | ||||||
|       throw ArgumentError.value( |  | ||||||
|         algorithm, |  | ||||||
|         'algorithm', |  | ||||||
|         'Unsupported algorithm', |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   Map<String, String?> _computeResponse( |  | ||||||
|     String method, |  | ||||||
|     String path, |  | ||||||
|     String body, |  | ||||||
|     String? algorithm, |  | ||||||
|     String? qop, |  | ||||||
|     String? opaque, |  | ||||||
|     String realm, |  | ||||||
|     String? cnonce, |  | ||||||
|     String? nonce, |  | ||||||
|     int nc, |  | ||||||
|     String username, |  | ||||||
|     String password, |  | ||||||
|   ) { |  | ||||||
|     final ret = <String, String?>{}; |  | ||||||
| 
 |  | ||||||
|     final ha1 = |  | ||||||
|         _computeHA1(realm, algorithm, username, password, nonce, cnonce); |  | ||||||
| 
 |  | ||||||
|     String ha2; |  | ||||||
| 
 |  | ||||||
|     if (qop == 'auth-int') { |  | ||||||
|       final bodyHash = Crypto.md5Hash(body); |  | ||||||
|       final token2 = '$method:$path:$bodyHash'; |  | ||||||
|       ha2 = Crypto.md5Hash(token2); |  | ||||||
|     } else { |  | ||||||
|       // qop in [null, auth] |  | ||||||
|       final token2 = '$method:$path'; |  | ||||||
|       ha2 = Crypto.md5Hash(token2); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     final nonceCount = _formatNonceCount(nc); |  | ||||||
|     ret['username'] = username; |  | ||||||
|     ret['realm'] = realm; |  | ||||||
|     ret['nonce'] = nonce; |  | ||||||
|     ret['uri'] = path; |  | ||||||
|     if (qop != null) { |  | ||||||
|       ret['qop'] = qop; |  | ||||||
|     } |  | ||||||
|     ret['nc'] = nonceCount; |  | ||||||
|     ret['cnonce'] = cnonce; |  | ||||||
|     if (opaque != null) { |  | ||||||
|       ret['opaque'] = opaque; |  | ||||||
|     } |  | ||||||
|     ret['algorithm'] = algorithm; |  | ||||||
| 
 |  | ||||||
|     if (qop == null) { |  | ||||||
|       final token3 = '$ha1:$nonce:$ha2'; |  | ||||||
|       ret['response'] = Crypto.md5Hash(token3); |  | ||||||
|     } else if (qop == 'auth' || qop == 'auth-int') { |  | ||||||
|       final token3 = '$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2'; |  | ||||||
|       ret['response'] = Crypto.md5Hash(token3); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return ret; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   String getAuthString(String method, Uri url) { |  | ||||||
|     final cnonce = _computeNonce(); |  | ||||||
|     _nc += 1; |  | ||||||
|     // if url has query parameters, append query to path |  | ||||||
|     final path = url.hasQuery ? '${url.path}?${url.query}' : url.path; |  | ||||||
| 
 |  | ||||||
|     // after the first request we have the nonce, so we can provide credentials |  | ||||||
|     final authValues = _computeResponse( |  | ||||||
|       method, |  | ||||||
|       path, |  | ||||||
|       '', |  | ||||||
|       _algorithm, |  | ||||||
|       _qop, |  | ||||||
|       _opaque, |  | ||||||
|       _realm!, |  | ||||||
|       cnonce, |  | ||||||
|       _nonce, |  | ||||||
|       _nc, |  | ||||||
|       username, |  | ||||||
|       password, |  | ||||||
|     ); |  | ||||||
|     final authValuesString = authValues.entries |  | ||||||
|         .where((e) => e.value != null) |  | ||||||
|         .map((e) => [e.key, '="', e.value, '"'].join()) |  | ||||||
|         .toList() |  | ||||||
|         .join(', '); |  | ||||||
|     final authString = 'Digest $authValuesString'; |  | ||||||
|     return authString; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   void initFromAuthenticateHeader(String? authInfo) { |  | ||||||
|     if (authInfo == null) { |  | ||||||
|       throw ArgumentError.notNull('authInfo'); |  | ||||||
|     } |  | ||||||
|     final values = splitWWWAuthenticateHeader(authInfo); |  | ||||||
|     if (values != null) { |  | ||||||
|       _algorithm = values['algorithm'] ?? _algorithm; |  | ||||||
|       _qop = values['qop'] ?? _qop; |  | ||||||
|       _realm = values['realm'] ?? _realm; |  | ||||||
|       _nonce = values['nonce'] ?? _nonce; |  | ||||||
|       _opaque = values['opaque'] ?? _opaque; |  | ||||||
|       _nc = 0; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   bool isReady() => _nonce != null && (_nc == 0 || _qop != null); |  | ||||||
| } |  | ||||||
| @ -1,27 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| /// Defines some header keys. |  | ||||||
| abstract class HeaderKeys { |  | ||||||
|   /// The `Authorization` header key. |  | ||||||
|   static const String authorization = 'Authorization'; |  | ||||||
| 
 |  | ||||||
|   /// The `WWW-Authenticate` header key. |  | ||||||
|   static const String wwwAuthenticate = 'WWW-Authenticate'; |  | ||||||
| 
 |  | ||||||
|   /// The `Content-Type` header key. |  | ||||||
|   static const String contentType = 'Content-Type'; |  | ||||||
| } |  | ||||||
| @ -1,32 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| /// Defines http verb methods. |  | ||||||
| enum HttpMethods { |  | ||||||
|   head('HEAD'), |  | ||||||
|   get('GET'), |  | ||||||
|   post('POST'), |  | ||||||
|   put('PUT'), |  | ||||||
|   patch('PATCH'), |  | ||||||
|   delete('DELETE'); |  | ||||||
| 
 |  | ||||||
|   const HttpMethods(this.method); |  | ||||||
| 
 |  | ||||||
|   /// Returns the method of the http verb. |  | ||||||
|   /// |  | ||||||
|   /// For example, the method of [HttpMethods.get] is `GET`. |  | ||||||
|   final String method; |  | ||||||
| } |  | ||||||
| @ -1,116 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| /// Status codes for HTTP responses. Extracted from dart:io |  | ||||||
| enum HttpStatus { |  | ||||||
|   continue_(100), |  | ||||||
|   switchingProtocols(101), |  | ||||||
|   processing(102), |  | ||||||
|   ok(200), |  | ||||||
|   created(201), |  | ||||||
|   accepted(202), |  | ||||||
|   nonAuthoritativeInformation(203), |  | ||||||
|   noContent(204), |  | ||||||
|   resetContent(205), |  | ||||||
|   partialContent(206), |  | ||||||
|   multiStatus(207), |  | ||||||
|   alreadyReported(208), |  | ||||||
|   imUsed(226), |  | ||||||
|   multipleChoices(300), |  | ||||||
|   movedPermanently(301), |  | ||||||
|   found(302), |  | ||||||
|   movedTemporarily(302), // Common alias for found. |  | ||||||
|   seeOther(303), |  | ||||||
|   notModified(304), |  | ||||||
|   useProxy(305), |  | ||||||
|   temporaryRedirect(307), |  | ||||||
|   permanentRedirect(308), |  | ||||||
|   badRequest(400), |  | ||||||
|   unauthorized(401), |  | ||||||
|   paymentRequired(402), |  | ||||||
|   forbidden(403), |  | ||||||
|   notFound(404), |  | ||||||
|   methodNotAllowed(405), |  | ||||||
|   notAcceptable(406), |  | ||||||
|   proxyAuthenticationRequired(407), |  | ||||||
|   requestTimeout(408), |  | ||||||
|   conflict(409), |  | ||||||
|   gone(410), |  | ||||||
|   lengthRequired(411), |  | ||||||
|   preconditionFailed(412), |  | ||||||
|   requestEntityTooLarge(413), |  | ||||||
|   requestUriTooLong(414), |  | ||||||
|   unsupportedMediaType(415), |  | ||||||
|   requestedRangeNotSatisfiable(416), |  | ||||||
|   expectationFailed(417), |  | ||||||
|   misdirectedRequest(421), |  | ||||||
|   unprocessableEntity(422), |  | ||||||
|   locked(423), |  | ||||||
|   failedDependency(424), |  | ||||||
|   upgradeRequired(426), |  | ||||||
|   preconditionRequired(428), |  | ||||||
|   tooManyRequests(429), |  | ||||||
|   requestHeaderFieldsTooLarge(431), |  | ||||||
|   connectionClosedWithoutResponse(444), |  | ||||||
|   unavailableForLegalReasons(451), |  | ||||||
|   clientClosedRequest(499), |  | ||||||
|   internalServerError(500), |  | ||||||
|   notImplemented(501), |  | ||||||
|   badGateway(502), |  | ||||||
|   serviceUnavailable(503), |  | ||||||
|   gatewayTimeout(504), |  | ||||||
|   httpVersionNotSupported(505), |  | ||||||
|   variantAlsoNegotiates(506), |  | ||||||
|   insufficientStorage(507), |  | ||||||
|   loopDetected(508), |  | ||||||
|   notExtended(510), |  | ||||||
|   networkAuthenticationRequired(511), |  | ||||||
|   // Client generated status code. |  | ||||||
|   networkConnectTimeoutError(599); |  | ||||||
| 
 |  | ||||||
|   const HttpStatus(this.statusCode); |  | ||||||
| 
 |  | ||||||
|   /// Returns the [HttpStatus] with the given [statusCode]. |  | ||||||
|   factory HttpStatus.from(int status) => |  | ||||||
|       HttpStatus.values.firstWhere((element) => element.statusCode == status); |  | ||||||
| 
 |  | ||||||
|   final int statusCode; |  | ||||||
| 
 |  | ||||||
|   bool equals(Object other) { |  | ||||||
|     if (other is HttpStatus) { |  | ||||||
|       return statusCode == other.statusCode; |  | ||||||
|     } |  | ||||||
|     if (other is int) { |  | ||||||
|       return statusCode == other; |  | ||||||
|     } |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Checks if the status code is in the range of 100-199. |  | ||||||
|   bool isInfo() => statusCode >= 100 && statusCode < 200; |  | ||||||
| 
 |  | ||||||
|   /// Checks if the status code is in the range of 200-299. |  | ||||||
|   bool isSuccess() => statusCode >= 200 && statusCode < 300; |  | ||||||
| 
 |  | ||||||
|   /// Checks if the status code is in the range of 300-399. |  | ||||||
|   bool isRedirection() => statusCode >= 300 && statusCode < 400; |  | ||||||
| 
 |  | ||||||
|   /// Checks if the status code is in the range of 400-499. |  | ||||||
|   bool isClientError() => statusCode >= 400 && statusCode < 500; |  | ||||||
| 
 |  | ||||||
|   /// Checks if the status code is in the range of 500-599. |  | ||||||
|   bool isServerError() => statusCode >= 500 && statusCode < 600; |  | ||||||
| } |  | ||||||
| @ -1,26 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| /// Defines few protocols |  | ||||||
| enum Protocols { |  | ||||||
|   http, |  | ||||||
|   https; |  | ||||||
| 
 |  | ||||||
|   /// Returns the scheme of the protocol. |  | ||||||
|   /// |  | ||||||
|   /// For example, the scheme of [Protocols.http] is `http://`. |  | ||||||
|   String get scheme => '$name://'; |  | ||||||
| } |  | ||||||
| @ -1,95 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| import 'package:http/http.dart'; |  | ||||||
| 
 |  | ||||||
| /// Defines some request utils. |  | ||||||
| abstract class RequestUtils { |  | ||||||
|   static Request _copyNormalRequestWith( |  | ||||||
|     Request original, { |  | ||||||
|     String? method, |  | ||||||
|     Uri? url, |  | ||||||
|     Map<String, String>? headers, |  | ||||||
|     int? maxRedirects, |  | ||||||
|     bool? followRedirects, |  | ||||||
|     bool? persistentConnection, |  | ||||||
|     String? body, |  | ||||||
|   }) { |  | ||||||
|     final request = Request(method ?? original.method, url ?? original.url) |  | ||||||
|       ..followRedirects = followRedirects ?? original.followRedirects |  | ||||||
|       ..headers.addAll(headers ?? original.headers) |  | ||||||
|       ..maxRedirects = maxRedirects ?? original.maxRedirects |  | ||||||
|       ..persistentConnection = |  | ||||||
|           persistentConnection ?? original.persistentConnection |  | ||||||
|       ..body = body ?? original.body; |  | ||||||
| 
 |  | ||||||
|     return request; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Copies the given [original] request and returns a new request with the |  | ||||||
|   /// given [method], [url], [headers], [maxRedirects], [followRedirects], |  | ||||||
|   /// [persistentConnection] and [body]. |  | ||||||
|   static BaseRequest copyRequestWith( |  | ||||||
|     BaseRequest original, { |  | ||||||
|     String? method, |  | ||||||
|     Uri? url, |  | ||||||
|     Map<String, String>? headers, |  | ||||||
|     int? maxRedirects, |  | ||||||
|     bool? followRedirects, |  | ||||||
|     bool? persistentConnection, |  | ||||||
|     String? body, |  | ||||||
|   }) { |  | ||||||
|     if (original is Request) { |  | ||||||
|       return _copyNormalRequestWith( |  | ||||||
|         original, |  | ||||||
|         method: method, |  | ||||||
|         url: url, |  | ||||||
|         headers: headers, |  | ||||||
|         maxRedirects: maxRedirects, |  | ||||||
|         followRedirects: followRedirects, |  | ||||||
|         persistentConnection: persistentConnection, |  | ||||||
|         body: body, |  | ||||||
|       ); |  | ||||||
|     } else { |  | ||||||
|       throw UnimplementedError( |  | ||||||
|         'Cannot handle requests of type ${original.runtimeType}', |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   static Request _copyNormalRequest(Request original) { |  | ||||||
|     final request = Request(original.method, original.url) |  | ||||||
|       ..followRedirects = original.followRedirects |  | ||||||
|       ..headers.addAll(original.headers) |  | ||||||
|       ..maxRedirects = original.maxRedirects |  | ||||||
|       ..persistentConnection = original.persistentConnection |  | ||||||
|       ..body = original.body; |  | ||||||
| 
 |  | ||||||
|     return request; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Copies the given [original] request and returns a new request. |  | ||||||
|   /// This method is useful when you want to modify the request |  | ||||||
|   static BaseRequest copyRequest(BaseRequest original) { |  | ||||||
|     if (original is Request) { |  | ||||||
|       return _copyNormalRequest(original); |  | ||||||
|     } else { |  | ||||||
|       throw UnimplementedError( |  | ||||||
|         'Cannot handle requests of type ${original.runtimeType}', |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,23 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| export 'authentication_methods.dart'; |  | ||||||
| export 'digest_auth.dart'; |  | ||||||
| export 'header_keys.dart'; |  | ||||||
| export 'http_methods.dart'; |  | ||||||
| export 'http_status.dart'; |  | ||||||
| export 'protocols.dart'; |  | ||||||
| export 'request_utils.dart'; |  | ||||||
| @ -1,24 +0,0 @@ | |||||||
| // Copyright (C) 2022 WYATT GROUP |  | ||||||
| // Please see the AUTHORS file for details. |  | ||||||
| // |  | ||||||
| // This program is free software: you can redistribute it and/or modify |  | ||||||
| // it under the terms of the GNU General Public License as published by |  | ||||||
| // the Free Software Foundation, either version 3 of the License, or |  | ||||||
| // any later version. |  | ||||||
| // |  | ||||||
| // This program is distributed in the hope that it will be useful, |  | ||||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
| // GNU General Public License for more details. |  | ||||||
| // |  | ||||||
| // You should have received a copy of the GNU General Public License |  | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. |  | ||||||
| 
 |  | ||||||
| library wyatt_http_client; |  | ||||||
| 
 |  | ||||||
| export 'src/middleware.dart'; |  | ||||||
| export 'src/middleware_client.dart'; |  | ||||||
| export 'src/middlewares/middlewares.dart'; |  | ||||||
| export 'src/models/models.dart'; |  | ||||||
| export 'src/pipeline.dart'; |  | ||||||
| export 'src/utils/utils.dart'; |  | ||||||
| @ -1,18 +0,0 @@ | |||||||
| name: wyatt_http_client |  | ||||||
| description: A Dart client for RESTful APIs with authentication. |  | ||||||
| repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_http_client |  | ||||||
| version: 2.0.1 |  | ||||||
| 
 |  | ||||||
| publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub |  | ||||||
| 
 |  | ||||||
| environment: |  | ||||||
|   sdk: '>=2.17.0 <3.0.0' |  | ||||||
| 
 |  | ||||||
| dependencies:  |  | ||||||
|   crypto: ^3.0.2 |  | ||||||
|   http: ^1.1.0 |  | ||||||
| 
 |  | ||||||
| dev_dependencies: |  | ||||||
|   wyatt_analysis: |  | ||||||
|     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub |  | ||||||
|     version: ^2.5.0 |  | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user