Gå til indhold

Smart HTTP

Pitmaster kommunikerer med git-servere over HTTPS ved hjælp af smart HTTP-protokollen. Dette er den primære netværkstransport. Den bruger PHPs native stream-funktioner (fopen med en stream-kontekst) til HTTP-anmodninger, så allow_url_fopen skal være aktiveret.

SmartHttpClient

PHP
use Pitmaster\Protocol\SmartHttpClient;

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

Timeouten er som standard konstanten PITMASTER_HTTP_TIMEOUT (et heltal) eller 30 sekunder, hvis den ikke er defineret.

Find referencer

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() gør det samme for git-receive-pack. Referenceopdagelsesanmodningen sendes til:

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

Svaret er en pkt-line-kodet liste over referencer med funktioner på den første linje.

Upload af pakke (fetch)

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

Sender en POST til <url>/git-upload-pack med kroppen, der indeholder want/have-forhandlingen. Returnerer den rå svarbody (pkt-lines, NAK og side-band-data). UploadPackClient opbygger anmodningen og udtrækker pakken:

PHP
use Pitmaster\Protocol\UploadPackClient;

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

Modtagelse af pakke (push)

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

Sender en POST til <url>/git-receive-pack med kommandoerne til referenceopdatering og pakkedataene.

PktLine-kodning

git-protokollen bruger pkt-line-indramning til al kommunikation. Hver linje indledes med dens samlede længde (inklusive det 4-byte lange længdepræfiks), kodet som 4 hexadecimale cifre.

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)

Regler for længde

  • Minimum for datalinje: 0005 (1 byte data)
  • Maksimum for datalinje: fff0 (65516 bytes data)
  • Flush-pakke: 0000
  • Afgrænsningspakke: 0001
  • Svarafslutning: 0002 (protokol v2; håndteres af ProtocolV2::decode(), mens PktLine::decode() afviser den)
PHP
PktLine::MAX_PAYLOAD;  // 65516 (65520 - 4)

Referenceopdagelse

Klassen RefDiscovery fortolker serverens referenceannoncering.

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

Format for referenceannoncering

Den første linje i annonceringen indeholder funktioner:

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

Funktioner

Klassen Capability fortolker og administrerer protokolfunktioner.

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']

Almindelige funktioner

Funktion Betydning
multi_ack Serveren understøtter multi-ack-forhandling
thin-pack Serveren sender tynde pakker (basisobjekter kan være udeladt). Pitmaster anmoder om det, men kan endnu ikke indeksere tynde pakker (#16)
side-band Serveren bruger side-band til pakkedata (begrænset til 1000 bytes)
side-band-64k Serveren bruger 64K side-band til pakkedata
ofs-delta Pakken kan bruge OFS_DELTA-objekter
shallow Serveren understøtter overfladisk kloning
no-done Serveren kræver ikke en "done"-linje
symref=HEAD:refs/heads/main HEADs symbolske mål
agent=git/2.45.0 Serverens Git-version

Demultipleksning af side-band

Når serveren bruger side-band, multiplexes pakkedata med status- og fejlmeddelelser. Den første byte i hver pkt-line-payload angiver kanalen:

Kanal Betydning
1 Pakkedata
2 Statusmeddelelser (stderr)
3 Kritiske fejlmeddelelser

Pitmasters UploadPackClient fjerner kanalbytes og samler pakkedataene igen.

Protokolversioner

v1 (standard)

Den traditionelle protokol. Referenceopdagelsen sender alle referencer på én gang. Pitmaster forhandler i én runde: den sender sine wants, alle lokale reference-spidser som have samt done.

v2

En enklere protokol med bedre ydeevne.

Vigtige forskelle fra v1:

  • Referenceopdagelse er en separat kommando af typen ls-refs (kan filtrere referencer)
  • Fetch er én kommando af typen fetch med strukturerede parametre
  • Bruger afgrænsningspakker (0001) til at adskille sektioner

clone() og fetch() bruger altid v1. v2 er tilgængelig, når du kalder den eksplicit:

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

Anmodningsforløb for HTTP

Clone/fetch

Kode
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

Kode
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

Fejlhåndtering

Netværksfejl kaster ProtocolException. Hvis udvekslingen via smart HTTP under clone() eller fetch() mislykkes, forsøger Pitmaster igen via dumb HTTP og kaster den oprindelige fejl igen, hvis det også mislykkes. Andre fejl (ukendt fjernlager, handle uden proces, pakke, der ikke kan indekseres) kaster andre undtagelsestyper:

PHP
use Pitmaster\Exceptions\ProtocolException;

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

Almindelige fejl:

  • Serveren kan ikke nås (timeout)
  • Godkendelse påkrævet, eller arkivet blev ikke fundet (rapporteres som Unexpected HTTP status 401, 403 eller 404)
  • Uventet Content-Type i svaret
  • Ugyldige pkt-line-data
  • Fejlmeddelelse fra side-band-fejlkanalen