Smart HTTP
Pitmaster communique avec les serveurs git via HTTPS au moyen du protocole smart HTTP. Il s’agit du transport réseau principal. Il utilise les fonctions de flux natives de PHP (fopen avec un contexte de flux) pour les requêtes HTTP ; allow_url_fopen doit donc être activé.
SmartHttpClient
use Pitmaster\Protocol\SmartHttpClient;
$http = new SmartHttpClient();
// Or with custom timeout:
$http = new SmartHttpClient(timeout: 60);
Le délai d’expiration est par défaut la constante PITMASTER_HTTP_TIMEOUT (un entier), ou 30 secondes si elle n’est pas définie.
Découvrir les refs
$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() fait de même pour git-receive-pack. La requête de découverte des refs est envoyée à :
GET <url>/info/refs?service=git-upload-pack
La réponse est une liste de refs encodée en pkt-line, avec les fonctionnalités sur la première ligne.
Envoyer le pack (fetch)
$response = $http->uploadPack($url, $requestBody);
Envoie une requête POST à <url>/git-upload-pack avec le corps de négociation want/have. Renvoie le corps brut de la réponse (pkt-lines, NAK et données side-band). UploadPackClient construit la requête et extrait le pack :
use Pitmaster\Protocol\UploadPackClient;
$client = new UploadPackClient($http);
$packData = $client->fetch($url, $wants, $haves); // ObjectId[] wants and haves
Recevoir le pack (push)
$response = $http->receivePack($url, $requestBody);
Envoie une requête POST à <url>/git-receive-pack avec les commandes de mise à jour des refs et les données du pack.
Encodage PktLine
Le protocole git utilise le cadrage pkt-line pour toutes les communications. Chaque ligne est préfixée par sa longueur totale (y compris le préfixe de longueur de 4 octets), encodée sur 4 chiffres hexadécimaux.
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)
Règles de longueur
- Ligne de données minimale :
0005(charge utile de 1 octet) - Ligne de données maximale :
fff0(charge utile de 65516 octets) - Paquet de vidage :
0000 - Paquet délimiteur :
0001 - Fin de réponse :
0002(v2 du protocole ; pris en charge parProtocolV2::decode(), tandis quePktLine::decode()le rejette)
PktLine::MAX_PAYLOAD; // 65516 (65520 - 4)
Découverte des refs
La classe RefDiscovery analyse l’annonce des refs du serveur.
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 de l’annonce des refs
La première ligne de l’annonce inclut les fonctionnalités :
<hash> HEAD\0<capability list>\n
<hash> refs/heads/main\n
<hash> refs/tags/v1.0\n
0000
Fonctionnalités
La classe Capability analyse et gère les fonctionnalités du protocole.
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']
Fonctionnalités courantes
| Fonctionnalité | Signification |
|---|---|
multi_ack |
Le serveur prend en charge la négociation multi-ack |
thin-pack |
Le serveur envoie des packs minces (les objets de base peuvent être omis). Pitmaster le demande, mais ne peut pas encore indexer les packs minces (#16) |
side-band |
Le serveur utilise side-band pour les données du pack (limitées à 1000 octets) |
side-band-64k |
Le serveur utilise side-band 64K pour les données du pack |
ofs-delta |
Le pack peut utiliser des objets OFS_DELTA |
shallow |
Le serveur prend en charge le clonage superficiel |
no-done |
Le serveur n’exige pas de ligne « done » |
symref=HEAD:refs/heads/main |
Cible symbolique de HEAD |
agent=git/2.45.0 |
Version de git du serveur |
Démultiplexage side-band
Lorsque le serveur utilise side-band, les données du pack sont multiplexées avec les messages de progression et d’erreur. Le premier octet de la charge utile de chaque pkt-line indique le canal :
| Canal | Signification |
|---|---|
| 1 | Données du pack |
| 2 | Messages de progression (stderr) |
| 3 | Messages d’erreur fatale |
Le UploadPackClient de Pitmaster supprime les octets de canal et reconstitue les données du pack.
Versions du protocole
v1 (par défaut)
Le protocole traditionnel. La découverte des refs envoie toutes les refs en une seule fois. Pitmaster négocie en un seul tour : il envoie ses wants, chaque pointe de ref locale comme have, puis done.
v2
Un protocole plus simple et plus performant.
Principales différences par rapport à v1 :
- La découverte des refs est une commande
ls-refsdistincte (elle peut filtrer les refs) - Fetch est une commande
fetchunique avec des paramètres structurés - Utilise des paquets délimiteurs (
0001) pour séparer les sections
clone() et fetch() utilisent toujours v1. v2 est disponible lorsque vous l’appelez explicitement :
$discovery = $http->discoverRefsV2($url); // ls-refs
$packData = (new UploadPackClient($http))->fetchV2($url, $wants, $haves);
Flux de requête HTTP
Clonage/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
Gestion des erreurs
Les erreurs réseau déclenchent ProtocolException. Si l’échange smart HTTP de clone() ou fetch() échoue, Pitmaster réessaie via dumb HTTP et relance l’erreur d’origine si cette tentative échoue aussi. Les autres échecs (remote inconnu, handle sans processus, pack impossible à indexer) déclenchent d’autres types d’exception :
use Pitmaster\Exceptions\ProtocolException;
try {
$repo->fetch();
} catch (ProtocolException $e) {
echo "Network error: {$e->getMessage()}\n";
}
Erreurs courantes :
- Serveur inaccessible (délai d’expiration)
- Authentification requise ou dépôt introuvable (signalé par
Unexpected HTTP status 401,403ou404) Content-Typeinattendu dans la réponse- Données pkt-line non valides
- Message du canal d’erreur side-band