std.net.http
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);
Imports
std.net.socketstd.net.dnsstd.net.typesstd.stringstd.base64
Konstanten
| 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 |
Typen
HTTPResponse (struct)
| 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 |
HTTPRequest (struct)
| 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 |
Funktionen
Einfache Convenience-Funktionen
| 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) |
Header-Varianten (mit vorgebautem Header-String)
| 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 |
Request-Builder und Low-Level-API
| 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 |
Header-Builder
| 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 |
Response-Zugriff
| 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 |
Codebeispiele
PUT mit Bearer-Token
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);
Response-Header lesen
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);
Redirect-Folgen (HTTP → HTTPS)
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);
Hinweise
- Chunked Transfer-Encoding:
HTTPSendund alle darauf aufbauenden Funktionen dekodierenTransfer-Encoding: chunkedautomatisch — kein manuelles Chunk-Parsing nötig. - Redirects:
HTTPSendWithRedirectsfolgt 3×x-Antworten bis zuHTTP_MAX_REDIRECTS(10) Hops. Ein Wechsel von HTTP auf HTTPS (Location: https://...) wird transparent über TLS abgewickelt. HTTPSetHeaderist funktional: Jeder Aufruf gibt einen neuen heap-alloc'd String zurück. Der alte Wert (Eingabehdrs) wird intern freigegeben — den Rückgabewert immer verwenden, nicht den altenhdrs-Wert weiterverwenden.HTTPGetHeaderist case-insensitiv:Content-Type,content-typeundCONTENT-TYPEliefern denselben Treffer.HTTPResponseFreegibtheadersRawfrei: Kein separates Freigeben nötig — ein Aufruf reicht für alle alloc'd Felder der Response.- Basic Auth (RFC 7617):
HTTPSetBasicAuthberechnetbase64(user:pass)intern — keine externe Base64-Funktion nötig. - TLS-Redirects: Für den HTTPS-Hop im Redirect-Pfad muss
std.net.tlsverfügbar sein.
Letzte Aktualisierung: 2026-06-06
Weiterleitungen automatisch folgen
| 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.
Kopfzeilen lesen
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>
