HTTP/1.1-Client für GET, POST, PUT, DELETE, PATCH und HEAD ohne TLS. Baut auf std.net.socket und std.net.dns auf. Unterstützt Header-Builder (HTTPSetHeader), Bearer- und Basic-Auth (RFC 7617), automatisches Chunked-Transfer-Decoding, 3×x-Redirects (HTTP→HTTP und HTTP→HTTPS, bis 10 Hops) sowie case-insensitives Header-Lesen. Für HTTPS-Verbindungen std.net.https verwenden.
import std.net.http;
var hdrs: int64 := HTTPSetBearerToken(0, "my-token");
var req: HTTPRequest;
req.method := HTTP_GET;
req.host := "api.example.com" as int64;
req.path := "/v1/items" as int64;
req.port := HTTP_PORT;
req.headers := hdrs;
var resp: HTTPResponse := HTTPSendWithRedirects(req);
if (resp.statusCode == HTTP_OK) {
PrintLn("OK");
}
HTTPResponseFree(resp);
HTTPHeadersFree(hdrs);
std.net.socketstd.net.dnsstd.net.typesstd.stringstd.base64| Name | Typ | Wert | Sichtbarkeit |
|---|---|---|---|
HTTP_PORT | int64 | 80 | pub |
HTTPS_PORT | int64 | 443 | pub |
HTTP_RECV_TIMEOUT_MS | int64 | 30000 | pub |
HTTP_MAX_REDIRECTS | int64 | 10 | pub |
HTTP_GET | int64 | 1 | pub |
HTTP_POST | int64 | 2 | pub |
HTTP_PUT | int64 | 3 | pub |
HTTP_DELETE | int64 | 4 | pub |
HTTP_PATCH | int64 | 5 | pub |
HTTP_HEAD | int64 | 6 | pub |
HTTP_OK | int64 | 200 | pub |
HTTP_CREATED | int64 | 201 | pub |
HTTP_NO_CONTENT | int64 | 204 | pub |
HTTP_BAD_REQUEST | int64 | 400 | pub |
HTTP_UNAUTHORIZED | int64 | 401 | pub |
HTTP_FORBIDDEN | int64 | 403 | pub |
HTTP_NOT_FOUND | int64 | 404 | pub |
HTTP_SERVER_ERROR | int64 | 500 | pub |
| Feld | Typ | Beschreibung |
|---|---|---|
statusCode | int64 | HTTP-Statuscode (z. B. 200, 404) |
statusText | int64 | Zeiger auf Statustext-String (z. B. „OK“) |
headerCount | int64 | Anzahl der geparsten Response-Header |
contentLength | int64 | Content-Length aus dem Kopf; 0 bei Transfer-Encoding: chunked — siehe Kasten |
bodyPtr | int64 | Zeiger auf Response-Body (heap-alloc'd) |
bodySize | int64 | Tatsächliche Größe des Body in Bytes |
headersRaw | int64 | Zeiger auf rohe Response-Header (null-terminiert, heap-alloc'd) |
headersSize | int64 | Byte-Anzahl der rohen Header |
| Feld | Typ | Beschreibung |
|---|---|---|
method | int64 | HTTP-Methode (HTTP_GET, HTTP_POST …) |
host | int64 | Zeiger auf Hostname-String |
path | int64 | Zeiger auf Pfad-String (inkl. führendem / und Query) |
port | int64 | TCP-Port (HTTP_PORT = 80) |
headers | int64 | Zeiger auf Header-String (aus HTTPSetHeader) oder 0 |
body | int64 | Zeiger auf Request-Body oder 0 |
bodySize | int64 | Länge des Request-Body in Bytes |
| Signatur | Sichtbarkeit | Beschreibung |
|---|---|---|
HTTPGet(host: int64, path: int64): HTTPResponse | pub | HTTP-GET an Host senden |
HTTPPost(host: int64, path: int64, body: int64, bodySize: int64): HTTPResponse | pub | HTTP-POST mit Body senden |
HTTPPut(host: int64, path: int64, body: int64, bodySize: int64): HTTPResponse | pub | HTTP-PUT mit Body senden |
HTTPDelete(host: int64, path: int64): HTTPResponse | pub | HTTP-DELETE senden |
HTTPPatch(host: int64, path: int64, body: int64, bodySize: int64): HTTPResponse | pub | HTTP-PATCH mit Body senden |
HTTPHead(host: int64, path: int64): HTTPResponse | pub | HTTP-HEAD senden (kein Body in Antwort) |
| Signatur | Sichtbarkeit | Beschreibung |
|---|---|---|
HTTPGetH(host: int64, path: int64, headers: int64): HTTPResponse | pub | HTTP-GET mit zusätzlichen Headern |
HTTPPostH(host: int64, path: int64, body: int64, bodySize: int64, headers: int64): HTTPResponse | pub | HTTP-POST mit Body und Headern |
HTTPDeleteH(host: int64, path: int64, headers: int64): HTTPResponse | pub | HTTP-DELETE mit Headern |
| Signatur | Sichtbarkeit | Beschreibung |
|---|---|---|
HTTPRequestBuild(req: HTTPRequest): int64 | pub | HTTP-Anfrage-Puffer aus Struct aufbauen; gibt Zeiger auf Puffer zurück |
HTTPSend(request: HTTPRequest): HTTPResponse | pub | HTTP-Anfrage senden; dekodiert automatisch Chunked Transfer-Encoding |
HTTPSendWithRedirects(request: HTTPRequest): HTTPResponse | pub | Wie HTTPSend, folgt aber automatisch 3×x-Redirects (bis HTTP_MAX_REDIRECTS = 10); HTTP→HTTPS via TLS |
| Signatur | Sichtbarkeit | Beschreibung |
|---|---|---|
HTTPSetHeader(hdrs: int64, name: int64, value: int64): int64 | pub | Fügt Header-Zeile zu vorhandenem Header-String hinzu (oder legt neuen an wenn hdrs=0); gibt neuen heap-alloc'd String zurück |
HTTPHeadersFree(hdrs: int64) | pub | Gibt einen per HTTPSetHeader aufgebauten Header-String frei |
HTTPSetBearerToken(hdrs: int64, token: int64): int64 | pub | Fügt Authorization: Bearer <token> hinzu; gibt neuen Header-String zurück |
HTTPSetBasicAuth(hdrs: int64, user: int64, pass: int64): int64 | pub | Fügt Authorization: Basic <base64(user:pass)> hinzu (RFC 7617); gibt neuen Header-String zurück |
| Signatur | Sichtbarkeit | Beschreibung |
|---|---|---|
HTTPGetHeader(resp: HTTPResponse, name: int64): int64 | pub | Sucht Header name im headersRaw-Puffer; case-insensitiv; gibt Zeiger auf Header-Wert zurück oder 0 wenn nicht gefunden |
HTTPResponseFree(response: HTTPResponse) | pub | Gibt Body-Puffer und headersRaw frei |
var hdrs: int64 := HTTPSetBearerToken(0, "eyJhbGci...");
var body: pchar := "{\"status\":\"active\"}";
var resp: HTTPResponse := HTTPPostH(
"api.example.com" as int64, "/v1/item/42" as int64,
body as int64, StrLen(body), hdrs);
if (resp.statusCode == HTTP_OK) {
PrintLn("Aktualisiert");
}
HTTPResponseFree(resp);
HTTPHeadersFree(hdrs);
var resp: HTTPResponse := HTTPGet("api.example.com" as int64, "/" as int64);
var ct: int64 := HTTPGetHeader(resp, "Content-Type" as int64);
if (ct != 0) {
PrintLn(ct as pchar);
}
HTTPResponseFree(resp);
var req: HTTPRequest;
req.method := HTTP_GET;
req.host := "example.com" as int64;
req.path := "/" as int64;
req.port := HTTP_PORT;
req.headers := 0;
req.body := 0;
req.bodySize := 0;
// Folgt automatisch: HTTP 301 → https://example.com/
var resp: HTTPResponse := HTTPSendWithRedirects(req);
HTTPResponseFree(resp);
HTTPSend und alle darauf aufbauenden Funktionen dekodieren Transfer-Encoding: chunked automatisch — kein manuelles Chunk-Parsing nötig.HTTPSendWithRedirects folgt 3×x-Antworten bis zu HTTP_MAX_REDIRECTS (10) Hops. Ein Wechsel von HTTP auf HTTPS (Location: https://...) wird transparent über TLS abgewickelt.HTTPSetHeader ist funktional: Jeder Aufruf gibt einen neuen heap-alloc'd String zurück. Der alte Wert (Eingabe hdrs) wird intern freigegeben — den Rückgabewert immer verwenden, nicht den alten hdrs-Wert weiterverwenden.HTTPGetHeader ist case-insensitiv: Content-Type, content-type und CONTENT-TYPE liefern denselben Treffer.HTTPResponseFree gibt headersRaw frei: Kein separates Freigeben nötig — ein Aufruf reicht für alle alloc'd Felder der Response.HTTPSetBasicAuth berechnet base64(user:pass) intern — keine externe Base64-Funktion nötig.std.net.tls verfügbar sein.Letzte Aktualisierung: 2026-06-06
| Signatur | Beschreibung |
|---|---|
HTTPGetWithRedirects(host: int64, path: int64): HTTPResponse | GET, das Weiterleitungen selbständig verfolgt |
Ein gewöhnliches HTTPGet liefert die Antwort so, wie sie kommt — bei 301 oder 302 also die Weiterleitung selbst, nicht das Ziel. Diese Fassung geht den Weg zu Ende.
Seit 1.0.20A liefert HTTPGetHeader nur noch den Wert der gesuchten Zeile (#1452). Vorher kam der Wert plus alle folgenden Kopfzeilen zurück, und gesucht wurde ohne Zeilenanker — ein Type traf damit auch mitten in einem fremden Wert. Ebenfalls neu: headerCount wird tatsächlich gesetzt (#1453); eine Schleife darüber lief bis dahin null Mal.
import std.net.http;
fn main(): int64 {
var r: HTTPResponse := HTTPGet("example.com" as int64, "/" as int64);
PrintLn("status = ", IntToStr(r.statusCode));
PrintLn("headerCount = ", IntToStr(r.headerCount));
PrintLn("contentLength = ", IntToStr(r.contentLength));
PrintLn("bodySize = ", IntToStr(r.bodySize));
PrintLn("Content-Type = '", HTTPGetHeader(r, "Content-Type" as int64) as pchar, "'");
return 0;
}
status = 200
headerCount = 11
contentLength = 0
bodySize = 571
Content-Type = 'text/html'
<WRAP alert>
contentLength und bodySize können auseinanderfallen. Im Lauf oben ist contentLength 0, obwohl 571 Byte ankamen — die Gegenstelle hat Transfer-Encoding: chunked benutzt und deshalb gar kein Content-Length geschickt.
Das ist sachlich richtig, am Feldnamen aber nicht zu erkennen. Für die tatsächliche Länge des Rumpfes ist bodySize zuständig, nicht contentLength. Wer über contentLength schleift, verarbeitet bei jeder chunked-Antwort null Bytes.
</WRAP>