İçeriğe geç

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

PHP
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

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(), git-receive-pack için de aynı işlemi yapar. Ref keşif isteği şu adrese gönderilir:

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

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

PHP
use Pitmaster\Protocol\UploadPackClient;

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

Paket alma (push)

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

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)

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)
PHP
PktLine::MAX_PAYLOAD;  // 65516 (65520 - 4)

Ref keşfi

RefDiscovery sınıfı, sunucunun ref duyurusunu ayrıştırır.

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

Ref duyuru biçimi

Duyurunun ilk satırı yetenekleri içerir:

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

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

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-refs komutudur
  • Fetch, yapılandırılmış parametreler içeren tek bir fetch komutudur
  • 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:

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

HTTP istek akışı

Klonlama/Fetch

Kod
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

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

PHP
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, 403 ya da 404 olarak bildirilir)
  • Yanıtta beklenmeyen Content-Type
  • Geçersiz pkt-line verisi
  • Side-band hata kanalı mesajı