LCOV - code coverage report
Current view: top level - Users/duwen/Documents/code/dio/dio/lib/src - options.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 157 161 97.5 %
Date: 2021-11-28 14:37:50 Functions: 0 0 -

          Line data    Source code
       1             : import 'adapter.dart';
       2             : import 'cancel_token.dart';
       3             : import 'headers.dart';
       4             : import 'transformer.dart';
       5             : import 'utils.dart';
       6             : 
       7             : /// Callback to listen the progress for sending/receiving data.
       8             : ///
       9             : /// [count] is the length of the bytes have been sent/received.
      10             : ///
      11             : /// [total] is the content length of the response/request body.
      12             : /// 1.When receiving data:
      13             : ///   [total] is the request body length.
      14             : /// 2.When receiving data:
      15             : ///   [total] will be -1 if the size of the response body is not known in advance,
      16             : ///   for example: response data is compressed with gzip or no content-length header.
      17             : typedef ProgressCallback = void Function(int count, int total);
      18             : 
      19             : /// ResponseType indicates which transformation should
      20             : /// be automatically applied to the response data by Dio.
      21          12 : enum ResponseType {
      22             :   /// Transform the response data to JSON object only when the
      23             :   /// content-type of response is "application/json" .
      24             :   json,
      25             : 
      26             :   /// Get the response stream without any transformation. The
      27             :   /// Response data will be a `ResponseBody` instance.
      28             :   ///
      29             :   ///    Response<ResponseBody> rs = await Dio().get<ResponseBody>(
      30             :   ///      url,
      31             :   ///      options: Options(
      32             :   ///        responseType: ResponseType.stream,
      33             :   ///      ),
      34             :   ///    );
      35             :   stream,
      36             : 
      37             :   /// Transform the response data to a String encoded with UTF8.
      38             :   plain,
      39             : 
      40             :   /// Get original bytes, the type of [Response.data] will be List<int>
      41             :   bytes
      42             : }
      43             : 
      44             : /// ListFormat specifies the array format
      45             : /// (a single parameter with multiple parameter or multiple parameters with the same name)
      46             : /// and the separator for array items.
      47          11 : enum ListFormat {
      48             :   /// Comma-separated values
      49             :   /// e.g. (foo,bar,baz)
      50             :   csv,
      51             : 
      52             :   /// Space-separated values
      53             :   /// e.g. (foo bar baz)
      54             :   ssv,
      55             : 
      56             :   /// Tab-separated values
      57             :   /// e.g. (foo\tbar\tbaz)
      58             :   tsv,
      59             : 
      60             :   /// Pipe-separated values
      61             :   /// e.g. (foo|bar|baz)
      62             :   pipes,
      63             : 
      64             :   /// Multiple parameter instances rather than multiple values.
      65             :   /// e.g. (foo=value&foo=another_value)
      66             :   multi,
      67             : 
      68             :   /// Forward compatibility
      69             :   /// e.g. (foo[]=value&foo[]=another_value)
      70             :   multiCompatible,
      71             : }
      72             : 
      73             : typedef ValidateStatus = bool Function(int? status);
      74             : 
      75             : typedef ResponseDecoder = String Function(
      76             :     List<int> responseBytes, RequestOptions options, ResponseBody responseBody);
      77             : typedef RequestEncoder = List<int> Function(
      78             :     String request, RequestOptions options);
      79             : 
      80             : /// The common config for the Dio instance.
      81             : /// `dio.options` is a instance of [BaseOptions]
      82             : class BaseOptions extends _RequestConfig with OptionsMixin {
      83           8 :   BaseOptions({
      84             :     String? method,
      85             :     int? connectTimeout,
      86             :     int? receiveTimeout,
      87             :     int? sendTimeout,
      88             :     String baseUrl = '',
      89             :     Map<String, dynamic>? queryParameters,
      90             :     Map<String, dynamic>? extra,
      91             :     Map<String, dynamic>? headers,
      92             :     ResponseType? responseType = ResponseType.json,
      93             :     String? contentType,
      94             :     ValidateStatus? validateStatus,
      95             :     bool? receiveDataWhenStatusError,
      96             :     bool? followRedirects,
      97             :     int? maxRedirects,
      98             :     RequestEncoder? requestEncoder,
      99             :     ResponseDecoder? responseDecoder,
     100             :     ListFormat? listFormat,
     101             :     this.setRequestContentTypeWhenNoPayload = false,
     102           8 :   }) : super(
     103             :           method: method,
     104             :           receiveTimeout: receiveTimeout,
     105             :           sendTimeout: sendTimeout,
     106             :           extra: extra,
     107             :           headers: headers,
     108             :           responseType: responseType,
     109             :           contentType: contentType,
     110             :           validateStatus: validateStatus,
     111             :           receiveDataWhenStatusError: receiveDataWhenStatusError,
     112             :           followRedirects: followRedirects,
     113             :           maxRedirects: maxRedirects,
     114             :           requestEncoder: requestEncoder,
     115             :           responseDecoder: responseDecoder,
     116             :           listFormat: listFormat,
     117             :         ) {
     118          16 :     this.queryParameters = queryParameters ?? {};
     119           8 :     this.baseUrl = baseUrl;
     120           8 :     this.connectTimeout = connectTimeout ?? 0;
     121             :   }
     122             : 
     123             :   /// Create a Option from current instance with merging attributes.
     124           1 :   BaseOptions copyWith({
     125             :     String? method,
     126             :     String? baseUrl,
     127             :     Map<String, dynamic>? queryParameters,
     128             :     String? path,
     129             :     int? connectTimeout,
     130             :     int? receiveTimeout,
     131             :     int? sendTimeout,
     132             :     Map<String, dynamic>? extra,
     133             :     Map<String, dynamic>? headers,
     134             :     ResponseType? responseType,
     135             :     String? contentType,
     136             :     ValidateStatus? validateStatus,
     137             :     bool? receiveDataWhenStatusError,
     138             :     bool? followRedirects,
     139             :     int? maxRedirects,
     140             :     RequestEncoder? requestEncoder,
     141             :     ResponseDecoder? responseDecoder,
     142             :     ListFormat? listFormat,
     143             :     bool? setRequestContentTypeWhenNoPayload,
     144             :   }) {
     145           1 :     return BaseOptions(
     146           1 :       method: method ?? this.method,
     147           1 :       baseUrl: baseUrl ?? this.baseUrl,
     148           1 :       queryParameters: queryParameters ?? this.queryParameters,
     149           1 :       connectTimeout: connectTimeout ?? this.connectTimeout,
     150           1 :       receiveTimeout: receiveTimeout ?? this.receiveTimeout,
     151           1 :       sendTimeout: sendTimeout ?? this.sendTimeout,
     152           2 :       extra: extra ?? Map.from(this.extra),
     153           2 :       headers: headers ?? Map.from(this.headers),
     154           1 :       responseType: responseType ?? this.responseType,
     155           1 :       contentType: contentType ?? this.contentType,
     156           1 :       validateStatus: validateStatus ?? this.validateStatus,
     157             :       receiveDataWhenStatusError:
     158           1 :           receiveDataWhenStatusError ?? this.receiveDataWhenStatusError,
     159           1 :       followRedirects: followRedirects ?? this.followRedirects,
     160           1 :       maxRedirects: maxRedirects ?? this.maxRedirects,
     161           1 :       requestEncoder: requestEncoder ?? this.requestEncoder,
     162           1 :       responseDecoder: responseDecoder ?? this.responseDecoder,
     163           1 :       listFormat: listFormat ?? this.listFormat,
     164             :       setRequestContentTypeWhenNoPayload: setRequestContentTypeWhenNoPayload ??
     165           1 :           this.setRequestContentTypeWhenNoPayload,
     166             :     );
     167             :   }
     168             : 
     169             :   static const _allowPayloadMethods = ['POST', 'PUT', 'PATCH', 'DELETE'];
     170             : 
     171             :   /// if false, content-type in request header will be deleted when method is not on of `_allowPayloadMethods`
     172             :   bool setRequestContentTypeWhenNoPayload;
     173             : 
     174           7 :   String? contentTypeWithRequestBody(String method) {
     175           7 :     if (setRequestContentTypeWhenNoPayload) {
     176           1 :       return contentType;
     177             :     } else {
     178          10 :       return _allowPayloadMethods.contains(method) ? contentType : null;
     179             :     }
     180             :   }
     181             : }
     182             : 
     183             : mixin OptionsMixin {
     184             :   /// Request base url, it can contain sub path, like: "https://www.google.com/api/".
     185             :   late String baseUrl;
     186             : 
     187             :   /// Common query parameters.
     188             :   ///
     189             :   /// List values use the default [ListFormat.multiCompatible].
     190             :   ///
     191             :   /// The value can be overridden per parameter by adding a [MultiParam]
     192             :   /// object wrapping the actual List value and the desired format.
     193             :   late Map<String, dynamic> queryParameters;
     194             : 
     195             :   /// Timeout in milliseconds for opening url.
     196             :   /// [Dio] will throw the [DioError] with [DioErrorType.connectTimeout] type
     197             :   ///  when time out.
     198             :   late int connectTimeout;
     199             : }
     200             : 
     201             : /// Every request can pass an [Options] object which will be merged with [Dio.options]
     202             : class Options {
     203           8 :   Options({
     204             :     this.method,
     205             :     this.sendTimeout,
     206             :     this.receiveTimeout,
     207             :     this.extra,
     208             :     this.headers,
     209             :     this.responseType,
     210             :     this.contentType,
     211             :     this.validateStatus,
     212             :     this.receiveDataWhenStatusError,
     213             :     this.followRedirects,
     214             :     this.maxRedirects,
     215             :     this.requestEncoder,
     216             :     this.responseDecoder,
     217             :     this.listFormat,
     218             :   });
     219             : 
     220             :   /// Create a Option from current instance with merging attributes.
     221           1 :   Options copyWith({
     222             :     String? method,
     223             :     int? sendTimeout,
     224             :     int? receiveTimeout,
     225             :     Map<String, dynamic>? extra,
     226             :     Map<String, dynamic>? headers,
     227             :     ResponseType? responseType,
     228             :     String? contentType,
     229             :     ValidateStatus? validateStatus,
     230             :     bool? receiveDataWhenStatusError,
     231             :     bool? followRedirects,
     232             :     int? maxRedirects,
     233             :     RequestEncoder? requestEncoder,
     234             :     ResponseDecoder? responseDecoder,
     235             :     ListFormat? listFormat,
     236             :   }) {
     237             :     Map<String, dynamic>? _headers;
     238           1 :     if (headers == null && this.headers != null) {
     239           2 :       _headers = caseInsensitiveKeyMap(this.headers!);
     240             :     }
     241             : 
     242             :     if (headers != null) {
     243           1 :       headers = caseInsensitiveKeyMap(headers);
     244             :       assert(
     245           0 :         !(contentType != null &&
     246           1 :             headers.containsKey(Headers.contentTypeHeader)),
     247             :         'You cannot set both contentType param and a content-type header',
     248             :       );
     249             :     }
     250             : 
     251             :     Map<String, dynamic>? _extra;
     252           1 :     if (extra == null && this.extra != null) {
     253           0 :       _extra = Map.from(this.extra!);
     254             :     }
     255             : 
     256           1 :     return Options(
     257           1 :       method: method ?? this.method,
     258           1 :       sendTimeout: sendTimeout ?? this.sendTimeout,
     259           1 :       receiveTimeout: receiveTimeout ?? this.receiveTimeout,
     260             :       extra: extra ?? _extra,
     261             :       headers: headers ?? _headers,
     262           1 :       responseType: responseType ?? this.responseType,
     263           1 :       contentType: contentType ?? this.contentType,
     264           1 :       validateStatus: validateStatus ?? this.validateStatus,
     265             :       receiveDataWhenStatusError:
     266           1 :           receiveDataWhenStatusError ?? this.receiveDataWhenStatusError,
     267           1 :       followRedirects: followRedirects ?? this.followRedirects,
     268           1 :       maxRedirects: maxRedirects ?? this.maxRedirects,
     269           1 :       requestEncoder: requestEncoder ?? this.requestEncoder,
     270           1 :       responseDecoder: responseDecoder ?? this.responseDecoder,
     271           1 :       listFormat: listFormat ?? this.listFormat,
     272             :     );
     273             :   }
     274             : 
     275           8 :   RequestOptions compose(
     276             :     BaseOptions baseOpt,
     277             :     String path, {
     278             :     data,
     279             :     Map<String, dynamic>? queryParameters,
     280             :     CancelToken? cancelToken,
     281             :     Options? options,
     282             :     ProgressCallback? onSendProgress,
     283             :     ProgressCallback? onReceiveProgress,
     284             :   }) {
     285           8 :     var query = <String, dynamic>{};
     286          16 :     query.addAll(baseOpt.queryParameters);
     287           1 :     if (queryParameters != null) query.addAll(queryParameters);
     288             : 
     289          16 :     var _headers = caseInsensitiveKeyMap(baseOpt.headers);
     290           8 :     _headers.remove(Headers.contentTypeHeader);
     291             : 
     292             :     String? _contentType;
     293             : 
     294           8 :     if (headers != null) {
     295           4 :       _headers.addAll(headers!);
     296           2 :       _contentType = _headers[Headers.contentTypeHeader] as String?;
     297             :     }
     298             : 
     299          16 :     var _extra = Map<String, dynamic>.from(baseOpt.extra);
     300           8 :     if (extra != null) {
     301           0 :       _extra.addAll(extra!);
     302             :     }
     303          18 :     var _method = (method ?? baseOpt.method).toUpperCase();
     304           8 :     var requestOptions = RequestOptions(
     305             :       method: _method,
     306             :       headers: _headers,
     307             :       extra: _extra,
     308           8 :       baseUrl: baseOpt.baseUrl,
     309             :       path: path,
     310             :       data: data,
     311           8 :       connectTimeout: baseOpt.connectTimeout,
     312          16 :       sendTimeout: sendTimeout ?? baseOpt.sendTimeout,
     313          16 :       receiveTimeout: receiveTimeout ?? baseOpt.receiveTimeout,
     314          15 :       responseType: responseType ?? baseOpt.responseType,
     315          16 :       validateStatus: validateStatus ?? baseOpt.validateStatus,
     316             :       receiveDataWhenStatusError:
     317          16 :           receiveDataWhenStatusError ?? baseOpt.receiveDataWhenStatusError,
     318          16 :       followRedirects: followRedirects ?? baseOpt.followRedirects,
     319          16 :       maxRedirects: maxRedirects ?? baseOpt.maxRedirects,
     320             :       queryParameters: query,
     321          16 :       requestEncoder: requestEncoder ?? baseOpt.requestEncoder,
     322          16 :       responseDecoder: responseDecoder ?? baseOpt.responseDecoder,
     323          16 :       listFormat: listFormat ?? baseOpt.listFormat,
     324             :     );
     325             : 
     326           8 :     requestOptions.onReceiveProgress = onReceiveProgress;
     327           8 :     requestOptions.onSendProgress = onSendProgress;
     328           8 :     requestOptions.cancelToken = cancelToken;
     329             : 
     330           8 :     requestOptions.contentType = _contentType ??
     331           8 :         contentType ??
     332           7 :         baseOpt.contentTypeWithRequestBody(_method);
     333             :     return requestOptions;
     334             :   }
     335             : 
     336             :   /// Http method.
     337             :   String? method;
     338             : 
     339             :   /// Http request headers. The keys of initial headers will be converted to lowercase,
     340             :   /// for example 'Content-Type' will be converted to 'content-type'.
     341             :   ///
     342             :   /// The key of Header Map is case-insensitive, eg: content-type and Content-Type are
     343             :   /// regard as the same key.
     344             :   Map<String, dynamic>? headers;
     345             : 
     346             :   /// Timeout in milliseconds for sending data.
     347             :   /// [Dio] will throw the [DioError] with [DioErrorType.sendTimeout] type
     348             :   ///  when time out.
     349             :   int? sendTimeout;
     350             : 
     351             :   ///  Timeout in milliseconds for receiving data.
     352             :   ///
     353             :   ///  Note: [receiveTimeout]  represents a timeout during data transfer! That is to say the
     354             :   ///  client has connected to the server, and the server starts to send data to the client.
     355             :   ///
     356             :   /// [0] meanings no timeout limit.
     357             :   int? receiveTimeout;
     358             : 
     359             :   /// The request Content-Type. The default value is [ContentType.json].
     360             :   /// If you want to encode request body with 'application/x-www-form-urlencoded',
     361             :   /// you can set `ContentType.parse('application/x-www-form-urlencoded')`, and [Dio]
     362             :   /// will automatically encode the request body.
     363             :   String? contentType;
     364             : 
     365             :   /// [responseType] indicates the type of data that the server will respond with
     366             :   /// options which defined in [ResponseType] are `json`, `stream`, `plain`.
     367             :   ///
     368             :   /// The default value is `json`, dio will parse response string to json object automatically
     369             :   /// when the content-type of response is 'application/json'.
     370             :   ///
     371             :   /// If you want to receive response data with binary bytes, for example,
     372             :   /// downloading a image, use `stream`.
     373             :   ///
     374             :   /// If you want to receive the response data with String, use `plain`.
     375             :   ///
     376             :   /// If you want to receive the response data with  original bytes,
     377             :   /// that's to say the type of [Response.data] will be List<int>, use `bytes`
     378             :   ResponseType? responseType;
     379             : 
     380             :   /// `validateStatus` defines whether the request is successful for a given
     381             :   /// HTTP response status code. If `validateStatus` returns `true` ,
     382             :   /// the request will be perceived as successful; otherwise, considered as failed.
     383             :   ValidateStatus? validateStatus;
     384             : 
     385             :   /// Whether receiving response data when http status code is not successful.
     386             :   /// The default value is true
     387             :   bool? receiveDataWhenStatusError;
     388             : 
     389             :   /// Custom field that you can retrieve it later in [Interceptor]、[Transformer] and the [Response] object.
     390             :   Map<String, dynamic>? extra;
     391             : 
     392             :   /// see [HttpClientRequest.followRedirects],
     393             :   /// The default value is true
     394             :   bool? followRedirects;
     395             : 
     396             :   /// Set this property to the maximum number of redirects to follow
     397             :   /// when [followRedirects] is `true`. If this number is exceeded
     398             :   /// an error event will be added with a [RedirectException].
     399             :   ///
     400             :   /// The default value is 5.
     401             :   int? maxRedirects;
     402             : 
     403             :   /// The default request encoder is utf8encoder, you can set custom
     404             :   /// encoder by this option.
     405             :   RequestEncoder? requestEncoder;
     406             : 
     407             :   /// The default response decoder is utf8decoder, you can set custom
     408             :   /// decoder by this option, it will be used in [Transformer].
     409             :   ResponseDecoder? responseDecoder;
     410             : 
     411             :   /// The [listFormat] indicates the format of collection data in request
     412             :   /// query parameters and `x-www-url-encoded` body data.
     413             :   /// Possible values defined in [ListFormat] are `csv`, `ssv`, `tsv`, `pipes`, `multi`, `multiCompatible`.
     414             :   /// The default value is `multi`.
     415             :   ListFormat? listFormat;
     416             : }
     417             : 
     418             : class RequestOptions extends _RequestConfig with OptionsMixin {
     419           9 :   RequestOptions({
     420             :     String? method,
     421             :     int? sendTimeout,
     422             :     int? receiveTimeout,
     423             :     int? connectTimeout,
     424             :     this.data,
     425             :     required this.path,
     426             :     Map<String, dynamic>? queryParameters,
     427             :     this.onReceiveProgress,
     428             :     this.onSendProgress,
     429             :     this.cancelToken,
     430             :     String? baseUrl,
     431             :     Map<String, dynamic>? extra,
     432             :     Map<String, dynamic>? headers,
     433             :     ResponseType? responseType,
     434             :     String? contentType,
     435             :     ValidateStatus? validateStatus,
     436             :     bool? receiveDataWhenStatusError,
     437             :     bool? followRedirects,
     438             :     int? maxRedirects,
     439             :     RequestEncoder? requestEncoder,
     440             :     ResponseDecoder? responseDecoder,
     441             :     ListFormat? listFormat,
     442             :     bool? setRequestContentTypeWhenNoPayload,
     443           9 :   }) : super(
     444             :           method: method,
     445             :           sendTimeout: sendTimeout,
     446             :           receiveTimeout: receiveTimeout,
     447             :           extra: extra,
     448             :           headers: headers,
     449             :           responseType: responseType,
     450             :           contentType: contentType,
     451             :           validateStatus: validateStatus,
     452             :           receiveDataWhenStatusError: receiveDataWhenStatusError,
     453             :           followRedirects: followRedirects,
     454             :           maxRedirects: maxRedirects,
     455             :           requestEncoder: requestEncoder,
     456             :           responseDecoder: responseDecoder,
     457             :           listFormat: listFormat,
     458             :         ) {
     459          11 :     this.queryParameters = queryParameters ?? {};
     460           9 :     this.baseUrl = baseUrl ?? '';
     461           9 :     this.connectTimeout = connectTimeout ?? 0;
     462             :   }
     463             : 
     464             :   /// Create a Option from current instance with merging attributes.
     465           2 :   RequestOptions copyWith({
     466             :     String? method,
     467             :     int? sendTimeout,
     468             :     int? receiveTimeout,
     469             :     int? connectTimeout,
     470             :     String? data,
     471             :     String? path,
     472             :     Map<String, dynamic>? queryParameters,
     473             :     String? baseUrl,
     474             :     ProgressCallback? onReceiveProgress,
     475             :     ProgressCallback? onSendProgress,
     476             :     CancelToken? cancelToken,
     477             :     Map<String, dynamic>? extra,
     478             :     Map<String, dynamic>? headers,
     479             :     ResponseType? responseType,
     480             :     String? contentType,
     481             :     ValidateStatus? validateStatus,
     482             :     bool? receiveDataWhenStatusError,
     483             :     bool? followRedirects,
     484             :     int? maxRedirects,
     485             :     RequestEncoder? requestEncoder,
     486             :     ResponseDecoder? responseDecoder,
     487             :     ListFormat? listFormat,
     488             :     bool? setRequestContentTypeWhenNoPayload,
     489             :   }) {
     490             :     var contentTypeInHeader = headers != null &&
     491           1 :         headers.keys
     492           3 :             .map((e) => e.toLowerCase())
     493           1 :             .contains(Headers.contentTypeHeader);
     494             : 
     495             :     assert(
     496           1 :       !(contentType != null && contentTypeInHeader),
     497             :       'You cannot set both contentType param and a content-type header',
     498             :     );
     499             : 
     500           2 :     var ro = RequestOptions(
     501           2 :       method: method ?? this.method,
     502           2 :       sendTimeout: sendTimeout ?? this.sendTimeout,
     503           2 :       receiveTimeout: receiveTimeout ?? this.receiveTimeout,
     504           2 :       connectTimeout: connectTimeout ?? this.connectTimeout,
     505           2 :       data: data ?? this.data,
     506           1 :       path: path ?? this.path,
     507           2 :       baseUrl: baseUrl ?? this.baseUrl,
     508           4 :       queryParameters: queryParameters ?? Map.from(this.queryParameters),
     509           2 :       onReceiveProgress: onReceiveProgress ?? this.onReceiveProgress,
     510           2 :       onSendProgress: onSendProgress ?? this.onSendProgress,
     511           2 :       cancelToken: cancelToken ?? this.cancelToken,
     512           4 :       extra: extra ?? Map.from(this.extra),
     513           4 :       headers: headers ?? Map.from(this.headers),
     514           2 :       responseType: responseType ?? this.responseType,
     515           2 :       validateStatus: validateStatus ?? this.validateStatus,
     516             :       receiveDataWhenStatusError:
     517           2 :           receiveDataWhenStatusError ?? this.receiveDataWhenStatusError,
     518           2 :       followRedirects: followRedirects ?? this.followRedirects,
     519           2 :       maxRedirects: maxRedirects ?? this.maxRedirects,
     520           2 :       requestEncoder: requestEncoder ?? this.requestEncoder,
     521           2 :       responseDecoder: responseDecoder ?? this.responseDecoder,
     522           2 :       listFormat: listFormat ?? this.listFormat,
     523             :     );
     524             : 
     525             :     if (contentType != null) {
     526           2 :       ro.headers.remove(Headers.contentTypeHeader);
     527           1 :       ro.contentType = contentType;
     528             :     } else if (!contentTypeInHeader) {
     529           4 :       ro.contentType = this.contentType;
     530             :     }
     531             : 
     532             :     return ro;
     533             :   }
     534             : 
     535             :   /// generate uri
     536           8 :   Uri get uri {
     537           8 :     var _url = path;
     538          16 :     if (!_url.startsWith(RegExp(r'https?:'))) {
     539          14 :       _url = baseUrl + _url;
     540           7 :       var s = _url.split(':/');
     541          14 :       if (s.length == 2) {
     542          35 :         _url = s[0] + ':/' + s[1].replaceAll('//', '/');
     543             :       }
     544             :     }
     545          24 :     var query = Transformer.urlEncodeMap(queryParameters, listFormat);
     546           8 :     if (query.isNotEmpty) {
     547           3 :       _url += (_url.contains('?') ? '&' : '?') + query;
     548             :     }
     549             :     // Normalize the url.
     550          16 :     return Uri.parse(_url).normalizePath();
     551             :   }
     552             : 
     553             :   /// Request data, can be any type.
     554             :   ///
     555             :   /// When using `x-www-url-encoded` body data,
     556             :   /// List values use the default [ListFormat.multi].
     557             :   ///
     558             :   /// The value can be overridden per value by adding a [MultiParam]
     559             :   /// object wrapping the actual List value and the desired format.
     560             :   dynamic data;
     561             : 
     562             :   /// If the `path` starts with 'http(s)', the `baseURL` will be ignored, otherwise,
     563             :   /// it will be combined and then resolved with the baseUrl.
     564             :   String path;
     565             : 
     566             :   CancelToken? cancelToken;
     567             : 
     568             :   ProgressCallback? onReceiveProgress;
     569             : 
     570             :   ProgressCallback? onSendProgress;
     571             : }
     572             : 
     573             : /// The [_RequestConfig] class describes the http request information and configuration.
     574             : class _RequestConfig {
     575           9 :   _RequestConfig({
     576             :     int? receiveTimeout,
     577             :     int? sendTimeout,
     578             :     String? method,
     579             :     Map<String, dynamic>? extra,
     580             :     Map<String, dynamic>? headers,
     581             :     String? contentType,
     582             :     ListFormat? listFormat,
     583             :     bool? followRedirects,
     584             :     int? maxRedirects,
     585             :     bool? receiveDataWhenStatusError,
     586             :     ValidateStatus? validateStatus,
     587             :     ResponseType? responseType,
     588             :     this.requestEncoder,
     589             :     this.responseDecoder,
     590             :   }) {
     591           9 :     this.headers = headers;
     592             : 
     593             :     var contentTypeInHeader =
     594          18 :         this.headers.containsKey(Headers.contentTypeHeader);
     595             :     assert(
     596           0 :       !(contentType != null && contentTypeInHeader) ||
     597           3 :           this.headers[Headers.contentTypeHeader] == contentType,
     598             :       'You cannot set different values for contentType param and a content-type header',
     599             :     );
     600             : 
     601           9 :     this.method = method ?? 'GET';
     602           9 :     this.sendTimeout = sendTimeout ?? 0;
     603           9 :     this.receiveTimeout = receiveTimeout ?? 0;
     604           9 :     this.listFormat = listFormat ?? ListFormat.multi;
     605          18 :     this.extra = extra ?? {};
     606           9 :     this.followRedirects = followRedirects ?? true;
     607           9 :     this.maxRedirects = maxRedirects ?? 5;
     608           9 :     this.receiveDataWhenStatusError = receiveDataWhenStatusError ?? true;
     609           9 :     this.validateStatus = validateStatus ??
     610           7 :         (int? status) {
     611          14 :           return status != null && status >= 200 && status < 300;
     612             :         };
     613           9 :     this.responseType = responseType ?? ResponseType.json;
     614             :     if (!contentTypeInHeader) {
     615           9 :       this.contentType = contentType ?? Headers.jsonContentType;
     616             :     }
     617             :   }
     618             : 
     619             :   /// Http method.
     620             :   late String method;
     621             : 
     622             :   /// Http request headers. The keys of initial headers will be converted to lowercase,
     623             :   /// for example 'Content-Type' will be converted to 'content-type'.
     624             :   ///
     625             :   /// The key of Header Map is case-insensitive, eg: content-type and Content-Type are
     626             :   /// regard as the same key.
     627             : 
     628          18 :   Map<String, dynamic> get headers => _headers;
     629             :   late Map<String, dynamic> _headers;
     630             : 
     631           9 :   set headers(Map<String, dynamic>? headers) {
     632          18 :     _headers = caseInsensitiveKeyMap(headers);
     633           9 :     if (_defaultContentType != null &&
     634           2 :         !_headers.containsKey(Headers.contentTypeHeader)) {
     635           3 :       _headers[Headers.contentTypeHeader] = _defaultContentType;
     636             :     }
     637             :   }
     638             : 
     639             :   /// Timeout in milliseconds for sending data.
     640             :   /// [Dio] will throw the [DioError] with [DioErrorType.sendTimeout] type
     641             :   ///  when time out.
     642             :   late int sendTimeout;
     643             : 
     644             :   ///  Timeout in milliseconds for receiving data.
     645             :   ///
     646             :   ///  Note: [receiveTimeout]  represents a timeout during data transfer! That is to say the
     647             :   ///  client has connected to the server, and the server starts to send data to the client.
     648             :   ///
     649             :   /// [0] meanings no timeout limit.
     650             :   late int receiveTimeout;
     651             : 
     652             :   /// The request Content-Type. The default value is [ContentType.json].
     653             :   /// If you want to encode request body with 'application/x-www-form-urlencoded',
     654             :   /// you can set `ContentType.parse('application/x-www-form-urlencoded')`, and [Dio]
     655             :   /// will automatically encode the request body.
     656           9 :   set contentType(String? contentType) {
     657             :     if (contentType != null) {
     658          18 :       _headers[Headers.contentTypeHeader] =
     659          18 :           _defaultContentType = contentType.trim();
     660             :     } else {
     661           7 :       _defaultContentType = null;
     662          14 :       _headers.remove(Headers.contentTypeHeader);
     663             :     }
     664             :   }
     665             : 
     666             :   String? _defaultContentType;
     667             : 
     668           9 :   String? get contentType => _headers[Headers.contentTypeHeader] as String?;
     669             : 
     670             :   /// [responseType] indicates the type of data that the server will respond with
     671             :   /// options which defined in [ResponseType] are `json`, `stream`, `plain`.
     672             :   ///
     673             :   /// The default value is `json`, dio will parse response string to json object automatically
     674             :   /// when the content-type of response is 'application/json'.
     675             :   ///
     676             :   /// If you want to receive response data with binary bytes, for example,
     677             :   /// downloading a image, use `stream`.
     678             :   ///
     679             :   /// If you want to receive the response data with String, use `plain`.
     680             :   ///
     681             :   /// If you want to receive the response data with  original bytes,
     682             :   /// that's to say the type of [Response.data] will be List<int>, use `bytes`
     683             :   late ResponseType responseType;
     684             : 
     685             :   /// `validateStatus` defines whether the request is successful for a given
     686             :   /// HTTP response status code. If `validateStatus` returns `true` ,
     687             :   /// the request will be perceived as successful; otherwise, considered as failed.
     688             :   late ValidateStatus validateStatus;
     689             : 
     690             :   /// Whether receiving response data when http status code is not successful.
     691             :   /// The default value is true
     692             :   late bool receiveDataWhenStatusError;
     693             : 
     694             :   /// Custom field that you can retrieve it later in [Interceptor]、[Transformer] and the [Response] object.
     695             :   late Map<String, dynamic> extra;
     696             : 
     697             :   /// see [HttpClientRequest.followRedirects],
     698             :   /// The default value is true
     699             :   late bool followRedirects;
     700             : 
     701             :   /// Set this property to the maximum number of redirects to follow
     702             :   /// when [followRedirects] is `true`. If this number is exceeded
     703             :   /// an error event will be added with a [RedirectException].
     704             :   ///
     705             :   /// The default value is 5.
     706             :   late int maxRedirects;
     707             : 
     708             :   /// The default request encoder is utf8encoder, you can set custom
     709             :   /// encoder by this option.
     710             :   RequestEncoder? requestEncoder;
     711             : 
     712             :   /// The default response decoder is utf8decoder, you can set custom
     713             :   /// decoder by this option, it will be used in [Transformer].
     714             :   ResponseDecoder? responseDecoder;
     715             : 
     716             :   /// The [listFormat] indicates the format of collection data in request
     717             :   /// query parameters and `x-www-url-encoded` body data.
     718             :   /// Possible values defined in [ListFormat] are `csv`, `ssv`, `tsv`, `pipes`, `multi`, `multiCompatible`.
     719             :   /// The default value is `multi`.
     720             :   ///
     721             :   /// The value can be overridden per parameter by adding a [MultiParam]
     722             :   /// object to the query or body data map.
     723             :   late ListFormat listFormat;
     724             : }

Generated by: LCOV version 1.14