Siirry sisältöön

Älykäs HTTP

Pitmaster viestii git-palvelinten kanssa HTTPS-yhteyden kautta käyttäen älykästä HTTP-protokollaa. Tämä on ensisijainen verkkosiirtotapa. Siinä käytetään PHP-järjestelmän natiiveja virtatoimintoja (fopen ja virtakonteksti) HTTP-pyyntöihin, joten allow_url_fopen on otettava käyttöön.

SmartHttpClient

PHP
use Pitmaster\Protocol\SmartHttpClient;

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

Aikakatkaisun oletusarvo on vakio PITMASTER_HTTP_TIMEOUT (kokonaisluku) tai 30 sekuntia, jos sitä ei ole määritelty.

Selvitä viitteet

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() tekee saman kohteelle git-receive-pack. Viitteiden selvityspyyntö lähetetään osoitteeseen:

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

Vastaus on pkt-line-muotoon koodattu viiteluettelo, jonka ensimmäisellä rivillä ovat ominaisuudet.

Lähetyspaketti (nouto)

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

Lähettää POST-pyynnön osoitteeseen <url>/git-upload-pack, jonka runko sisältää haluttujen ja olemassa olevien objektien neuvottelun. Palauttaa raakavastausrungon (pkt-line-rivit, NAK ja side-band-tiedot). UploadPackClient muodostaa pyynnön ja poimii paketin:

PHP
use Pitmaster\Protocol\UploadPackClient;

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

Vastaanottopaketti (lähetys)

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

Lähettää POST-pyynnön osoitteeseen <url>/git-receive-pack, jonka runko sisältää viitepäivityskomennot ja pakettitiedot.

PktLine-koodaus

git-protokolla käyttää pkt-line-kehystystä kaikessa tiedonsiirrossa. Jokaisen rivin eteen lisätään rivin kokonaispituus (mukaan lukien 4 tavun pituusetuliite), joka koodataan neljänä heksadesimaalinumerona.

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)

Pituussäännöt

  • Tietorivin vähimmäispituus: 0005 (hyötykuorma 1 tavu)
  • Tietorivin enimmäispituus: fff0 (65516 tavun hyötykuorma)
  • Tyhjennyspaketti: 0000
  • Erotinpaketti: 0001
  • Vastauksen loppu: 0002 (protokolla v2; ProtocolV2::decode() käsittelee sen, mutta PktLine::decode() hylkää sen)
PHP
PktLine::MAX_PAYLOAD;  // 65516 (65520 - 4)

Viitteiden selvitys

Luokka RefDiscovery jäsentää palvelimen viiteilmoituksen.

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

Viiteilmoituksen muoto

Ilmoituksen ensimmäinen rivi sisältää ominaisuudet:

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

Ominaisuudet

Luokka Capability jäsentää protokollan ominaisuudet ja hallinnoi niitä.

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

Yleiset ominaisuudet

Ominaisuus Merkitys
multi_ack Palvelin tukee usean kuittauksen neuvottelua
thin-pack Palvelin lähettää ohuita paketteja (perusobjekteja voidaan jättää pois). Pitmaster pyytää niitä, mutta ei vielä osaa indeksoida ohuita paketteja (#16)
side-band Palvelin käyttää side-bandia pakettitiedoille (enintään 1000 tavua)
side-band-64k Palvelin käyttää 64K side-bandia pakettitiedoille
ofs-delta Paketti voi käyttää OFS_DELTA-objekteja
shallow Palvelin tukee vajaata kloonausta
no-done Palvelin ei vaadi "done"-riviä
symref=HEAD:refs/heads/main HEADin symbolinen kohde
agent=git/2.45.0 Palvelimen git-versio

Side-band-kanavien erottelu

Kun palvelin käyttää side-bandia, pakettitiedot lomitetaan edistymis- ja virheilmoitusten kanssa. Jokaisen pkt-line-hyötykuorman ensimmäinen tavu ilmaisee kanavan:

Kanava Merkitys
1 Pakettitiedot
2 Edistymisilmoitukset (stderr)
3 Vakavat virheilmoitukset

Pitmaster-luokan UploadPackClient poistaa kanavatavut ja kokoaa pakettitiedot uudelleen.

Protokollaversiot

v1 (oletus)

Perinteinen protokolla. Viitteiden selvityksessä lähetetään kaikki viitteet kerralla. Pitmaster neuvottelee yhdellä kierroksella: se lähettää haluamansa objektit, jokaisen paikallisen viitteen kärjen muodossa have sekä done.

v2

Yksinkertaisempi ja suorituskykyisempi protokolla.

Tärkeimmät erot protokollaan v1 verrattuna:

  • Viitteiden selvitys on erillinen ls-refs-komento (viitteitä voi suodattaa)
  • Nouto tehdään yhdellä fetch-komennolla, jolla on rakenteiset parametrit
  • Osioiden erottamiseen käytetään erotinpaketteja (0001)

clone() ja fetch() käyttävät aina v1-protokollaa. v2 on käytettävissä, kun kutsut sitä erikseen:

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

HTTP-pyynnön kulku

Kloonaus/nouto

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

Lähetys

Koodi
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

Virheenkäsittely

Verkkovirheet aiheuttavat poikkeuksen ProtocolException. Jos älykäs HTTP-pyyntö kohteelle clone() tai fetch() epäonnistuu, Pitmaster yrittää uudelleen tavallisella HTTP-pyynnöllä ja heittää alkuperäisen virheen uudelleen, jos sekin epäonnistuu. Muunlaiset virheet (tuntematon etärepositorio, prosessiton käsittelijä tai indeksoimaton paketti) aiheuttavat muuntyyppisiä poikkeuksia:

PHP
use Pitmaster\Exceptions\ProtocolException;

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

Yleisiä virheitä:

  • Palvelimeen ei saada yhteyttä (aikakatkaisu)
  • Todennus vaaditaan tai repositoriota ei löydy (ilmoitetaan muodossa Unexpected HTTP status 401, 403 tai 404)
  • Vastauksessa on odottamaton Content-Type
  • Virheellistä pkt-line-dataa
  • Side-band-virhekanavan viesti