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
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
$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:
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)
$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:
use Pitmaster\Protocol\UploadPackClient;
$client = new UploadPackClient($http);
$packData = $client->fetch($url, $wants, $haves); // ObjectId[] wants and haves
Receive pack (push)
$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.
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 doorProtocolV2::decode(), terwijlPktLine::decode()het weigert)
PktLine::MAX_PAYLOAD; // 65516 (65520 - 4)
Ref-discovery
De klasse RefDiscovery parseert de ref-advertentie van de server.
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:
<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.
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
fetchmet 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:
$discovery = $http->discoverRefsV2($url); // ls-refs
$packData = (new UploadPackClient($http))->fetchV2($url, $wants, $haves);
Verzoekstroom van HTTP
Clone/fetch
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
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:
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,403of404) - Onverwachte
Content-Typein de response - Ongeldige pkt-line-data
- Foutmelding via side-band-kanaal