Send Session: Outgoing Transfer Orchestration
This module traces a single outgoing transfer from SendNotifier.startSession() — which registers device info and negotiates prepare-upload with the target, including PIN retry — through the per-file isolate dispatch that streams bytes via HttpUploadService.postStream(). It highlights the two distinct Rust bridges the Dart app leans on: the FRB-generated RsHttpClient for control-plane calls, and the rhttp package's Rust client for the actual cert-pinned HTTPS byte stream. Understanding this hand-off is key to seeing where pure-Dart orchestration ends and the native TLS/cert-pinning core takes over.
Handing bytes off to the native HTTP client
common/lib/src/task/upload/http_upload.dart · lines 16–42upload() takes the raw byte stream plus everything needed to address the request: the target device, the remote session/file identifiers, the per-file upload token, and progress/cancel hooks passed down from the isolate.
It calls _client.postStream() — the CustomHttpClient abstraction — building the /upload URL via ApiRoute and passing sessionId/fileId/token as query params plus Content-Length/Content-Type headers.
The actual byte stream, progress callback, and cancel token are handed straight through — this is the exact point where pure-Dart orchestration hands off to whatever concrete client implements postStream (RhttpWrapper, backed by Rust).
Future<void> upload({ required Stream<List<int>> stream, required int contentLength, required String contentType, required Device target, required String? remoteSessionId, required String fileId, required String token, required void Function(double) onSendProgress, required CustomCancelToken cancelToken, }) async { await _client.postStream( uri: ApiRoute.upload.target(target), query: { if (remoteSessionId != null) 'sessionId': remoteSessionId, 'fileId': fileId, 'token': token, }, headers: { 'Content-Length': contentLength.toString(), 'Content-Type': contentType, }, stream: stream, onSendProgress: onSendProgress, cancelToken: cancelToken, ); }
RhttpClient createRhttpClient(Duration timeout, StoredSecurityContext securityContext, {Interceptor? interceptor}) { return RhttpClient.createSync( settings: ClientSettings( timeoutSettings: TimeoutSettings( timeout: timeout, ), tlsSettings: TlsSettings( verifyCertificates: false, clientCertificate: ClientCertificate( certificate: securityContext.certificate, privateKey: securityContext.privateKey, ), ), ), interceptors: interceptor != null ? [interceptor] : [], );}
app/lib/util/rhttp.dart · lines 70–86Check your understanding
Answered in place — nothing is graded, everything is explained. 0 / 3 passed
In SendNotifier.startSession(), what happens when client.prepareUpload() throws a status-401 error?
Which call is actually responsible for streaming a file's bytes to the receiver over HTTPS?
Why does createRhttpClient() set verifyCertificates: false while still attaching a client certificate?