Read misc.httpmethod, misc.protocol and misc.port from their IANA registries #26

Merged
lilleman merged 16 commits from iana-network-tables into main 2026-09-20 00:50:35 +02:00
5 changed files with 51 additions and 56 deletions
Showing only changes of commit caec22001d - Show all commits
+5 -4
View File
@@ -44,10 +44,11 @@ replacement, and each removed path, column or flag.
`device` and `os` columns. `misc.car` keeps its makes and models in a `make` and a
`model` column.
- `misc.httpmethod`, `misc.protocol` and `misc.port` are IANA's registries as tables.
`misc.httpmethod` carries `safe` and `idempotent` beside the method; `misc.protocol`
the keyword, its `number` and its `name`, selectable by either; `misc.port` renders a
TCP port number, with the IANA `service` name beside it, keeping the first service the
registry describes for a port so a number selects one row.
`misc.httpmethod` is the nine methods the HTTP core specification defines, carrying
`safe` and `idempotent` as `true` or `false`; `misc.protocol` the keyword, its
`number` and its `name`, selectable by either; `misc.port` renders a TCP port number,
with the IANA `service` name beside it, keeping the first service the registry
describes for a port so a number selects one row.
- `geo.SE` and `geo.US`: five linked tables per country, `region`, `municipality`,
`locality`, `postal-code` and `street`, weighted by population and address counts
and built from SCB, GeoNames, Trafikverket NVDB and the US Census Bureau, and an
+16 -4
View File
@@ -170,10 +170,18 @@ which `--list` shows. `car`, `currency`, `httpmethod`, `httpstatus`, `language`,
`mimetype`, `port`, `protocol`, `territory`, `timezone` and `useragent` are
[tables](#table), so `misc.territory[SE].capital` and `misc.currency[Euro].symbol`
select a row; `car` and `useragent` carry no key or name, so they are drawn from rather
than selected in. `misc.httpmethod`, `misc.protocol` and `misc.port` are IANA's
registries: a method carries the register's `yes` or `no` for `safe` and `idempotent`,
a protocol its `number` and its spelled-out `name`, and `misc.port` renders the number
a port field holds, with the IANA `service` name beside it.
than selected in.
`misc.httpmethod`, `misc.protocol` and `misc.port` are IANA's registries.
`misc.httpmethod` is the nine methods the HTTP core specification defines, not the
WebDAV extensions the register also holds, and its `safe` and `idempotent` are `true`
or `false`, so a Go `bool` reads them. `misc.protocol` carries a `number` and a `name`,
the keyword itself where the register spells none out, and selects by either spelling.
`misc.port` is the TCP assignments, rendering the number a port field holds with the
IANA `service` beside it, and selecting by number alone. A draw spans the whole
register, so pin `misc.port[443]` where a fixture needs a port a reader recognises;
it stops at 49150, IANA assigning nothing above, so an ephemeral source port is
`{int(49152,65535)}`.
[`DATA-LICENSES.md`](DATA-LICENSES.md) names each table's source and licence.
`misc.timezone` is every zone tzdb gives a shipped territory, from one apiece for most
@@ -1188,6 +1196,10 @@ the Development section below, and who ships a register the four above then draw
worth more than the last rows of a table. Where no such link can hold the fact
stays a column. Layer your own `misc.territory` over the shipped one and you
must layer `misc.timezone` too, or the link fails at load naming the row.
- **`misc.port` selects by number, and carries no `name`.** 29 of its services sit on
more than one port, `http-alt` on three, so `misc.port[http-alt]` could name no one
row. The number is what a port field holds anyway, and `misc.port[443].service`
reads the other way.
- **`misc.car` is one flat table, not a make linked to its models.** A row is a make
and a model drawn together, so no render pairs a Volvo with a RAV4. Two linked
tables would reach the same pairs and add a selector nothing asks for; a make alone
+16 -8
View File
@@ -3,8 +3,10 @@
data-import/httpmethod.py [--source URL_OR_FILE] [--cache DIR] [--out FILE]
A row needs a name of letters and hyphens, which drops the registry's `*`, and both of
the answers the registry gives for it.
A method ships when the register cites the HTTP core specification for it, RFC 9110
section 9.3 or RFC 5789, which is the nine a request carries; the WebDAV and DeltaV
extensions the register also holds do not. The register's `yes` and `no` ship as `true`
and `false`, which a consumer's boolean reads.
"""
import argparse
import csv
@@ -20,19 +22,23 @@ SOURCE = "https://www.iana.org/assignments/http-methods/methods.csv"
OUT = Path(__file__).resolve().parent.parent / "data" / "misc" / "httpmethod.tsv"
CACHE = Path(__file__).resolve().parent / "cache"
COLUMNS = ["idempotent", "method", "safe"]
ANSWERS = ("yes", "no")
CORE = re.compile(r"\[RFC9110, Section 9\.3\.|\[RFC5789, Section 2\]")
BOOLEAN = {"yes": "true", "no": "false"}
EXPECTED = 9
def rows(text):
for r in csv.DictReader(io.StringIO(text)):
method = (r["Method Name"] or "").strip()
safe, idempotent = (r["Safe"] or "").strip(), (r["Idempotent"] or "").strip()
if not re.fullmatch(r"[A-Za-z][A-Za-z-]*", method) or not safe or not idempotent:
if not CORE.search(r["Reference"] or ""):
continue
for column, answer in (("Safe", safe), ("Idempotent", idempotent)):
if answer not in ANSWERS:
answers = {}
for column in ("Safe", "Idempotent"):
answer = (r[column] or "").strip()
if answer not in BOOLEAN:
sys.exit(f"{method}: {column} {answer!r} is neither yes nor no")
yield {"idempotent": idempotent, "method": method, "safe": safe}
answers[column] = BOOLEAN[answer]
yield {"idempotent": answers["Idempotent"], "method": method, "safe": answers["Safe"]}
def main():
@@ -42,6 +48,8 @@ def main():
p.add_argument("--out", default=str(OUT))
a = p.parse_args()
table = sorted(rows(source.fetch(a.source, a.cache, "http-methods.csv").decode("utf-8")), key=lambda r: r["method"])
if len(table) != EXPECTED:
sys.exit(f"{len(table)} methods cite the core specification, not {EXPECTED}; the register's Reference column has moved")
tsv.write(a.out, COLUMNS, table)
+9 -40
View File
@@ -1,41 +1,10 @@
idempotent method safe
yes ACL no
yes BASELINE-CONTROL no
yes BIND no
yes CHECKIN no
yes CHECKOUT no
no CONNECT no
yes COPY no
yes DELETE no
yes GET yes
yes HEAD yes
yes LABEL no
yes LINK no
no LOCK no
yes MERGE no
yes MKACTIVITY no
yes MKCALENDAR no
yes MKCOL no
yes MKREDIRECTREF no
yes MKWORKSPACE no
yes MOVE no
yes OPTIONS yes
yes ORDERPATCH no
no PATCH no
no POST no
yes PRI yes
yes PROPFIND yes
yes PROPPATCH no
yes PUT no
yes QUERY yes
yes REBIND no
yes REPORT yes
yes SEARCH yes
yes TRACE yes
yes UNBIND no
yes UNCHECKOUT no
yes UNLINK no
yes UNLOCK no
yes UPDATE no
yes UPDATEREDIRECTREF no
yes VERSION-CONTROL no
false CONNECT false
true DELETE false
true GET true
true HEAD true
true OPTIONS true
false PATCH false
false POST false
true PUT false
true TRACE true
1 idempotent method safe
2 yes false ACL CONNECT no false
3 yes true BASELINE-CONTROL DELETE no false
4 yes true BIND GET no true
5 yes true CHECKIN HEAD no true
6 yes true CHECKOUT OPTIONS no true
7 no false CONNECT PATCH no false
8 yes false COPY POST no false
9 yes true DELETE PUT no false
10 yes true GET TRACE yes true
yes HEAD yes
yes LABEL no
yes LINK no
no LOCK no
yes MERGE no
yes MKACTIVITY no
yes MKCALENDAR no
yes MKCOL no
yes MKREDIRECTREF no
yes MKWORKSPACE no
yes MOVE no
yes OPTIONS yes
yes ORDERPATCH no
no PATCH no
no POST no
yes PRI yes
yes PROPFIND yes
yes PROPPATCH no
yes PUT no
yes QUERY yes
yes REBIND no
yes REPORT yes
yes SEARCH yes
yes TRACE yes
yes UNBIND no
yes UNCHECKOUT no
yes UNLINK no
yes UNLOCK no
yes UPDATE no
yes UPDATEREDIRECTREF no
yes VERSION-CONTROL no
+5
View File
@@ -103,6 +103,11 @@ by a `data-import/` script, as README goal 10 asks.
- Add `{base64url(n)}` for JWT shapes.
- Add a `unix` layout to `date()` once something needs it.
- Name a spelling that works when a row selector misses: `misc.protocol[tcp]`,
`misc.httpmethod[get]` and `misc.territory[se]` all answer "no row … has key or name"
and stop there, where a case-insensitive match could name the row that exists, and a
table with no `name` column could say it selects by key alone.
### Open questions to settle
- Decide whether `misc.browser` becomes a parent of `misc.useragent`, so