Hoppa till innehåll

Smart HTTP

Pitmaster kommunicerar med git-servrar över HTTPS med det smarta HTTP-protokollet. Detta är den primära nätverkstransporten. Den använder PHPs inbyggda strömfunktioner (fopen med en strömkontext) för HTTP-förfrågningar, så allow_url_fopen måste vara aktiverat.

SmartHttpClient

PHP
use Pitmaster\Protocol\SmartHttpClient;

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

Timeoutvärdet är som standard konstanten PITMASTER_HTTP_TIMEOUT (ett heltal), eller 30 sekunder om den inte är definierad.

Upptäck refs

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 samma sak för git-receive-pack. Ref-upptäcktsförfrågan skickas till:

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

Svaret är en pkt-line-kodad lista med refs och funktioner på den första raden.

Ladda upp pack (fetch)

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

Skickar en POST till <url>/git-upload-pack med förhandlingsinnehållet want/have. Returnerar rådata från svarskroppen (pkt-lines, NAK och side-band-data). UploadPackClient bygger förfrågan och extraherar packen:

PHP
use Pitmaster\Protocol\UploadPackClient;

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

Ta emot pack (push)

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

Skickar en POST till <url>/git-receive-pack med ref-uppdateringskommandona och packdata.

PktLine-kodning

Protokollet git använder pkt-line-inramning för all kommunikation. Varje rad föregås av sin totala längd (inklusive det 4 byte långa längdprefixet), kodad som 4 hexadecimala siffror.

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)

Längdregler

  • Minsta datarad: 0005 (1 byte nyttolast)
  • Största datarad: fff0 (65516 byte nyttolast)
  • Flush-paket: 0000
  • Avgränsarpaket: 0001
  • Svarsslut: 0002 (protokollet v2; hanteras av ProtocolV2::decode(), medan PktLine::decode() avvisar det)
PHP
PktLine::MAX_PAYLOAD;  // 65516 (65520 - 4)

Ref-upptäckt

Klassen RefDiscovery tolkar serverns ref-annonsering.

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

Ref-annonsformat

Den första raden i annonseringen innehåller funktioner:

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

Funktioner

Klassen Capability tolkar och hanterar protokollfunktioner.

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

Vanliga funktioner

Funktion Betydelse
multi_ack Servern stöder förhandling med multi-ack
thin-pack Servern skickar tunna packar (basobjekt kan utelämnas). Pitmaster begär detta men kan ännu inte indexera tunna packar (#16)
side-band Servern använder side-band för packdata (begränsat till 1000 byte)
side-band-64k Servern använder 64K side-band för packdata
ofs-delta Packen kan använda OFS_DELTA-objekt
shallow Servern stöder ytlig kloning
no-done Servern kräver ingen "done"-rad
symref=HEAD:refs/heads/main HEAD:s symboliska mål
agent=git/2.45.0 Serverns version av git

Demultiplexering av side-band

När servern använder side-band multiplexeras packdata med förlopps- och felmeddelanden. Den första byten i varje pkt-line-nyttolast anger kanalen:

Kanal Betydelse
1 Packdata
2 Förloppsmeddelanden (stderr)
3 Allvarliga felmeddelanden

Pitmasters UploadPackClient tar bort kanalbyten och sätter ihop packdatan igen.

Protokollversioner

v1 (standard)

Det traditionella protokollet. Ref-upptäckten skickar alla refs på en gång. Pitmaster förhandlar i en enda omgång: det skickar sina wants, varje lokal ref-topp som en have och done.

v2

Ett enklare protokoll med bättre prestanda.

Viktiga skillnader jämfört med v1:

  • Ref-upptäckt är ett separat ls-refs-kommando (kan filtrera refs)
  • Fetch är ett enda fetch-kommando med strukturerade parametrar
  • Använder avgränsarpaket (0001) för att separera avsnitt

clone() och fetch() använder alltid v1. v2 kan användas när du anropar det uttryckligen:

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

Förfrågningsflöde för HTTP

Clone/Fetch

Kod
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

Kod
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

Felhantering

Nätverksfel orsakar ProtocolException. Om det smarta HTTP-utbytet för clone() eller fetch() misslyckas försöker Pitmaster igen via dumb HTTP och kastar det ursprungliga felet på nytt om även det misslyckas. Andra fel (en okänd fjärrserver, ett handtag utan process, en pack som inte kan indexeras) orsakar andra undantagstyper:

PHP
use Pitmaster\Exceptions\ProtocolException;

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

Vanliga fel:

  • Servern kan inte nås (timeout)
  • Autentisering krävs eller så hittades inte repot (rapporteras som Unexpected HTTP status 401, 403 eller 404)
  • Oväntad Content-Type i svaret
  • Ogiltiga pkt-line-data
  • Felmeddelande via side-band-kanalen