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

```
<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](https://github.com/inline0/pitmaster/issues/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

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

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