General points

  • Swiftfire is a GUI-less server application for OS-X that can service HTTP(S) v1.0 and v1.1 requests.

  • It does not need any additional tools or services.

  • Swiftfire can be monitored and controlled via an administration account which is created during initial setup.

  • Currently Swiftfire can only be installed by downloading the sourcecode and compiling it.

  • At a minimum the user must configure the service port number and 1 domain. This is described in Quick Setup

Starting with Swiftfire development

There are three hooks into Swiftfire that are of interest when starting out:

  • Custom.swift
    • Contains the “customSetup” that is called by Swiftfire after the Swiftfire setup is complete, but before the servers (HTTP and HTTPS) are started.
  • Service.Registration.swift
  • Function.Registration.swift

Specific notes

Logging

Logging has 8 levels in Swiftfire:

DEBUG     = 0
INFO      = 1
NOTICE    = 2
WARNING   = 3
ERROR     = 4
CRITICAL  = 5
ALERT     = 6
EMERGENCY = 7
NONE      = 8

When configuring loglevels an integer is used. The value 8 means that no logging is done, a value of 0 means that all possible logging is done. Note that logging levels 0 and 1 do not work for the ASL (Apple System Log) unless some extra configuration is done of certain OS-X properties (see blog)

Accepting HTTP(S) requests

Swiftfire uses a connection-object pool to handle incoming requests. When all connection objects are in-use new connection requests will have to wait. There is parameter that controls how many connection-objects are created. Another parameter controls how many connection requests will be kept “waiting”. When all connection objects are in use and the number of waiting requests is reached, new requests will be rejected immediately.

Client requests can thus be handled in a couple of ways:

  1. They are accepted and complete nominally. The user notices nothing.
  2. They have to wait, but are accepted before the time-out and terminate nominally. The user experiences a delay.
  3. They have to wait and are not accepted before the time-out expires. These requests are rejected after the time-out. The user experiences a “server busy” after a delay.
  4. They are rejected immediately. The user immediately experiences a “server busy”.

No 1 should be normal case, no 2 is acceptable if it does not happen too often. No 3 & 4 should be avoided except for rare circumstances.

The number of connection objects is equal to the number of parallel client requests that can be handled. The more parallel client requests are handled, the more “sluggishness” the end user experiences. Hence there is a trade-off point where adding more connection-objects no longer improves user experience. Unfortunately there is no easy way to calculate this number. It depends on the system (hardware) the type of website, as well as the way the typical user chooses to interact with the site.

The only way to achieve the “correct” number of objects is to keep track of end-user complaints concerning the system performance and to balance “sluggish” complaints with “unreachable” complaints such that the minimum number of complaints is received.

A very simple, completely static, website running on a system with an SSD drive should be able to handle roughly as many requests per second as there are connection objects (if the keep-alive-inactivity is set to 1 second)

Performance

A difficult subject. Running on a mac mini with SSD (Late 2014, MacOS 10.12.5, 2.8 GHz i5), we often see round trip times of about 2 mS per request for static pages (i.e. no functions) with full logging enabled (which is quite a lot). This includes blacklisting and session (cookie based) processing.

Returning the server admin ‘Domains - edit’ page -which is completely created by Swift code- takes 8mS.

Obviously the more functions a page contains, the more the raw processing power of the server will drive the performance.