Lewati ke konten

Smart HTTP

Pitmaster berkomunikasi dengan server git melalui HTTPS menggunakan protokol smart HTTP. Ini adalah transport jaringan utama. Protokol ini menggunakan fungsi stream native milik PHP (fopen dengan konteks stream) untuk permintaan HTTP, jadi allow_url_fopen harus diaktifkan.

SmartHttpClient

PHP
use Pitmaster\Protocol\SmartHttpClient;

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

Batas waktu default-nya adalah konstanta PITMASTER_HTTP_TIMEOUT (bilangan bulat), atau 30 detik jika konstanta tersebut tidak ditentukan.

Temukan ref

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() melakukan hal yang sama untuk git-receive-pack. Permintaan discovery ref dikirim ke:

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

Responsnya berupa daftar ref berkode pkt-line dengan kapabilitas pada baris pertama.

Upload pack (fetch)

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

Mengirim POST ke <url>/git-upload-pack dengan isi permintaan negosiasi want/have. Mengembalikan isi respons mentah (pkt-lines, NAK, dan data side-band). UploadPackClient menyusun permintaan dan mengekstrak pack:

PHP
use Pitmaster\Protocol\UploadPackClient;

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

Receive pack (push)

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

Mengirim POST ke <url>/git-receive-pack dengan perintah pembaruan ref dan data pack.

Encoding PktLine

Protokol git menggunakan framing pkt-line untuk semua komunikasi. Setiap baris diawali panjang totalnya (termasuk prefiks panjang 4 byte) yang dikodekan sebagai 4 digit heksadesimal.

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)

Aturan panjang

  • Baris data minimum: 0005 (payload 1 byte)
  • Baris data maksimum: fff0 (payload 65516 byte)
  • Paket flush: 0000
  • Paket delimiter: 0001
  • Akhir respons: 0002 (protokol v2; ditangani oleh ProtocolV2::decode(), sedangkan PktLine::decode() menolaknya)
PHP
PktLine::MAX_PAYLOAD;  // 65516 (65520 - 4)

Discovery ref

Kelas RefDiscovery mengurai iklan ref dari server.

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

Format iklan ref

Baris pertama iklan tersebut mencakup kapabilitas:

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

Kapabilitas

Kelas Capability mengurai dan mengelola kapabilitas protokol.

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

Kapabilitas umum

Kapabilitas Arti
multi_ack Server mendukung negosiasi multi-ack
thin-pack Server mengirim pack tipis (objek dasar dapat dihilangkan). Pitmaster memintanya, tetapi belum dapat mengindeks pack tipis (#16)
side-band Server menggunakan side-band untuk data pack (terbatas hingga 1000 byte)
side-band-64k Server menggunakan side-band 64K untuk data pack
ofs-delta Pack dapat menggunakan objek OFS_DELTA
shallow Server mendukung clone dangkal
no-done Server tidak memerlukan baris "done"
symref=HEAD:refs/heads/main Target simbolis HEAD
agent=git/2.45.0 Versi git server

Demultipleks side-band

Saat server menggunakan side-band, data pack dimultipleks bersama pesan progres dan kesalahan. Byte pertama dari setiap payload pkt-line menunjukkan kanalnya:

Kanal Arti
1 Data pack
2 Pesan progres (stderr)
3 Pesan kesalahan fatal

Pitmaster milik UploadPackClient menghapus byte kanal dan menyusun kembali data pack.

Versi protokol

v1 (default)

Protokol tradisional. Discovery ref mengirim semua ref sekaligus. Pitmaster bernegosiasi dalam satu putaran: mengirim wants-nya, setiap tip ref lokal sebagai have, dan done.

v2

Protokol yang lebih sederhana dengan performa lebih baik.

Perbedaan utama dari v1:

  • Discovery ref adalah perintah ls-refs terpisah (dapat memfilter ref)
  • Fetch adalah satu perintah fetch dengan parameter terstruktur
  • Menggunakan paket delimiter (0001) untuk memisahkan bagian

clone() dan fetch() selalu menggunakan v1. v2 tersedia jika Anda memanggilnya secara eksplisit:

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

Alur permintaan HTTP

Clone/Fetch

Kode
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

Kode
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

Penanganan error

Kesalahan jaringan melempar ProtocolException. Jika pertukaran smart HTTP untuk clone() atau fetch() gagal, Pitmaster mencoba lagi melalui dumb HTTP dan melempar ulang kesalahan awal jika upaya itu juga gagal. Kegagalan lain (remote tidak dikenal, handle tanpa proses, pack yang tidak dapat diindeks) melempar jenis pengecualian lain:

PHP
use Pitmaster\Exceptions\ProtocolException;

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

Kesalahan umum:

  • Server tidak dapat dijangkau (batas waktu)
  • Autentikasi diperlukan atau repositori tidak ditemukan (dilaporkan sebagai Unexpected HTTP status 401, 403, atau 404)
  • Content-Type tak terduga dalam respons
  • Data pkt-line tidak valid
  • Pesan kanal kesalahan side-band