Ga naar de inhoud

Smart HTTP

Pitmaster communiceert met git-servers via HTTPS met het smart HTTP-protocol. Dit is het primaire netwerktransport. Het gebruikt de native streamfuncties van PHP (fopen met een streamcontext) voor HTTP-verzoeken, dus allow_url_fopen moet zijn ingeschakeld.

SmartHttpClient

PHP
use Pitmaster\Protocol\SmartHttpClient;

$http = new SmartHttpClient();
// Or with custom timeout:
$http = new SmartHttpClient(timeout: 60);

De time-out is standaard de constante PITMASTER_HTTP_TIMEOUT (een geheel getal), of 30 seconden als deze niet is gedefinieerd.

Refs ontdekken

PHP
$discovery = $http->discoverRefs('https://github.com/user/repo.git');

foreach ($discovery->refs() as $name => $id) {
    echo "{$id->hex} {$name}\n";
}

// HEAD symref (e.g., 'refs/heads/main')
$defaultBranch = $discovery->headSymref();

// Specific ref
$mainId = $discovery->ref('refs/heads/main');

// Server capabilities (a Capability object, or null)
$caps = $discovery->capabilities();

discoverReceivePackRefs() doet hetzelfde voor git-receive-pack. Het verzoek voor ref-discovery gaat naar:

Code
GET <url>/info/refs?service=git-upload-pack

De reactie is een met pkt-line gecodeerde lijst met refs, met capabilities op de eerste regel.

Upload pack (fetch)

PHP
$response = $http->uploadPack($url, $requestBody);

Verstuurt een POST naar <url>/git-upload-pack met de body voor de want/have-onderhandeling. Geeft de ruwe responsebody terug (pkt-lines, NAK en side-band-data). UploadPackClient bouwt het verzoek op en haalt de pack eruit:

PHP
use Pitmaster\Protocol\UploadPackClient;

$client = new UploadPackClient($http);
$packData = $client->fetch($url, $wants, $haves);   // ObjectId[] wants and haves

Receive pack (push)

PHP
$response = $http->receivePack($url, $requestBody);

Verstuurt een POST naar <url>/git-receive-pack met de ref-updateopdrachten en pack-data.

PktLine-codering

Het git-protocol gebruikt pkt-line-framing voor alle communicatie. Elke regel begint met de totale lengte (inclusief het voorvoegsel van 4 bytes), gecodeerd als 4 hexadecimale cijfers.

PHP
use Pitmaster\Protocol\PktLine;

// Encode a single line
$encoded = PktLine::encode("want abc123def456\n");
// "0016want abc123def456\n"

// Flush packet (end of section)
$flush = PktLine::flush();
// "0000"

// Delimiter packet (protocol v2)
$delim = PktLine::delimiter();
// "0001"

// Decode a stream
$lines = PktLine::decode($rawData);
// Each element is: string (data), null (flush), or false (delimiter)

Lengteregels

  • Minimale gegevensregel: 0005 (payload van 1 byte)
  • Maximale gegevensregel: fff0 (payload van 65516 bytes)
  • Flush-pakket: 0000
  • Scheidingstekenpakket: 0001
  • Einde van de response: 0002 (protocol v2; verwerkt door ProtocolV2::decode(), terwijl PktLine::decode() het weigert)
PHP
PktLine::MAX_PAYLOAD;  // 65516 (65520 - 4)

Ref-discovery

De klasse RefDiscovery parseert de ref-advertentie van de server.

PHP
use Pitmaster\Protocol\RefDiscovery;

$discovery = RefDiscovery::parse($pktLines);

// All refs
$refs = $discovery->refs();
// ['refs/heads/main' => ObjectId, 'refs/tags/v1.0' => ObjectId, ...]

// Single ref
$id = $discovery->ref('refs/heads/main');

// HEAD symbolic ref (from capabilities)
$symref = $discovery->headSymref();
// 'refs/heads/main' or null

// Server capabilities
$caps = $discovery->capabilities();
// Capability object (see below), or null

Indeling van de ref-advertentie

De eerste regel van de advertentie bevat capabilities:

Code
<hash> HEAD\0<capability list>\n
<hash> refs/heads/main\n
<hash> refs/tags/v1.0\n
0000

Capabilities

De klasse Capability parseert en beheert protocol-capabilities.

PHP
use Pitmaster\Protocol\Capability;

$caps = Capability::parse('thin-pack side-band-64k ofs-delta symref=HEAD:refs/heads/main');

$caps->has('thin-pack');           // true
$caps->get('symref');              // 'HEAD:refs/heads/main'
$caps->all();                      // ['thin-pack' => null, ..., 'symref' => 'HEAD:refs/heads/main']

Veelgebruikte capabilities

Capability Betekenis
multi_ack De server ondersteunt multi-ack-onderhandeling
thin-pack De server verstuurt thin packs (basisobjecten kunnen ontbreken). Pitmaster vraagt hierom, maar kan thin packs nog niet indexeren (#16)
side-band De server gebruikt side-band voor pack-data (beperkt tot 1000 bytes)
side-band-64k De server gebruikt 64K side-band voor pack-data
ofs-delta Pack kan OFS_DELTA-objecten gebruiken
shallow De server ondersteunt shallow clone
no-done De server vereist geen "done"-regel
symref=HEAD:refs/heads/main Symbolisch doel van HEAD
agent=git/2.45.0 Git-versie van de server

Side-band-demultiplexing

Wanneer de server side-band gebruikt, wordt de pack-data gemultiplexed met voortgangs- en foutmeldingen. De eerste byte van de payload van elke pkt-line geeft het kanaal aan:

Kanaal Betekenis
1 Pack-data
2 Voortgangsberichten (stderr)
3 Fatale foutmeldingen

Pitmaster's UploadPackClient verwijdert de kanaalbytes en voegt de pack-data weer samen.

Protocolversies

v1 (standaard)

Het traditionele protocol. Ref-discovery verstuurt alle refs tegelijk. Pitmaster onderhandelt in één ronde: het verstuurt zijn wants, elke lokale ref-tip als een have en done.

v2

Een eenvoudiger protocol met betere prestaties.

Belangrijkste verschillen met v1:

  • Ref-discovery is een afzonderlijke opdracht ls-refs (kan refs filteren)
  • Fetch is één opdracht fetch met gestructureerde parameters
  • Gebruikt scheidingstekenpakketten (0001) om secties van elkaar te scheiden

clone() en fetch() gebruiken altijd v1. v2 is beschikbaar wanneer u het expliciet aanroept:

PHP
$discovery = $http->discoverRefsV2($url);       // ls-refs
$packData = (new UploadPackClient($http))->fetchV2($url, $wants, $haves);

Verzoekstroom van HTTP

Clone/fetch

Code
1. GET  /info/refs?service=git-upload-pack
   Response: pkt-line encoded ref list

2. POST /git-upload-pack
   Request:  want <hash>\n ... have <hash>\n ... done\n
   Response: NAK\n + pack data (possibly side-band wrapped)

Push

Code
1. GET  /info/refs?service=git-receive-pack
   Response: pkt-line encoded ref list

2. POST /git-receive-pack
   Request:  <old-hash> <new-hash> refs/heads/main\0<capabilities>\n
             0000
             PACK<pack data>
   Response: unpack ok\n + ref status lines

Foutafhandeling

Netwerkfouten gooien ProtocolException. Wanneer de smart HTTP-uitwisseling van clone() of fetch() mislukt, probeert Pitmaster het opnieuw via dumb HTTP en gooit het de oorspronkelijke fout opnieuw als ook dat mislukt. Andere fouten (een onbekende remote, een handle zonder proces, een pack die niet kan worden geïndexeerd) gooien andere uitzonderingstypen:

PHP
use Pitmaster\Exceptions\ProtocolException;

try {
    $repo->fetch();
} catch (ProtocolException $e) {
    echo "Network error: {$e->getMessage()}\n";
}

Veelvoorkomende fouten:

  • Server onbereikbaar (time-out)
  • Authenticatie vereist of repository niet gevonden (gemeld als Unexpected HTTP status 401, 403 of 404)
  • Onverwachte Content-Type in de response
  • Ongeldige pkt-line-data
  • Foutmelding via side-band-kanaal