Išmanusis HTTP
Pitmaster palaiko ryšį su git serveriais per HTTPS, naudodamas išmaniojo HTTP protokolą. Tai pagrindinis tinklo transportas. HTTP užklausoms jis naudoja savąsias PHP srauto funkcijas (fopen su srauto kontekstu), todėl turi būti įjungtas allow_url_fopen.
SmartHttpClient
use Pitmaster\Protocol\SmartHttpClient;
$http = new SmartHttpClient();
// Or with custom timeout:
$http = new SmartHttpClient(timeout: 60);
Numatytoji skirtojo laiko reikšmė yra konstanta PITMASTER_HTTP_TIMEOUT (sveikasis skaičius) arba 30 sekundžių, jei ji neapibrėžta.
Aptikti nuorodas
$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() tą patį atlieka su git-receive-pack. Nuorodų aptikimo užklausa siunčiama į:
GET <url>/info/refs?service=git-upload-pack
Atsakymas yra pkt-line koduotas nuorodų sąrašas, kurio pirmoje eilutėje pateikiamos galimybės.
Įkelti paketą (gauti)
$response = $http->uploadPack($url, $requestBody);
Siunčia POST užklausą į <url>/git-upload-pack su norimų ir turimų objektų suderinimo turiniu. Grąžina neapdorotą atsakymo turinį (pkt-lines, NAK ir šalutinės juostos duomenis). UploadPackClient sukuria užklausą ir ištraukia paketą:
use Pitmaster\Protocol\UploadPackClient;
$client = new UploadPackClient($http);
$packData = $client->fetch($url, $wants, $haves); // ObjectId[] wants and haves
Gauti paketą (siųsti)
$response = $http->receivePack($url, $requestBody);
Siunčia POST užklausą į <url>/git-receive-pack su nuorodų atnaujinimo komandomis ir paketo duomenimis.
PktLine kodavimas
git protokolas visam ryšiui naudoja pkt-line kadravimą. Prieš kiekvieną eilutę pateikiamas jos bendras ilgis (įskaitant 4 baitų ilgio prefiksą), užkoduotas kaip 4 šešioliktainiai skaitmenys.
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)
Ilgio taisyklės
- Minimali duomenų eilutė:
0005(1 baito naudingoji apkrova) - Maksimali duomenų eilutė:
fff0(65516 baitų naudingoji apkrova) - Išvalymo paketas:
0000 - Skyriklio paketas:
0001 - Atsakymo pabaiga:
0002(protokolo v2; apdorojaProtocolV2::decode(), oPktLine::decode()jį atmeta)
PktLine::MAX_PAYLOAD; // 65516 (65520 - 4)
Nuorodų aptikimas
RefDiscovery klasė analizuoja serverio paskelbtas nuorodas.
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
Paskelbtų nuorodų formatas
Pirmoje paskelbimo eilutėje pateikiamos galimybės:
<hash> HEAD\0<capability list>\n
<hash> refs/heads/main\n
<hash> refs/tags/v1.0\n
0000
Galimybės
Capability klasė analizuoja ir tvarko protokolo galimybes.
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']
Dažniausios galimybės
| Galimybė | Reikšmė |
|---|---|
multi_ack |
Serveris palaiko kelių patvirtinimų suderinimą |
thin-pack |
Serveris siunčia plonus paketus (bazinių objektų gali nebūti). Pitmaster jų prašo, bet kol kas negali indeksuoti plonų paketų (#16) |
side-band |
Serveris paketų duomenims naudoja šalutinę juostą (iki 1000 baitų) |
side-band-64k |
Serveris paketų duomenims naudoja 64K šalutinę juostą |
ofs-delta |
Pakete gali būti OFS_DELTA objektų |
shallow |
Serveris palaiko negilųjį klonavimą |
no-done |
Serveris nereikalauja „done“ eilutės |
symref=HEAD:refs/heads/main |
Simbolinis HEAD tikslas |
agent=git/2.45.0 |
Serverio git versija |
Šalutinės juostos demultipleksavimas
Kai serveris naudoja šalutinę juostą, paketo duomenys perduodami kartu su eigos ir klaidų pranešimais. Pirmasis kiekvienos pkt-line naudingosios apkrovos baitas nurodo kanalą:
| Kanalas | Reikšmė |
|---|---|
| 1 | Paketo duomenys |
| 2 | Eigos pranešimai (stderr) |
| 3 | Kritinių klaidų pranešimai |
Pitmaster UploadPackClient pašalina kanalų baitus ir iš naujo surenka paketo duomenis.
Protokolo versijos
v1 (numatytoji)
Tradicinis protokolas. Aptinkant nuorodas, visos nuorodos siunčiamos iš karto. Pitmaster suderina vienu etapu: siunčia norimus objektus, kiekvienos vietinės nuorodos viršūnę kaip have ir done.
v2
Paprastesnis ir našesnis protokolas.
Pagrindiniai skirtumai nuo v1:
- Nuorodų aptikimas yra atskira komanda
ls-refs(galima filtruoti nuorodas) - Gavimas vykdomas viena komanda
fetchsu struktūrizuotais parametrais - Skyriklio paketais (
0001) atskiriamos skiltys
clone() ir fetch() visada naudoja v1. v2 prieinamas, kai jį iškviečiate aiškiai:
$discovery = $http->discoverRefsV2($url); // ls-refs
$packData = (new UploadPackClient($http))->fetchV2($url, $wants, $haves);
HTTP užklausos eiga
Klonavimas / gavimas
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)
Siuntimas
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
Klaidų tvarkymas
Dėl tinklo klaidų išmetama ProtocolException. Jei išmaniojo HTTP apsikeitimas duomenimis vykdant clone() arba fetch() nepavyksta, Pitmaster pakartotinai bando naudoti paprastąjį HTTP ir, jei nepavyksta ir tada, išmeta pradinę klaidą. Dėl kitų nesėkmių (nežinomos nuotolinės saugyklos, procesų nepalaikančio deskriptoriaus, negalimo indeksuoti paketo) išmetamos kitokio tipo išimtys:
use Pitmaster\Exceptions\ProtocolException;
try {
$repo->fetch();
} catch (ProtocolException $e) {
echo "Network error: {$e->getMessage()}\n";
}
Dažnos klaidos:
- Serveris nepasiekiamas (skirtojo laiko pabaiga)
- Būtinas autentifikavimas arba saugykla nerasta (pranešama kaip
Unexpected HTTP status 401,403arba404) - Atsakyme netikėta
Content-Type - Netinkami pkt-line duomenys
- Šalutinės juostos klaidos kanalo pranešimas