Skip to content

Release 2.1.2

Latest

Choose a tag to compare

@objecthub objecthub released this 15 Oct 23:39

2.1.2 adds request.rawParams and makes the errors of the framework LocalizedErrors. It is source-compatible with 2.1.x: swift package diagnose-api-breaking-changes 2.1.1 reports no breaking changes.

New: request.rawParams

request.params holds the values of route variables decoded, so a%2Fb/c and a/b/c both give a/b/c for a path variable. request.rawParams has the same names with the values as the client sent them, still percent-encoded and not decoded at all (a + stays a +).

server.get["/files/::path"] = { request in
  let decoded = request.params["path"] ?? ""     // "a/b/c" for GET /files/a%2Fb/c
  let raw = request.rawParams["path"] ?? ""      // "a%2Fb/c"
  return .ok(.text("\(decoded) was sent as \(raw)"))
}

A variable :name gets its raw segment, and a path variable ::name its raw segments joined with /. As in params, empty segments are left out, a path variable that matches nothing has the value "", and the query is not part of a value. Like params, it is set when the request has been routed: in handlers, and in middleware after next has returned. A raw value is untrusted input: decode it at most once, and never use it as a file path without checking it.

Routers: the protocol NanoHTTPRouter has a new requirement routeWithRawParams(_:path:) with a default implementation, so existing routers keep working (their rawParams stay empty). NanoHTTPSegmentRouter implements it.

New: errors are LocalizedErrors

All error types (NanoHTTPError, NanoSocketError, NanoHTTPParserError, NanoHTTPRouterError, NanoFileError, NanoHTTPResponse.ResponseError, NanoWebSocketSession.WsError and .Control) now say what failed in error.localizedDescription, instead of Foundation's generic text:

Unable to bind the socket to the address: Address already in use
404 Not Found: There is no item 7
The request line is not of the form METHOD TARGET VERSION: "BAD"

The texts are in English. Text that a client sent is quoted and escaped in them, so a control character cannot get into a log. description and string interpolation ("\(error)") are unchanged, and the server still answers every error but a NanoHTTPError with a 500 without details.

Notes on upgrading

  • A subclass of NanoHTTPSegmentRouter that overrides route(_:path:) to change how requests are routed has to override routeWithRawParams(_:path:) instead: the server now calls that function.
  • If your program declares extension NanoSocketError: LocalizedError (or the same for another of these types) itself, remove it.

Other

  • Router lookups of paths without percent-escapes are a little faster; paths with escapes take about 0.1–0.15 µs longer. Paired benchmarks against 2.1.1 show no difference in throughput or latency.
  • The tests of NanoProcessTests that send a signal to the test process are skipped under a debugger: lldb (and so Xcode) stops the process at SIGUSR1/SIGUSR2, and the test run seemed not to end.

Install: .package(url: "https://github.com/objecthub/swift-nanohttp.git", from: "2.1.2")