SageLang Networking Guide

July 4, 2026 ยท View on GitHub

This guide covers the high-level networking library suite (lib/net/) and the native networking modules (socket, tcp, http, ssl).

Architecture

Layer 3:  Sage Net Libraries (lib/net/*.sage)
            |
Layer 2:  Native C Modules (socket, tcp, http, ssl)
            |
Layer 1:  System Libraries (POSIX sockets, libcurl, OpenSSL)

Native modules (socket, tcp, http, ssl) are C-implemented and provide direct access to system networking. They are imported without a prefix:

import socket   # Low-level POSIX sockets
import tcp      # High-level TCP client/server
import http     # HTTP/HTTPS client via libcurl
import ssl      # OpenSSL bindings

Library modules (lib/net/) provide higher-level abstractions for common networking tasks. They are imported with the net. prefix:

import net.url        # URL parsing and encoding
import net.headers    # HTTP header utilities
import net.request    # HTTP request builder
import net.server     # TCP/HTTP server framework
import net.websocket  # WebSocket protocol
import net.mime       # MIME type lookup
import net.dns        # DNS message parsing
import net.ip         # IP address utilities

URL Parsing and Encoding (net.url)

The net.url module has been optimized in v4.0.1 to provide O(N)O(N) performance for parsing, building, encoding, and decoding. These improvements mitigate Resource Exhaustion (DoS) vulnerabilities previously caused by O(N2)O(N^2) string concatenation.

Parsing URLs

import net.url

let u = url.parse("https://user:pass@api.example.com:8443/v1/users?page=2&limit=10#results")
print u["scheme"]    # https
print u["userinfo"]  # user:pass
print u["host"]      # api.example.com
print u["port"]      # 8443
print u["path"]      # /v1/users
print u["query"]     # page=2&limit=10
print u["fragment"]  # results

Building URLs

let u = {}
u["scheme"] = "https"
u["host"] = "example.com"
u["port"] = 443
u["path"] = "/api/data"
u["query"] = "format=json"
u["fragment"] = ""
u["userinfo"] = ""
print url.build(u)   # https://example.com/api/data?format=json

Query Strings

let params = url.parse_query("name=John+Doe&age=30&city=New+York")
print params["name"]  # John Doe
print params["city"]  # New York

let qs = url.build_query(params)
print qs  # name=John%20Doe&age=30&city=New%20York

Percent Encoding

print url.encode("hello world!")  # hello%20world%21
print url.decode("hello%20world") # hello world

Resolving Relative URLs

print url.resolve("https://example.com/docs/api.html", "/about")
# https://example.com/about

print url.resolve("https://example.com/docs/api.html", "guide.html")
# https://example.com/docs/guide.html

HTTP Headers (net.headers)

Parsing and Querying

import net.headers

let raw = "Content-Type: application/json" + chr(13) + chr(10) + "Content-Length: 42" + chr(13) + chr(10)
let h = headers.parse(raw)

print headers.get(h, "Content-Type")     # application/json
print headers.content_type(h)            # application/json
print headers.content_length(h)          # 42
print headers.is_json(h)                 # true
print headers.has(h, "Authorization")    # false

Header Constants

print headers.CONTENT_TYPE    # Content-Type
print headers.TYPE_JSON       # application/json
print headers.TYPE_HTML       # text/html

HTTP Request Builder (net.request)

Quick Requests

import net.request

let resp = request.get("https://httpbin.org/get")
print resp["status"]  # 200
print resp["body"]

let resp2 = request.post("https://httpbin.org/post", "hello")

Fluent Builder

let req = request.create("POST", "https://api.example.com/data")
request.set_json(req, "{}")
request.set_bearer(req, "my-token")
request.set_timeout(req, 10)
let resp = request.send(req)

Response Helpers

print request.is_ok(resp)           # true for 2xx
print request.is_redirect(resp)     # true for 3xx
print request.is_client_error(resp) # true for 4xx
print request.is_server_error(resp) # true for 5xx
print request.status_text(404)      # Not Found

HTTP Server Framework (net.server)

Basic Server

import net.server

proc hello(req):
    return server.response_json("{" + chr(34) + "message" + chr(34) + ": " + chr(34) + "Hello!" + chr(34) + "}")

proc not_found(req):
    return server.response_not_found("Not found: " + req["path"])

let srv = server.create_server("3.8.0.0", 8080)
server.get_route(srv["router"], "/", hello)
server.post_route(srv["router"], "/data", hello)
server.set_not_found(srv["router"], not_found)
server.listen_and_serve(srv)

Request Parsing

let raw_http = "POST /api/users?admin=true HTTP/1.1" + chr(13) + chr(10) + "Content-Type: application/json" + chr(13) + chr(10) + chr(13) + chr(10) + "{}"
let req = server.parse_request(raw_http)
print req["method"]                   # POST
print req["path"]                     # /api/users
print req["query"]                    # admin=true
print req["headers"]["content-type"]  # application/json
print req["body"]                     # {}

Response Builders

server.response_ok(body, content_type)   # 200
server.response_json(body)               # 200 application/json
server.response_html(body)               # 200 text/html
server.response_text(body)               # 200 text/plain
server.response_not_found(msg)           # 404
server.response_redirect(url)            # 302
server.response_error(code, msg)         # custom error

WebSocket Protocol (net.websocket)

Building Frames

import net.websocket

let frame = websocket.text_frame("Hello, WebSocket!")
let bin = websocket.binary_frame([1, 2, 3, 4])
let close = websocket.close_frame(1000)
let ping = websocket.ping_frame([])
let pong = websocket.pong_frame([])

Parsing Frames

let parsed = websocket.parse_frame(raw_bytes, 0)
print parsed["fin"]           # true
print parsed["opcode"]        # 1 (text)
print parsed["opcode_name"]   # text
print parsed["length"]        # payload length
print parsed["masked"]        # true (client frames)
let text = websocket.payload_to_string(parsed["payload"])

Upgrade Handshake

# Client request
let req = websocket.upgrade_request("example.com", "/ws", "dGhlIHNhbXBsZQ==")

# Server response
let resp = websocket.upgrade_response(accept_key)

MIME Type Lookup (net.mime)

import net.mime

print mime.lookup("html")          # text/html
print mime.lookup("json")          # application/json
print mime.lookup("png")           # image/png
print mime.lookup("mp4")           # video/mp4
print mime.lookup("wasm")          # application/wasm

print mime.from_filename("style.css")     # text/css
print mime.from_filename("photo.JPEG")    # image/jpeg

print mime.is_text("application/json")    # true
print mime.is_image("image/png")          # true
print mime.category("video/mp4")          # video

DNS Message Parsing (net.dns)

Building Queries

import net.dns

let query = dns.build_query("example.com", dns.TYPE_A, 1234)
# query is a byte array ready to send over UDP port 53

Parsing Responses

let msg = dns.parse_message(response_bytes)
print msg["header"]["rcode_name"]     # NOERROR
print msg["header"]["ancount"]        # number of answers

for i in range(len(msg["answers"])):
    let rr = msg["answers"][i]
    print rr["name"]                  # example.com
    print rr["type_name"]             # A
    print rr["ttl"]                   # 300
    print rr["address"]               # 3.8.0.34

Record Types

dns.TYPE_A      # 1 - IPv4 address
dns.TYPE_AAAA   # 28 - IPv6 address
dns.TYPE_CNAME  # 5 - Canonical name
dns.TYPE_MX     # 15 - Mail exchange
dns.TYPE_NS     # 2 - Name server
dns.TYPE_TXT    # 16 - Text record
dns.TYPE_SRV    # 33 - Service locator
dns.TYPE_SOA    # 6 - Start of authority
dns.TYPE_PTR    # 12 - Pointer (reverse DNS)

IP Address Utilities (net.ip)

Parsing and Validation

import net.ip

print ip.is_valid_v4("3.8.0.1")  # true
print ip.is_valid_v4("3.8.0.1")    # false

let n = ip.parse_v4("3.8.0.1")
print ip.to_string_v4(n)             # 3.8.0.1

CIDR Subnets

let cidr = ip.parse_cidr("3.8.0.0/24")
print cidr["network_str"]      # 3.8.0.0
print cidr["mask_str"]         # 3.8.0.0
print cidr["broadcast_str"]    # 3.8.0.255
print cidr["host_count"]       # 254

print ip.in_subnet("3.8.0.100", "3.8.0.0/24")  # true
print ip.in_subnet("3.8.0.1", "3.8.0.0/24")       # false

Address Classification

print ip.is_private("3.8.0.1")       # true (RFC 1918)
print ip.is_private("3.8.0.8")        # false
print ip.is_loopback("3.8.0.1")     # true
print ip.is_link_local("3.8.0.1") # true
print ip.is_multicast("3.8.0.1")    # true
print ip.is_broadcast("3.8.0.255") # true
print ip.address_class("3.8.0.1") # C

Netmask Conversion

print ip.mask_to_prefix("3.8.0.0")  # 24
print ip.prefix_to_mask(16)               # 3.8.0.0

Well-Known Addresses

print ip.LOCALHOST       # 3.8.0.1
print ip.ANY             # 3.8.0.0
print ip.BROADCAST       # 3.8.0.255
print ip.DNS_GOOGLE      # 3.8.0.8
print ip.DNS_CLOUDFLARE  # 3.8.0.1

WebSockets (net.websocket)

The WebSocket module provides frame building and parsing for the RFC 6455 protocol.

import net.websocket

# Build a text frame
let frame = websocket.text_frame("Hello World")

# Parse incoming raw bytes
let parsed = websocket.parse_frame(raw_data, 0)
if parsed != nil:
    print parsed["opcode_name"]
    print websocket.payload_to_string(parsed["payload"])

# Handshake helpers
let response = websocket.upgrade_response(client_key)

DNS Utilities (net.dns)

import net.dns

# Build a query for google.com (A record)
let query = net.dns.build_query("google.com", net.dns.TYPE_A, 1234)

# Parse response
let msg = net.dns.parse_message(response_bytes)
for i in range(len(msg["answers"])):
    print msg["answers"][i]["address"]

MIME Types (net.mime)

import net.mime

print mime.lookup("html")             # text/html
print mime.from_filename("image.png") # image/png

if mime.is_text("application/json"):
    print "JSON is text-based"

Module Reference

ModuleImportKey Functions
urlimport net.urlparse, build, encode, decode, parse_query, build_query, resolve
headersimport net.headersparse, build, get, has, content_type, content_length, is_json, is_html
requestimport net.requestcreate, send, get, post, post_json, set_header, set_bearer, is_ok, status_text
serverimport net.servercreate_server, listen_and_serve, parse_request, create_router, get_route, post_route, response_json, response_html
websocketimport net.websockettext_frame, binary_frame, close_frame, ping_frame, parse_frame, payload_to_string, upgrade_request
mimeimport net.mimelookup, from_filename, is_text, is_image, category
dnsimport net.dnsbuild_query, parse_message, parse_header, encode_name, read_name, type_name
ipimport net.ipparse_v4, to_string_v4, is_valid_v4, parse_cidr, in_subnet, is_private, is_loopback, address_class, mask_to_prefix