
# Smart HTTP

Pitmaster kommunicerar med git-servrar över HTTPS med det smarta HTTP-protokollet. Detta är den primära nätverkstransporten. Den använder PHPs inbyggda strömfunktioner (`fopen` med en strömkontext) för HTTP-förfrågningar, så `allow_url_fopen` måste vara aktiverat.

## SmartHttpClient

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Timeoutvärdet är som standard konstanten `PITMASTER_HTTP_TIMEOUT` (ett heltal), eller 30 sekunder om den inte är definierad.

### Upptäck refs

```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()` gör samma sak för `git-receive-pack`. Ref-upptäcktsförfrågan skickas till:
```
GET <url>/info/refs?service=git-upload-pack
```

Svaret är en pkt-line-kodad lista med refs och funktioner på den första raden.

### Ladda upp pack (fetch)

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

Skickar en POST till `<url>/git-upload-pack` med förhandlingsinnehållet want/have. Returnerar rådata från svarskroppen (pkt-lines, `NAK` och side-band-data). `UploadPackClient` bygger förfrågan och extraherar packen:

```php
use Pitmaster\Protocol\UploadPackClient;

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

### Ta emot pack (push)

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

Skickar en POST till `<url>/git-receive-pack` med ref-uppdateringskommandona och packdata.

## PktLine-kodning

Protokollet git använder pkt-line-inramning för all kommunikation. Varje rad föregås av sin totala längd (inklusive det 4 byte långa längdprefixet), kodad som 4 hexadecimala siffror.

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

### Längdregler

- Minsta datarad: `0005` (1 byte nyttolast)
- Största datarad: `fff0` (65516 byte nyttolast)
- Flush-paket: `0000`
- Avgränsarpaket: `0001`
- Svarsslut: `0002` (protokollet v2; hanteras av `ProtocolV2::decode()`, medan `PktLine::decode()` avvisar det)

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

## Ref-upptäckt

Klassen `RefDiscovery` tolkar serverns ref-annonsering.

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

Den första raden i annonseringen innehåller funktioner:

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

## Funktioner

Klassen `Capability` tolkar och hanterar protokollfunktioner.

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

### Vanliga funktioner

| Funktion | Betydelse |
|-----------|---------|
| `multi_ack` | Servern stöder förhandling med multi-ack |
| `thin-pack` | Servern skickar tunna packar (basobjekt kan utelämnas). Pitmaster begär detta men kan ännu inte indexera tunna packar ([#16](https://github.com/inline0/pitmaster/issues/16)) |
| `side-band` | Servern använder side-band för packdata (begränsat till 1000 byte) |
| `side-band-64k` | Servern använder 64K side-band för packdata |
| `ofs-delta` | Packen kan använda OFS_DELTA-objekt |
| `shallow` | Servern stöder ytlig kloning |
| `no-done` | Servern kräver ingen "done"-rad |
| `symref=HEAD:refs/heads/main` | HEAD:s symboliska mål |
| `agent=git/2.45.0` | Serverns version av git |

## Demultiplexering av side-band

När servern använder side-band multiplexeras packdata med förlopps- och felmeddelanden. Den första byten i varje pkt-line-nyttolast anger kanalen:

| Kanal | Betydelse |
|---------|---------|
| 1 | Packdata |
| 2 | Förloppsmeddelanden (stderr) |
| 3 | Allvarliga felmeddelanden |

Pitmasters `UploadPackClient` tar bort kanalbyten och sätter ihop packdatan igen.

## Protokollversioner

### v1 (standard)

Det traditionella protokollet. Ref-upptäckten skickar alla refs på en gång. Pitmaster förhandlar i en enda omgång: det skickar sina wants, varje lokal ref-topp som en `have` och `done`.

### v2

Ett enklare protokoll med bättre prestanda.

Viktiga skillnader jämfört med v1:
- Ref-upptäckt är ett separat `ls-refs`-kommando (kan filtrera refs)
- Fetch är ett enda `fetch`-kommando med strukturerade parametrar
- Använder avgränsarpaket (`0001`) för att separera avsnitt

`clone()` och `fetch()` använder alltid v1. v2 kan användas när du anropar det uttryckligen:

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

## Förfrågningsflöde för HTTP

### Clone/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
```

## Felhantering

Nätverksfel orsakar `ProtocolException`. Om det smarta HTTP-utbytet för `clone()` eller `fetch()` misslyckas försöker Pitmaster igen via dumb HTTP och kastar det ursprungliga felet på nytt om även det misslyckas. Andra fel (en okänd fjärrserver, ett handtag utan process, en pack som inte kan indexeras) orsakar andra undantagstyper:

```php
use Pitmaster\Exceptions\ProtocolException;

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

Vanliga fel:
- Servern kan inte nås (timeout)
- Autentisering krävs eller så hittades inte repot (rapporteras som `Unexpected HTTP status 401`, `403` eller `404`)
- Oväntad `Content-Type` i svaret
- Ogiltiga pkt-line-data
- Felmeddelande via side-band-kanalen
