Skip to content

Perfect-FileMaker 4.0.0

Latest

Choose a tag to compare

@taplin taplin released this 13 Oct 14:44
cfb8c4f

The first release since 3.0.1 (2018). It brings the package up to Swift 6 with an async/await API, replaces Perfect-CURL with Foundation's URLSession, and closes a query-injection hole in the percent-encoder. It is a major version: every public method changed shape. Read "Breaking and behaviour changes" before upgrading.

Requirements

  • Swift tools 6.2 (// swift-tools-version: 6.2); 3.0.1 declared 4.0.
  • Platforms: macOS 12+ and iOS 15+ (newly declared; 3.0.1 declared none), and Linux. On Linux, install libxml2-dev and pkg-config for Perfect-XML.
  • Depends on Perfect-XML from: "4.0.0". Perfect-CURL is no longer a dependency, and neither is PerfectLib, which 3.0.1 got through Perfect-CURL.
.package(url: "https://github.com/PerfectlySoft/Perfect-FileMaker.git", from: "4.0.0")

CI now runs on GitHub Actions for every push and pull request: Linux (Swift 6.2 and 6.4) and macOS (Xcode 26.0.1 and 26.6), each in debug and release with warnings treated as errors, plus the tests on an iOS Simulator. There is no FileMaker Server in CI, so it runs the query-building tests and the request/response tests against a mocked URLSession; the seven live-server tests are skipped unless FILEMAKER_TESTS=1 is set. The live tests were not run for this release.

Highlights

  • async/await (#4). databaseNames(), layoutNames(database:), layoutInfo(database:layout:) and query(_:) are async throws and return their results directly.
  • URLSession networking (#4). Requests go through Foundation instead of Perfect-CURL. FileMakerServer.init gains optional parameters: useTLS: (default: HTTPS only on port 443, as before), urlSession: (default .shared; inject one for testing) and defaultTimeout: (default 5 seconds of inactivity).
  • Sendable (#4). FileMakerServer and the query and result types are Sendable.
  • Linux and iOS. The package builds and its tests pass on Linux with Swift 6.2 and 6.4, and on the iOS Simulator with Xcode 26.3 and 27; iOS 15 is declared (Perfect-XML 4.0 requires it).
  • Swift Testing. The tests moved from XCTest to Swift Testing, with new mocked-network tests for the request layer and regression tests for the escaping fixes (27 tests: 20 run without a server, 7 live). The offline tests cover layoutInfo field typing and portal definitions, portal records, layoutNames and error 401.

Breaking and behaviour changes

  • Toolchain and platforms. Swift tools 6.2 is required, with macOS 12 or iOS 15 at minimum. Upgrade: use a Swift 6.2 or newer toolchain and raise your deployment target to at least macOS 12 / iOS 15.
  • Callbacks replaced by async methods (#4). The completion: closures are gone. Upgrade: replace fms.query(q) { response in let rs = try response() … } with let rs = try await fms.query(q), and likewise for the other three methods.
  • Perfect-CURL removed (#4), and with it PerfectLib, which came in through Perfect-CURL. Upgrade: drop Perfect-CURL from your own manifest if you listed it only for this package, and add PerfectLib yourself if your code imported it without depending on it. On Linux, FoundationNetworking still links libcurl itself.
  • 5-second default inactivity timeout (#4). Each request sets URLRequest.timeoutInterval to 5 seconds; 3.0.1 set no timeout of its own. That is an inactivity timeout: the request fails if no data arrives for 5 seconds, which in practice means waiting for the first byte, while a response that keeps arriving can take longer in total. Upgrade: for servers, large finds or scripted queries that are slow to start responding, create the FileMakerServer with a longer defaultTimeout:. The methods take no per-call timeout, so use a second FileMakerServer value for the slow calls if you want to keep the short default elsewhere.
  • Connection: close on every request (#4). The header asks the server to close the connection after its response (URLSession doesn't close the socket itself), so connections aren't kept alive for reuse and the Web Publishing Engine shouldn't keep idle client sessions open. Upgrade: nothing; expect one TCP (and TLS) handshake per request.
  • Stricter percent-encoding (#4). Database, layout, field, script and sort names and query values are encoded with an allow-list of A-Z a-z 0-9 - . _ ~. 3.0.1 used PerfectLib's stringByEncodingURL, which left = * & ! ( ) ; ' , / ? @ unescaped, so a search value containing & could add query directives. Compound -query= expressions now percent-encode their parentheses. Operators are only encoded differently, not in effect: < and > are now sent literally where 3.0.1 encoded them, which decodes to the same thing. Upgrade: nothing for normal use; if you pre-escaped values yourself, stop, or they will be encoded twice.
  • Credentials over plain HTTP are logged (#4). With a user name set and TLS off (useTLS unset and port not 443), each request writes a warning to standard error. Requests still go out. Upgrade: set useTLS: true or use port 443, or pass useTLS: false knowingly and accept the warning.
  • FMPQueryField is @unchecked Sendable (#4) because its value is Any. Upgrade: pass only strings and numbers as values.

Fixes

  • #4: Query-injection hole in the percent-encoder closed (strict allow-list encoding).
  • #4: Requests time out after 5 seconds without data by default and ask the server to close the connection, after live use showed Web Publishing Engine sessions building up under crawl-style load. Queries stay POST with the query in the body, so query values don't end up in URL logs.
  • Release prep: the seven live-server tests used to return early and count as passes without a server; they now show as skipped.
  • Release prep: README corrections. It said Perfect-XML parses FMPXMLLAYOUT responses while also saying that grammar is unimplemented. Every request uses the fmresultset grammar: layoutInfo reads field names, result types and portal fields from its metadata, and FMPXMLLAYOUT and FMPXMLRESULT are not implemented. It also called Linux unverified.
  • Release prep: defaultTimeout's documentation described a per-call timeout: parameter that doesn't exist and didn't say it is an inactivity timeout; corrected. The operator comments no longer claim 3.0.1's operators were double-encoded or broken.
  • Release prep: the offline test mocks used type="text", but the code reads a field's data type from result=, so field typing was untested; mocks now match FileMaker's output.

Upgrade notes

  1. Point your dependency at from: "4.0.0" and build with Swift 6.2 or newer; raise your deployment target to macOS 12 / iOS 15. This also brings in Perfect-XML 4.0.0.
  2. Convert each callback call to try await, inside an async context.
  3. Remove Perfect-CURL from your manifest if it was there only for this package.
  4. Decide on a timeout: 5 seconds without data is short for big finds or scripted queries that are slow to start responding.
  5. Check TLS: set useTLS: explicitly if your server uses HTTPS on a port other than 443.
  6. If you escaped field values yourself before passing them in, stop.

Legacy

The pre-Swift-6 code is preserved on the legacy branch, which points at the same commit as the 3.0.1 tag. Stay on 3.0.1 if you can't move to Swift 6.2 yet.