Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/lib/task/backend.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'dart:typed_data';

import 'package:_pub_shared/data/task_api.dart' as api;
import 'package:_pub_shared/data/task_payload.dart';
import 'package:_pub_shared/worker/limits.dart';
import 'package:chunked_stream/chunked_stream.dart' show MaximumSizeExceeded;
import 'package:clock/clock.dart';
import 'package:collection/collection.dart';
Expand Down Expand Up @@ -788,7 +789,7 @@ class TaskBackend {
try {
return await _bucket.readAsBytes(
path, offset: offset, length: length,
maxSize: 10 * 1024 * 1024, // sanity limit
maxSize: blobContentSizeLimit, // sanity limit
);
} on DetailedApiRequestError catch (e) {
if (e.status == 404) {
Expand Down
6 changes: 6 additions & 0 deletions pkg/_pub_shared/lib/worker/limits.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// The maximum size of the compressed blob content that we want to store and serve.
const blobContentSizeLimit = 10 * 1024 * 1024;
21 changes: 20 additions & 1 deletion pkg/indexed_blob/lib/indexed_blob.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,36 @@ final class IndexedBlobBuilder {
/// This cannot be called concurrently, callers must await this operation
/// being completed.
///
/// When [skipAfterSize] is set, the blob file may contain the streamed content
/// up to the specified number of bytes, but will skip updating the index file
/// after the threshold is reached.
///
/// If an exception is thrown generated blob is not valid.
Future<void> addFile(String path, Stream<List<int>> content) async {
Future<void> addFile(
String path,
Stream<List<int>> content, {
int skipAfterSize = 0,
}) async {
_checkState();
try {
_isAdding = true;
final start = _offset;
var totalSize = 0;
await _blob.addStream(content.map((chunk) {
totalSize += chunk.length;
if (skipAfterSize > 0 && totalSize > skipAfterSize) {
// Do not store the remaining chunks, we will not store the entry.
return const [];
}

_offset += chunk.length;
return chunk;
}));

if (skipAfterSize > 0 && totalSize > skipAfterSize) {
return;
}

var target = _index;
final segments = path.split('/');
for (var i = 0; i < segments.length - 1; i++) {
Expand Down
41 changes: 41 additions & 0 deletions pkg/indexed_blob/test/blob_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:convert';
import 'dart:io';

Expand Down Expand Up @@ -101,4 +102,44 @@ void main() {
final files = index.files.toList();
expect(files, hasLength(5));
});

test('size limit', () async {
final controller = StreamController<List<int>>();
final result = controller.stream.toList();
final b = IndexedBlobBuilder(controller);
await b.addFile(
'a',
Stream.value([0, 1]),
skipAfterSize: 3,
);
await b.addFile(
'b',
Stream.fromIterable([
[0],
[1, 2, 3], // will be removed,
]),
skipAfterSize: 3,
);
await b.addFile(
'c',
Stream.value([8, 9]),
skipAfterSize: 3,
);
final index = await b.buildIndex('1');
final files = index.files.toList();
expect(files, hasLength(2));
await controller.close();
expect(await result, [
[0, 1],
[0],
[],
[8, 9],
]);

expect(index.lookup('b'), isNull);

final c = index.lookup('c')!;
expect(c.start, 3);
expect(c.end, 5);
});
}
7 changes: 6 additions & 1 deletion pkg/pub_worker/lib/src/analyze.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'dart:isolate' show Isolate;

import 'package:_pub_shared/data/task_payload.dart';
import 'package:_pub_shared/pubapi.dart';
import 'package:_pub_shared/worker/limits.dart';
import 'package:api_builder/api_builder.dart';
import 'package:clock/clock.dart' show clock;
import 'package:http/http.dart' show Client, ClientException;
Expand Down Expand Up @@ -201,7 +202,11 @@ Future<void> _analyzePackage(
continue; // We'll add this at the very end!
}
try {
await builder.addFile(path, f.openRead().transform(gzip.encoder));
await builder.addFile(
path,
f.openRead().transform(gzip.encoder),
skipAfterSize: blobContentSizeLimit,
);
} on IOException {
log.writeln('ERROR: Failed to read output file at "$path"');
}
Expand Down