From 6fe110be47c0fc34bc9dce6d377ce9b48ab27c2e Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Sun, 30 Aug 2026 15:34:15 +0200 Subject: feat(url): classify host as name/ipv4/ipv6 in parse and build parse() now sets hosttype ("name"/"ipv4"/"ipv6") plus a matching hostname/ipv4/ipv6 field alongside host. build() accepts those same fields when host is absent, erroring if more than one is set. classify_host is exported for standalone use; it classifies by shape (colon present -> ipv6, dotted-quad shape -> ipv4) rather than validating the address. --- docs/url.html | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) (limited to 'docs') diff --git a/docs/url.html b/docs/url.html index e03b094..788f409 100644 --- a/docs/url.html +++ b/docs/url.html @@ -140,6 +140,14 @@ Lower level components, if specified, take precedence over high level components of the URL grammar.

+

+If host is not set, the host is taken from whichever single +one of hostname, ipv4 or ipv6 is set +(hosttype is ignored when building). It is an error to set more +than one of hostname, ipv4 or ipv6 while +host is absent. +

+

The function returns a string with the built URL.

@@ -169,6 +177,62 @@ The function returns a string with the built <path> component.

+ + +

+url.classify_host(host) +

+ +

+Classifies a raw <host> string into "name", +"ipv4" or "ipv6". This is the same classification +parse uses to fill in hosttype, +exposed for callers that have a host string to classify without a full +URL to parse. +

+ +

+Host is a host string as found in a URL's authority. Any +: in host is taken as a sign of an IPv6 literal, so +the enclosing [...] brackets URLs normally require for one are +optional here: they are stripped when present, but classification does +not depend on them. +

+ +

+The function returns two values: hosttype, one of +"name", "ipv4" or "ipv6"; and host, +the input with any enclosing [...] brackets stripped, if +present. +

+ +

+Note: classification is done by exclusion of shape, not by validating +the address. A host is "ipv4" if it merely has the shape of +four dot-separated digit groups — octet ranges are not checked, +so "999.1.1.1" classifies as "ipv4" — and +"ipv6" if it merely contains a :, whether or not that +is a well-formed IPv6 address. Anything left over is "name", +whether or not it is actually a valid hostname. +

+ +
+-- load url module
+url = require("socket.url")
+
+print(url.classify_host("example.com"))
+-- name    example.com
+
+print(url.classify_host("192.168.1.1"))
+-- ipv4    192.168.1.1
+
+print(url.classify_host("[::1]"))
+-- ipv6    ::1
+
+print(url.classify_host("::1"))
+-- ipv6    ::1
+
+

@@ -230,12 +294,28 @@ parsed_url = {
  fragment = string,
  userinfo = string,
  host = string,
+  hosttype = string,
+  hostname = string,
+  ipv4 = string,
+  ipv6 = string,
  port = string,
  user = string,
  password = string
} +

+When a host is present, hosttype is set to one of +"name", "ipv4" or "ipv6", describing the +syntax of host. Exactly one of hostname, ipv4 +or ipv6 is then also set to the same value as host, +matching hosttype — the other two are left nil. +In case of an ipv6 address the brackets are stripped, both in host and ipv6. +This classification is done by +classify_host, by exclusion of +shape rather than by validating the address (see its notes). +

+
 -- load url module
 url = require("socket.url")
@@ -248,6 +328,8 @@ parsed_url = url.parse("http://www.example.com/cgilua/index.lua?a=2#there")
 --   query = "a=2",
 --   fragment = "there",
 --   host = "www.puc-rio.br",
+--   hosttype = "name",
+--   hostname = "www.puc-rio.br",
 -- }
 
 parsed_url = url.parse("ftp://root:passwd@unsafe.org/pub/virus.exe;type=i")
-- 
cgit v1.2.3-55-g6feb