Akıllı HTTP
Pitmaster, akıllı HTTP protokolünü kullanarak git sunucularıyla HTTPS üzerinden iletişim kurar. Bu, birincil ağ aktarım yöntemidir. HTTP istekleri için PHP'ün yerel akış işlevlerini (akış bağlamı içeren fopen) kullanır; bu nedenle allow_url_fopen etkin olmalıdır.
SmartHttpClient
use Pitmaster\Protocol\SmartHttpClient;
$http = new SmartHttpClient();
// Or with custom timeout:
$http = new SmartHttpClient(timeout: 60);
Zaman aşımı varsayılan olarak PITMASTER_HTTP_TIMEOUT sabitine (bir tam sayı) ayarlanır; bu sabit tanımlı değilse 30 saniye kullanılır.
Ref'leri keşfetme
$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(), git-receive-pack için de aynı işlemi yapar. Ref keşif isteği şu adrese gönderilir:
GET <url>/info/refs?service=git-upload-pack
Yanıt, ilk satırında yeteneklerin yer aldığı, pkt-line ile kodlanmış bir ref listesidir.
Paketi yükleme (fetch)
$response = $http->uploadPack($url, $requestBody);
want/have uzlaşma gövdesini içeren bir POST isteğini <url>/git-upload-pack adresine gönderir. Ham yanıt gövdesini (pkt-line'lar, NAK ve side-band verileri) döndürür. UploadPackClient isteği oluşturur ve paketi çıkarır:
use Pitmaster\Protocol\UploadPackClient;
$client = new UploadPackClient($http);
$packData = $client->fetch($url, $wants, $haves); // ObjectId[] wants and haves
Paket alma (push)
$response = $http->receivePack($url, $requestBody);
Ref güncelleme komutlarını ve paket verilerini içeren bir POST isteğini <url>/git-receive-pack adresine gönderir.
PktLine kodlaması
git protokolü, tüm iletişimlerde pkt-line çerçevelemesini kullanır. Her satırın başında toplam uzunluğu (4 baytlık uzunluk öneki dahil) 4 onaltılık basamakla kodlanmış olarak bulunur.
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)
Uzunluk kuralları
- En kısa veri satırı:
0005(1 bayt yük) - En uzun veri satırı:
fff0(65516 bayt yük) - Boşaltma paketi:
0000 - Ayırıcı paket:
0001 - Yanıt sonu:
0002(protokol v2;ProtocolV2::decode()tarafından işlenir,PktLine::decode()ise bunu reddeder)
PktLine::MAX_PAYLOAD; // 65516 (65520 - 4)
Ref keşfi
RefDiscovery sınıfı, sunucunun ref duyurusunu ayrıştırır.
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
Ref duyuru biçimi
Duyurunun ilk satırı yetenekleri içerir:
<hash> HEAD\0<capability list>\n
<hash> refs/heads/main\n
<hash> refs/tags/v1.0\n
0000
Yetenekler
Capability sınıfı, protokol yeteneklerini ayrıştırır ve yönetir.
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']
Yaygın yetenekler
| Yetenek | Anlamı |
|---|---|
multi_ack |
Sunucu, multi-ack uzlaşmasını destekler |
thin-pack |
Sunucu, ince paketler gönderir (temel nesneler atlanabilir). Pitmaster bunu ister ancak henüz ince paketleri dizine ekleyemez (#16) |
side-band |
Sunucu, paket verileri için side-band kullanır (1000 baytla sınırlıdır) |
side-band-64k |
Sunucu, paket verileri için 64K side-band kullanır |
ofs-delta |
Paket, OFS_DELTA nesneleri kullanabilir |
shallow |
Sunucu, sığ klonlamayı destekler |
no-done |
Sunucu, "done" satırını zorunlu tutmaz |
symref=HEAD:refs/heads/main |
HEAD'in sembolik hedefi |
agent=git/2.45.0 |
Sunucu sürümü git |
Side-band ayrıştırma
Sunucu side-band kullandığında paket verileri ilerleme ve hata mesajlarıyla çoğullama yoluyla birleştirilir. Her pkt-line yükünün ilk baytı kanalı belirtir:
| Kanal | Anlamı |
|---|---|
| 1 | Paket verisi |
| 2 | İlerleme mesajları (stderr) |
| 3 | Kritik hata mesajları |
Pitmaster'ün UploadPackClient yöntemi kanal baytlarını çıkarır ve paket verilerini yeniden birleştirir.
Protokol sürümleri
v1 (varsayılan)
Geleneksel protokol. Ref keşfi tüm ref'leri tek seferde gönderir. Pitmaster tek turda uzlaşır: isteklerini, her yerel ref'in ucunu bir have olarak ve done öğesini gönderir.
v2
Daha iyi performans sunan, daha basit bir protokol.
v1 ile temel farkları:
- Ref keşfi, ref'leri filtreleyebilen ayrı bir
ls-refskomutudur - Fetch, yapılandırılmış parametreler içeren tek bir
fetchkomutudur - Bölümleri ayırmak için ayırıcı paketler (
0001) kullanır
clone() ve fetch() her zaman v1 kullanır. v2, açıkça çağrıldığında kullanılabilir:
$discovery = $http->discoverRefsV2($url); // ls-refs
$packData = (new UploadPackClient($http))->fetchV2($url, $wants, $haves);
HTTP istek akışı
Klonlama/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
Hata işleme
Ağ hataları ProtocolException fırlatır. clone() veya fetch() için akıllı HTTP alışverişi başarısız olursa, Pitmaster aptal HTTP üzerinden yeniden dener; bu da başarısız olursa ilk hatayı yeniden fırlatır. Bilinmeyen bir uzak depo, süreç içermeyen bir tanıtıcı veya dizine eklenemeyen bir paket gibi diğer hatalar farklı özel durum türleri fırlatır:
use Pitmaster\Exceptions\ProtocolException;
try {
$repo->fetch();
} catch (ProtocolException $e) {
echo "Network error: {$e->getMessage()}\n";
}
Yaygın hatalar:
- Sunucuya ulaşılamıyor (zaman aşımı)
- Kimlik doğrulaması gerekiyor veya depo bulunamadı (
Unexpected HTTP status 401,403ya da404olarak bildirilir) - Yanıtta beklenmeyen
Content-Type - Geçersiz pkt-line verisi
- Side-band hata kanalı mesajı