Uploading een video van twee gigabyte via de wifi van een koffietent is een oefening in optimisme. Je ziet de voortgangsbalk langzaam richting de zeventig procent kruipen, en dan hapert de verbinding. De upload mislukt. Wanneer je het opnieuw probeert, verwacht de server een gloednieuw bestand. Je begint weer bij nul. Voor iedereen die een applicatie bouwt die door gebruikers gegenereerde video's verwerkt, is dit geen uitzondering. Het is de norm. Het tus-protocol is specifiek ontwikkeld om dit probleem op te lossen. Het is een open standaard die over gewoon HTTP draait en uploads een geheugen geeft. Zodra het netwerk herstelt, wordt de bestandsoverdracht precies hervat waar deze was gebleven.
Waarom standaard uploads mislukken
Standaard multipart-bestandsuploads behandelen de volledige payload als één enkele transactie. De browser of app opent een TCP-verbinding, streamt de bytes en verwacht aan het einde een 200 OK. Als de verbinding wordt verbroken omdat de gebruiker is overgeschakeld van LTE naar wifi, of omdat de laptop in slaapstand is gegaan, heeft de server geen manier om te weten welke bytes veilig zijn aangekomen. De meeste frameworks gooien de gedeeltelijke gegevens simpelweg weg. De gebruiker blijft achter met een mislukt formulier en een slecht humeur. Videobestanden vergroten de pijn omdat ze groot zijn, vaak worden geüpload vanaf mobiele apparaten op onstabiele netwerken, en vaak zijn gecodeerd in formaten die pas verwerkt kunnen worden als het volledige bestand intact is.
Hoe Tus het spel verandert
Tus heroverweegt de upload als een stateful gesprek in plaats van een eenmalige levering. In plaats van een bestand in één continue stroom van bytes te sturen, verdeelt de client de payload in chunks. Belangrijker nog is dat de server de offset onthoudt, het exacte aantal bytes dat tot nu toe is ontvangen. Deze state-persistentie is wat hervatting mogelijk maakt. Het protocol is opzettelijk eenvoudig. Het vereist geen WebSockets, gRPC of propriëtaire SDK's. Het maakt gebruik van de HTTP-methoden die je al kent.
De drie verzoeken die hervatting mogelijk maken
Elke tus-upload volgt een voorspelbare dans.
Eerst stuurt de client een POST-verzoek naar een bekend tus-endpoint. De headers beschrijven het bestand. De Upload-Length-header geeft de uiteindelijke grootte in bytes aan, en optionele metadata zoals de bestandsnaam of het contenttype wordt verzonden in de Upload-Metadata-header als een met komma's gescheiden lijst van base64-gecodeerde sleutel-waarde paren. De server maakt een leeg upload-resource aan en reageert met een 201 Created-status plus een Location-header die naar een unieke URL verwijst. Deze URL is het adres van de upload voor de rest van zijn bestaan.
Vervolgens komt het PATCH-verzoek. De client stuurt chunks van ruwe binaire gegevens naar die unieke URL. Twee cruciale headers begeleiden de payload. Content-Type moet application/offset+octet-stream zijn, en Upload-Offset moet overeenkomen met de bytepositie waar deze chunk begint. De server controleert of de offset overeenkomt met zijn eigen gegevens. Als dat niet het geval is, geeft de server een 409 Conflict terug, om corruptie van de status te voorkomen. Als alles klopt, voegt de server de bytes toe, werkt hij zijn interne offset bij en geeft hij een 204 No Content-antwoord terug samen met de nieuwe Upload-Offset. De chunkgrootte is configureerbaar, maar in de praktijk ligt deze meestal ergens tussen een paar honderd kilobytes en een paar megabytes. Kleinere chunks zorgen voor meer HTTP-overhead maar herstellen sneller van fouten. Grotere chunks verminderen het aantal round trips, maar verspillen meer bandbreedte als ze halverwege mislukken.
Ten slotte het HEAD-verzoek. Dit is het vangnet. Als een PATCH halverwege een chunk mislukt, bijvoorbeeld na drie megabyte van een segment van vijf megabyte, wordt de verbinding verbroken. Zodra de client weer toegang heeft tot het netwerk, stuurt hij een HEAD-verzoek naar de upload-URL. De server antwoordt met de huidige Upload-Offset. De client vergelijkt
