loadWebPage function

Future<WebPage> loadWebPage(
  1. Client client,
  2. Uri uri, {
  3. required Duration timeout,
  4. required int maxBytes,
  5. Map<String, String>? headers,
})

Fetches uri with a browser profile, following redirects and capping the body at maxBytes (omp's loadPage, reduced: no user-agent rotation or 429 retry — the tool surfaces failures directly).

Implementation

Future<WebPage> loadWebPage(
  http.Client client,
  Uri uri, {
  required Duration timeout,
  required int maxBytes,
  Map<String, String>? headers,
}) async {
  final request = http.Request('GET', uri)
    ..followRedirects = true
    ..maxRedirects = 5
    ..headers.addAll({
      'User-Agent': webSearchUserAgent,
      'Accept':
          'text/html,application/xhtml+xml,application/xml;q=0.9,'
          'text/plain;q=0.8,*/*;q=0.5',
      'Accept-Language': 'en-US,en;q=0.5',
    });
  if (headers != null) request.headers.addAll(headers);

  final response = await client.send(request).timeout(timeout);
  final rawContentType = response.headers['content-type'] ?? '';
  final contentType = rawContentType.split(';').first.trim().toLowerCase();

  final chunks = <int>[];
  var truncated = false;
  await for (final chunk in response.stream.timeout(timeout)) {
    final remaining = maxBytes - chunks.length;
    if (chunk.length > remaining) {
      chunks.addAll(chunk.sublist(0, remaining));
      truncated = true;
      break;
    }
    chunks.addAll(chunk);
  }

  return WebPage(
    url: uri,
    finalUrl: response.request?.url ?? uri,
    statusCode: response.statusCode,
    contentType: contentType,
    body: _decodeBody(chunks, rawContentType),
    truncated: truncated,
  );
}