
# Intelligens HTTP

Az Pitmaster intelligens HTTP protokollt használva kommunikál a git-szerverekkel HTTPS felett. Ez az elsődleges hálózati átviteli mód. Az HTTP kérésekhez az PHP natív adatfolyam-függvényeit használja (`fopen` adatfolyam-kontextussal), ezért engedélyezni kell az `allow_url_fopen` beállítást.

## SmartHttpClient

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Az időkorlát alapértelmezés szerint az `PITMASTER_HTTP_TIMEOUT` konstans értékét használja (egész számként), ennek hiányában pedig 30 másodperc.

### Refek felderítése

```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();
```

Az `discoverReceivePackRefs()` ugyanezt teszi az `git-receive-pack` esetében. A ref-felderítési kérés ide kerül:
```
GET <url>/info/refs?service=git-upload-pack
```

A válasz egy pkt-line kódolású reflista, amelynek első sora tartalmazza a képességeket.

### Pack feltöltése (fetch)

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

POST-kérést küld az `<url>/git-upload-pack` címre, benne a want/have egyeztetés törzsével. A nyers válaszüzenettörzset adja vissza (pkt-line sorok, `NAK` és side-band adatok). Az `UploadPackClient` állítja össze a kérést, és nyeri ki a packet:

```php
use Pitmaster\Protocol\UploadPackClient;

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

### Pack fogadása (push)

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

POST-kérést küld az `<url>/git-receive-pack` címre, benne a reffrissítési parancsokkal és a pack-adatokkal.

## PktLine-kódolás

A git protokoll minden kommunikációhoz pkt-line keretezést használ. Minden sort a teljes hossza előz meg, beleértve a 4 bájtos hosszprefixet is, 4 hexadecimális számjeggyel kódolva.

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

### Hosszra vonatkozó szabályok

- Minimális adatsor: `0005` (1 bájtos hasznos adat)
- Maximális adatsor: `fff0` (65516 bájtos hasznos adat)
- Ürítőcsomag: `0000`
- Elválasztócsomag: `0001`
- Válasz vége: `0002` (v2 protokoll; az `ProtocolV2::decode()` kezeli, az `PktLine::decode()` viszont elutasítja)

```php
PktLine::MAX_PAYLOAD;  // 65516 (65520 - 4)
```

## Refek felderítése

Az `RefDiscovery` osztály feldolgozza a szerver refhirdetését.

```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
```

### A refhirdetés formátuma

A hirdetés első sora képességeket tartalmaz:

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

## Képességek

Az `Capability` osztály feldolgozza és kezeli a protokollképességeket.

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

### Gyakori képességek

| Képesség | Jelentés |
|-----------|---------|
| `multi_ack` | A szerver támogatja a többes nyugtázású egyeztetést |
| `thin-pack` | A szerver vékony packokat küldhet (az alapobjektumok kimaradhatnak). Az Pitmaster kéri ezt, de egyelőre nem tudja indexelni a vékony packokat ([#16](https://github.com/inline0/pitmaster/issues/16)) |
| `side-band` | A szerver side-band csatornát használ a pack-adatokhoz (legfeljebb 1000 bájtot) |
| `side-band-64k` | A szerver 64K side-band csatornát használ a pack-adatokhoz |
| `ofs-delta` | A pack használhat OFS_DELTA objektumokat |
| `shallow` | A szerver támogatja a sekély klónozást |
| `no-done` | A szerver nem követel meg „done” sort |
| `symref=HEAD:refs/heads/main` | A HEAD szimbolikus célja |
| `agent=git/2.45.0` | A szerver git-verziója |

## A side-band szétválasztása

Ha a szerver side-band módot használ, a pack-adatok az állapotjelentésekkel és hibaüzenetekkel együtt kerülnek továbbításra. Minden pkt-line hasznos adatának első bájtja jelzi a csatornát:

| Csatorna | Jelentés |
|---------|---------|
| 1 | Pack-adatok |
| 2 | Folyamatjelzések (stderr) |
| 3 | Végzetes hibaüzenetek |

Az Pitmaster `UploadPackClient` eltávolítja a csatornabájtokat, és újra összeállítja a pack-adatokat.

## Protokollverziók

### v1 (alapértelmezett)

A hagyományos protokoll. A ref-felderítés egyszerre küldi el az összes refet. Az Pitmaster egyetlen körben egyeztet: elküldi a kéréseit, minden helyi ref csúcsát `have`-ként, valamint a `done` értéket.

### v2

Egyszerűbb protokoll, jobb teljesítménnyel.

Főbb eltérések az v1 verziótól:
- A ref-felderítés külön `ls-refs` parancs; a refek szűrhetők
- A fetch egyetlen `fetch` parancs strukturált paraméterekkel
- Elválasztócsomagokat (`0001`) használ a szakaszok elkülönítésére

Az `clone()` és az `fetch()` mindig az v1 protokollt használja. Az v2 kifejezett meghívással érhető el:

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

## HTTP kérésfolyamat

### Klónozás/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
```

## Hibakezelés

A hálózati hibák `ProtocolException` kivételt dobnak. Ha az `clone()` vagy az `fetch()` intelligens HTTP egyeztetése sikertelen, az Pitmaster újrapróbálkozik egyszerű HTTP módon, és ismét sikertelenség esetén újra dobja az eredeti hibát. Más hibák (ismeretlen távoli tároló, folyamat nélküli fogantyú, nem indexelhető pack) más kivételtípusokat dobnak:

```php
use Pitmaster\Exceptions\ProtocolException;

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

Gyakori hibák:
- A szerver nem érhető el (időtúllépés)
- Hitelesítés szükséges, vagy a tároló nem található (`Unexpected HTTP status 401`, `403` vagy `404` jelzi)
- Váratlan `Content-Type` a válaszban
- Érvénytelen pkt-line-adat
- Üzenet a side-band hiba csatornáján
