Preskoči na vsebino

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

PHP
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

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() enako naredi za git-receive-pack. Zahteva za odkrivanje referenc se pošlje na:

Koda
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)

PHP
$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:

PHP
use Pitmaster\Protocol\UploadPackClient;

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

Prejem paketa (potiskanje)

PHP
$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.

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)

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 ga ProtocolV2::decode(), medtem ko ga PktLine::decode() zavrne)
PHP
PktLine::MAX_PAYLOAD;  // 65516 (65520 - 4)

Odkrivanje referenc

Razred RefDiscovery razčleni oglas referenc strežnika.

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

Oblika oglasa referenc

Prva vrstica oglasa vključuje zmožnosti:

Koda
<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.

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

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 fetch s 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:

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

Potek zahteve HTTP

Kloniranje/pridobivanje

Koda
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

Koda
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:

PHP
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, 403 ali 404)
  • Nepričakovan Content-Type v odgovoru
  • Neveljavni podatki pkt-line
  • Sporočilo o napaki v kanalu stranskega pasu