performRequest method
Implementation
@override
Future<FittorResponse> performRequest(
FittorRequest request, Stopwatch stopwatch) async {
try {
// Create HTTP request using the full URI to preserve scheme (HTTP/HTTPS)
final HttpClientRequest httpRequest = await _httpClient.openUrl(
request.methodName,
request.uri,
);
// Set timeout
final timeout = request.timeout ?? const Duration(seconds: 30);
// Set headers
request.headers.toMultiMap().forEach((key, values) {
for (final value in values) {
httpRequest.headers.add(key, value);
}
});
// Set follow redirects
httpRequest.followRedirects = request.followRedirects;
httpRequest.maxRedirects = request.maxRedirects;
// Write body if present
if (request.body != null) {
if (request.body is String) {
httpRequest.write(request.body);
} else if (request.body is List<int>) {
httpRequest.add(request.body);
} else {
httpRequest.write(request.body.toString());
}
}
// Send request and get response with timeout
final httpResponse = await httpRequest.close().timeout(timeout);
// Read response body
final bodyBytes = await httpResponse.fold<List<int>>(
<int>[],
(previous, element) => previous..addAll(element),
);
stopwatch.stop();
// Build response headers
final responseHeaders = FittorHeaders();
httpResponse.headers.forEach((key, values) {
for (final value in values) {
responseHeaders.add(key, value);
}
});
return FittorResponse(
statusCode: httpResponse.statusCode,
statusMessage: httpResponse.reasonPhrase,
headers: responseHeaders,
bodyBytes: Uint8List.fromList(bodyBytes),
requestDuration: stopwatch.elapsed,
);
} on SocketException catch (e) {
stopwatch.stop();
throw FittorNetworkException('Socket error: ${e.message}', e);
} on TimeoutException catch (e) {
stopwatch.stop();
throw FittorTimeoutException(
'Request timeout', request.timeout ?? const Duration(seconds: 30), e);
} catch (e) {
stopwatch.stop();
throw FittorNetworkException('Request failed: $e', e);
}
}