Smart HTTP
Pitmaster komunicira s strežniki git prek HTTPS s protokolom smart HTTP. To je primarni omrežni način prenosa. Uporablja izvorne pretočne funkcije PHP (fopen s kontekstom toka) za zahteve HTTP, zato mora biti omogočen allow_url_fopen.
SmartHttpClient
use Pitmaster\Protocol\SmartHttpClient;
$http = new SmartHttpClient();
// Or with custom timeout:
$http = new SmartHttpClient(timeout: 60);
Privzeta vrednost časovne omejitve je konstanta PITMASTER_HTTP_TIMEOUT (celo število) oziroma 30 sekund, če ni določena.
Odkrivanje referenc
$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() enako naredi za git-receive-pack. Zahteva za odkrivanje referenc se pošlje na:
GET <url>/info/refs?service=git-upload-pack
Odgovor je seznam referenc, kodiran v pkt-line, z zmožnostmi v prvi vrstici.
Pošiljanje paketa (pridobivanje)
$response = $http->uploadPack($url, $requestBody);
Pošlje zahtevo POST na <url>/git-upload-pack s telesom za dogovarjanje want/have. Vrne neobdelano telo odgovora (pkt-lines, NAK in podatke stranskega pasu). UploadPackClient sestavi zahtevo in izlušči paket:
use Pitmaster\Protocol\UploadPackClient;
$client = new UploadPackClient($http);
$packData = $client->fetch($url, $wants, $haves); // ObjectId[] wants and haves
Prejem paketa (potiskanje)
$response = $http->receivePack($url, $requestBody);
Pošlje zahtevo POST na <url>/git-receive-pack z ukazi za posodobitev referenc in podatki paketa.
Kodiranje PktLine
Protokol git za vso komunikacijo uporablja okvirjanje pkt-line. Pred vsako vrstico je zapisana njena skupna dolžina (vključno s 4-bajtno predpono dolžine), kodirana kot 4 šestnajstiške števke.
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)
Pravila dolžine
- Najkrajša podatkovna vrstica:
0005(1 bajt koristnega tovora) - Najdaljša podatkovna vrstica:
fff0(65516 bajtov koristnega tovora) - Paket za izpraznitev:
0000 - Ločilni paket:
0001 - Konec odgovora:
0002(protokol v2; obravnava gaProtocolV2::decode(), medtem ko gaPktLine::decode()zavrne)
PktLine::MAX_PAYLOAD; // 65516 (65520 - 4)
Odkrivanje referenc
Razred RefDiscovery razčleni oglas referenc strežnika.
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
Oblika oglasa referenc
Prva vrstica oglasa vključuje zmožnosti:
<hash> HEAD\0<capability list>\n
<hash> refs/heads/main\n
<hash> refs/tags/v1.0\n
0000
Zmožnosti
Razred Capability razčleni in upravlja zmožnosti protokola.
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']
Pogoste zmožnosti
| Zmožnost | Pomen |
|---|---|
multi_ack |
Strežnik podpira pogajanje multi-ack |
thin-pack |
Strežnik pošilja tanke pakete (osnovni objekti so lahko izpuščeni). Pitmaster to zahteva, vendar še ne more indeksirati tankih paketov (#16) |
side-band |
Strežnik za podatke paketa uporablja stranski pas (omejen na 1000 bajtov) |
side-band-64k |
Strežnik za podatke paketa uporablja stranski pas 64K |
ofs-delta |
Paket lahko uporablja objekte OFS_DELTA |
shallow |
Strežnik podpira plitvo kloniranje |
no-done |
Strežnik ne zahteva vrstice »done« |
symref=HEAD:refs/heads/main |
Simbolični cilj HEAD |
agent=git/2.45.0 |
Različica git strežnika |
Demultipleksiranje stranskega pasu
Ko strežnik uporablja stranski pas, se podatki paketa multipleksirajo s sporočili o napredku in napakah. Prvi bajt koristnega tovora vsake vrstice pkt-line označuje kanal:
| Kanal | Pomen |
|---|---|
| 1 | Podatki paketa |
| 2 | Sporočila o napredku (stderr) |
| 3 | Usodna sporočila o napaki |
PitmasterUploadPackClient odstrani bajte kanala in znova sestavi podatke paketa.
Različice protokola
v1 (privzeto)
Tradicionalni protokol. Pri odkrivanju referenc se vse reference pošljejo hkrati. Pitmaster se pogaja v enem krogu: pošlje svoje zahteve, vsak lokalni vrh reference kot have in done.
v2
Preprostejši protokol z boljšo zmogljivostjo.
Glavne razlike v primerjavi z v1:
- Odkrivanje referenc je ločen ukaz
ls-refs(reference je mogoče filtrirati) - Pridobivanje je en sam ukaz
fetchs strukturiranimi parametri - Za ločevanje razdelkov uporablja ločilne pakete (
0001)
clone() in fetch() vedno uporabljata v1. v2 je na voljo, ko ga izrecno pokličete:
$discovery = $http->discoverRefsV2($url); // ls-refs
$packData = (new UploadPackClient($http))->fetchV2($url, $wants, $haves);
Potek zahteve HTTP
Kloniranje/pridobivanje
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)
Potiskanje
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
Obravnava napak
Omrežne napake sprožijo ProtocolException. Če izmenjava smart HTTP za clone() ali fetch() spodleti, Pitmaster poskusi znova prek dumb HTTP in ob ponovnem neuspehu znova sproži prvotno napako. Druge napake (neznan oddaljeni repozitorij, ročica brez procesa, paketa ni mogoče indeksirati) sprožijo druge vrste izjem:
use Pitmaster\Exceptions\ProtocolException;
try {
$repo->fetch();
} catch (ProtocolException $e) {
echo "Network error: {$e->getMessage()}\n";
}
Pogoste napake:
- Strežnik ni dosegljiv (časovna omejitev)
- Zahtevano preverjanje pristnosti ali repozitorij ni bil najden (sporočeno kot
Unexpected HTTP status 401,403ali404) - Nepričakovan
Content-Typev odgovoru - Neveljavni podatki pkt-line
- Sporočilo o napaki v kanalu stranskega pasu