Reliable Server Side Swift ✭ Make Apache great again!

Overview

mod_swift

Apache 2 Swift3 macOS tuxOS Raspiberry Pi Travis

mod_swift is a technology demo which shows how to write native modules for the Apache Web Server in the Swift 3 programming language. The demo includes a C module to load Swift modules, a basic demo module, the ApacheExpress framework which provides an Express like API for mod_swift, a demo for ApacheExpress, a Todo MVC backend (w/ CalDAV support!), and a few supporting libraries (such as Freddy or Noze.io Mustache).

Server Side Swift the right way. Instead of reinventing the HTTP server, hook into something that just works and is battle proven. And comes with HTTP/2 as well as TLS support out of the box 🤓 (If you don't care, Noze.io might be something for you.)

What is an Apache module?

Well, Apache is a highly modular and efficient server framework. The httpd daemon itself is quite tiny and pretty much all webserver functionality is actually implemented in the form of modules. Be it thread handling, access control, mime detection or content negotation - all of that is implemented as modules. And can be replaced by own modules!

The Apache core modules are written in portable C. Some modules are built right into the server, but most are loaded as dynamic libraries. Which ones is specified by the user in the configuration file, e.g.:

LoadModule authz_core_module /usr/libexec/apache2/mod_authz_core.so
LoadModule mime_module       /usr/libexec/apache2/mod_mime.so

Now with mod_swift you can write such modules using the Swift programming language. Enter:

LoadSwiftModule ApacheMain /usr/libexec/apache2/mods_demo.so

This is a little different to something like mod_php which enables Apache to directly interpret PHP scripts. mod_php itself is C software and a single module. Since Swift compiles down to regular executable binaries, and because Swift has excellent C integration, you can write arbitrary modules with mod_swift which behave just like the regular C modules.

This is boring, show us something!

OK, ok. So in short with mod_swift you can extend Apache in many many ways, or just write dynamic HTTP endpoints, be it dynamically generated web pages or web services. There is no interpreter or JVM or proxy, the compiled Swift code runs directly as part of Apache - a.k.a. superfast. Here is your screenshot:

and here is some code used to generate that page (shortened, full):

let sampleDict  : [ String : Any ] = [
  "name"        : "Chris",
  "value"       : 10000,
  "taxed_value" : Int(10000 - (10000 * 0.4))
]

func MustacheHandler(p: UnsafeMutablePointer<request_rec>?) -> Int32 {
  var req = ZzApacheRequest(raw: p!) // make it nicer to use
  guard req.handler == "de.zeezide.mustache" else { return DECLINED }
  
  req.contentType = "text/html; charset=ascii"
  guard let fn = req.filename else { return HTTP_NOT_FOUND }
  
  guard let template = try? String(contentsOfFile: fn) else {
    return HTTP_INTERNAL_SERVER_ERROR
  }
  req.puts(MustacheParser().parse(string: template).render(object: sampleDict))
  return OK
}

What this does is it loads a Mustache template located in the Apache documents directory. It then resolves the template from some Swift dictionary and returns the result to the browser. Note that the file lookup and all that is managed by other Apache modules, this handler is just invoked for Mustache templates (as configured in our apache.conf).

Remember that this is just a proof of concept. Quite likely you'd want some wrapper library making the Apache API a little 'Swiftier'. Also remember that you can use this not only to deliver dynamic content, but you can also use it to add new authentication modules to Apache, or write new filter modules (say one which converts XML to JSON on demand).

Know what? This looks awkwardly difficult ...

Fair enough. So we integrated a tiny subset of Noze.io to allow you to do just that. This is what it looks like:

func expressMain() {
  apache.onRequest { req, res in
    res.writeHead(200, [ "Content-Type": "text/html" ])
    try res.end("<h1>Hello World</h1>")
  }
}

And is configured like this in the Apache conf:

<LocationMatch /express/*>
  SetHandler de.zeezide.ApacheExpress
</LocationMatch>

Now you are saying, this is all nice and pretty. But what about Connect? I want to write and reuse middleware! Here you go:

func expressMain() {
  let app = apache.connect()
  
  app.use { req, res, next in
    console.info("Request is passing Connect middleware ...")
    res.setHeader("Content-Type", "text/html; charset=utf-8")
    // Note: we do not close the request, we continue with the next middleware
    try next()
  }
  
  app.use("/express/connect") { req, res, next in
    try res.write("<p>This is a random cow:</p><pre>")
    try res.write(vaca())
    try res.write("</pre>")
    res.end()
  }
}

And Express? Sure, the Apache Express is about to leave:

let app = apache.express(cookieParser(), session())

app.get("/express/cookies") { req, res, _ in
  // returns all cookies as JSON
  try res.json(req.cookies)
}

app.get("/express/") { req, res, _ in
  let tagline = arc4random_uniform(UInt32(taglines.count))
  
  let values : [ String : Any ] = [
    "tagline"     : taglines[Int(tagline)],
    "viewCount"   : req.session["viewCount"] ?? 0,
    "cowOfTheDay" : cows.vaca()
  ]
  try res.render("index", values)
}

Yes. All that is running within Apache. The working example can be found here: ExpressMain.swift. The TodoMVC is pretty neat too (and comes with a demo CalDAV/CardDAV implementation).

And how do I access MySQL/PostgreSQL/SQLite3?

Funny that you ask. A feature of Apache 2 known to few is mod_dbd. Using that you can configure a database connection within the Apache.conf and use that within all your Apache modules/handlers. It does all the pooling and maintenance required. Like so:

<IfModule dbd_module>
  DBDriver  sqlite3
  DBDParams "/var/data/testdb.sqlite3"
</IfModule>

Well, and as part of mods_baredemo we provide an example on how to use this. It looks like this:

guard let con = req.dbdAcquire()                 else { return ... }
guard let res = con.select("SELECT * FROM pets") else { return ... }

while let row = res.next() {
  req.puts("<li>\(row[0])</li>")
}

Both macOS Apache installations (system and Homebrew) include the SQLite3 driver, so we included a demo database in the data directory. On Linux you need to install the drivers you want (sudo apt-get install libaprutil1-dbd-sqlite3 libaprutil1-dbd-pgsql).
A little more work: Next you need to load mod_dbd in the proper apache.conf and specify the absolute path to the data/testdb.sqlite3 database (the path where you checked out mod_swift).
If you got that right, restart Apache and http://localhost:8042/database/ should be able to successfully query stuff.

This is wicked! How can I try it?

Easy! Just clone this repository, make and run it:

git clone https://github.com/AlwaysRightInstitute/mod_swift.git
cd mod_swift
make run

Then open http://localhost:8042/ and voilà, you should see a webpage delivered by Apache.

It works out of the box on macOS 10.11+ with Xcode 8 and the builtin system Apache (no Apache install required!), with the Homebrew Apache 2.4 on macOS (brew install homebrew/apache/httpd24), and on Linux (tested with Ubuntu 16.04).

On Linux you need to hack /usr/include/apr-1.0/apr.h and add a typedef int pid_t; just below the MingW section to make swiftc behave.

To explore and hack the code, just open the UseMe.xcworkspace. You can run everything directly from within Xcode.

Don't be afraid, the Apache invoked here doesn't interfere with your system Apache at all (but uses it, Apache is part of all macOS installs). It uses the apache.conf included in this repo, runs against the DocRoot included in this repo and loads the libraries from the Xcode build dir (hardcoded to SRCROOT/.libs).

You want an intro into Apache module programming? Try this: Developing modules for the Apache HTTP Server 2.4.

Various Notes of Interest

  • The code is properly formatted, max width 80 chars, 2-space indent.

  • ApacheExpress is just code copy/pasted in from Noze.io. It may very well be non-sensical in the context of Apache :-)

  • This doesn't use apxs because that is badly b0rked on both 10.11 and 10.12.

  • It uses a lot of hardcoded load and lookup pathes, remember, it is a demo!

  • It has some leaks and issues, e.g. modules are not properly unloaded.

  • Sure, you can link against arbitrary Swift dylibs, mustache is an example for exactly that.

  • However, you currently cannot use the Swift Package Manager to create dylibs (AFAIK). So while in theory that would work, you need to do the final linking step separately.

  • Yes mod_swift itself could be avoided by including the .c in the Swift module. Yes, you can even statically link Swift including its runtime. Let me know if this is interesting, I have a branch which does exactly that.

  • There is one big bet in the code: Officially there is no way to invoke a Swift function from C, only the other way around! In other words: it is pure luck that this works and is ABI compatible with C.

  • If you would want to debug the stuff in Xcode - /usr/sbin/httpd is under macOS SIP.

  • On macOS 10.11 starting Apache with -X crashes a few seconds after the last request was received. Maybe just SIGPIPE or sth. 10.12 looks fine.

  • Unloading is an issue. I think the Apple and GNUstep Objective-C runtimes cannot be properly unloaded (I've heard there is a great runtime that can). No idea what the situation with 'pure Swift' is.

  • Would be cool if Swift 4 would get a proper extern C {}.

  • Yes, Apache content handlers are not Noze.io like asynchronous but run in a traditional, synchronous thread-setup.

  • Apache varargs funcs are not available since Swift doesn't support such. We provide a wrapper for ap_log_rerror_, other funcs would need to be wrapped the same way.

  • Apache also uses quite a few #defines, e.g. ap_fwrite

  • The Apache C headers are prone to crash swiftc. Which is why we wrap the Apache request_rec in an additional struct.

            (__)
          /  .\/.     ______
         |  /\_|     |      \
         |  |___     |       |
         |   ---@    |_______|
      *  |  |   ----   |    |
       \ |  |_____
        \|________|
    

    CompuCow Discovers Bug in Compiler

Oh, ages ago I did mod_objc for Apache 1.3.

Status

This is a demo. Do not use it for realz.

Who

mod_swift is brought to you by The Always Right Institute and ZeeZide. We like feedback, GitHub stars, cool contract work, presumably any form of praise you can think of. We don't like people who are wrong.

There is a #mod_swift channel on the Noze.io Slack.

You might also like...
High Performance (nearly)100% Swift Web server supporting dynamic content.

Dynamo - Dynamic Swift Web Server Starting this project the intention was to code the simplest possible Web Server entirely in Swift. Unfortunately I

Super lightweight async HTTP server library in pure Swift runs in iOS / MacOS / Linux

Embassy Super lightweight async HTTP server in pure Swift. Please read: Embedded web server for iOS UI testing. See also: Our lightweight web framewor

Tiny http server engine written in Swift programming language.

What is Swifter? Tiny http server engine written in Swift programming language. Branches * stable - lands on CocoaPods and others. Supports the latest

PillowTalk - An iOS & SwiftUI server monitor tool for linux based machines using remote proc file system with script execution.
PillowTalk - An iOS & SwiftUI server monitor tool for linux based machines using remote proc file system with script execution.

An iOS & SwiftUI server monitor tool for linux based machines using remote proc file system with script execution.

A small, lightweight, embeddable HTTP server for Mac OS X or iOS applications

CocoaHTTPServer CocoaHTTPServer is a small, lightweight, embeddable HTTP server for Mac OS X or iOS applications. Sometimes developers need an embedde

GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to be embedded in iOS, macOS & tvOS apps.

GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to be embedded in iOS, macOS & tvOS apps. It was written from scr

iOS Tweak to redirect Discord API calls to a Fosscord server.

FosscordTweak iOS Tweak to redirect Discord API calls to a Fosscord server. Installation Manual Download .deb file from release and install on jailbro

 🪶 Feather is a modern Swift-based content management system powered by Vapor 4.
🪶 Feather is a modern Swift-based content management system powered by Vapor 4.

Feather CMS 🪶 🪶 Feather is a modern Swift-based content management system powered by Vapor 4. 💬 Click to join the chat on Discord. Requirements To

A dockerized microservice written in Swift using Vapor.

price-calculation-service-swift This is an example project for a university project. It uses Vapor to serve a microservice written in Swift. The point

Releases(0.7.6)
  • 0.7.6(Apr 21, 2017)

    Minor adjustments, the main feature being a demo of a typesafe-select in mods_baredemo.

    dbd.select("SELECT * FROM pets") { (name : String, count : Int?) in
      req.puts("<tr><td>\(name)</td><td>\(count)</td></tr>")
    }
    

    No manual mapping required, the required static Swift types are the closure types.

    Source code(tar.gz)
    Source code(zip)
  • 0.7.5(Feb 14, 2017)

    As part of mod_swift we have been shipping mods_todomvc. Which is an implementation of a Todo-Backend, a simple JSON API to access and modify a list of todos. This release takes Todo-Backend one step further: Access the todos using CalDAV!

    That's it. Demos how to implement a basic CalDAV/CardDAV server using Swift.

    Source code(tar.gz)
    Source code(zip)
  • 0.7.0(Feb 6, 2017)

    We prefer the Elephant, a lot. It is the right thing.

    mod_swift 0.7.0 brings you support for accessing SQL database using Apache mod_dbd. Yes, Apache even includes SQL database support!

    Enough words, this is how the code looks like:

    guard let con = req.dbdAcquire()                 else { return ... }
    guard let res = con.select("SELECT * FROM pets") else { return ... }
    
    while let row = res.next() {
      req.puts("<li>\(row[0])</li>")
    }
    

    And the config looks like so:

    <IfModule dbd_module>
      DBDriver  sqlite3
      DBDParams "/var/data/testdb.sqlite3"
    </IfModule>
    

    The release contains a very simple/basic wrapper library to make access to mod_dbd nicer, but is far from being a complete solution. Stay tuned.

    Source code(tar.gz)
    Source code(zip)
  • 0.6.0(Feb 5, 2017)

    This release brings support for using mod_swift on Ubuntu (presumably any Linux) and with Apache 2.4 servers installed via Homebrew.

    Get ready to deploy!!!

    Source code(tar.gz)
    Source code(zip)
  • 0.5.0(Jan 29, 2017)

  • 0.4.0(Jan 29, 2017)

    Modularized the codebase. Instead of having one big project, there are now multiple. This provides both, a raw Apache API for those who want very little, and a Noze.io based Express framework which provides Node.js like convenience.

    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Jan 27, 2017)

    This:

    let app = express(cookieParser(), session())
    
    app.get("/express/cookies") { req, res, _ in
      // returns all cookies as JSON
      try res.json(req.cookies)
    }
    
    app.get("/express/") { req, res, _ in
      let tagline = arc4random_uniform(UInt32(taglines.count))
    
      let values : [ String : Any ] = [
        "tagline"     : taglines[Int(tagline)],
        "viewCount"   : req.session["viewCount"] ?? 0,
        "cowOfTheDay" : cows.vaca()
      ]
      try res.render("index", values)
    }
    

    and more.

    Also: leftpad.

    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Jan 26, 2017)

    Integrated a tiny subset of Noze.io. This makes writing simple handlers, well simple:

    apache.onRequest { req, res in
      res.writeHead(200, [ "Content-Type": "text/html" ])
      try res.end("<h1>Hello World</h1>")
    }
    
    Source code(tar.gz)
    Source code(zip)
  • 0.1.0(Jan 26, 2017)

Owner
The ApacheExpress Alliance
Reliable Server Side Swift ✭ Make Apache great again!
The ApacheExpress Alliance
💧 A server-side Swift HTTP web framework.

Vapor is an HTTP web framework for Swift. It provides a beautifully expressive and easy-to-use foundation for your next website, API, or cloud project

Vapor 22.4k Jan 3, 2023
A light-weight server-side service framework written in the Swift programming language.

Smoke Framework The Smoke Framework is a light-weight server-side service framework written in Swift and using SwiftNIO for its networking layer by de

Amazon 1.4k Dec 22, 2022
Swift Express is a simple, yet unopinionated web application server written in Swift

Documentation <h5 align="right"><a href="http://demo.swiftexpress.io/">Live ?? server running Demo <img src="https://cdn0.iconfinder.com/data/icons/

Crossroad Labs 850 Dec 2, 2022
Swift backend / server framework (Pure Swift, Supports Linux)

NetworkObjects NetworkObjects is a #PureSwift backend. This framework compiles for OS X, iOS and Linux and serves as the foundation for building power

Alsey Coleman Miller 258 Oct 6, 2022
Simple server APIs in Swift

Simple server APIs in Swift

null 4 Apr 25, 2022
Tiny http server engine written in Swift programming language.

What is Swifter? Tiny http server engine written in Swift programming language. Branches * stable - lands on CocoaPods and others. Supports the latest

null 3.6k Dec 31, 2022
Swift HTTP server using the pre-fork worker model

Curassow Curassow is a Swift Nest HTTP Server. It uses the pre-fork worker model and it's similar to Python's Gunicorn and Ruby's Unicorn. It exposes

Kyle Fuller Archive 397 Oct 30, 2022
Lightweight library for web server applications in Swift on macOS and Linux powered by coroutines.

Why Zewo? • Support • Community • Contributing Zewo Zewo is a lightweight library for web applications in Swift. What sets Zewo apart? Zewo is not a w

Zewo 1.9k Dec 22, 2022
libuv base Swift web HTTP server framework

Notice Trevi now open a Trevi Community. Yoseob/Trevi project split up into respective Trevi, lime, middlewares and sys packages at our community. If

leeyoseob 46 Jan 29, 2022
A Swift web framework and HTTP server.

A Swift Web Framework and HTTP Server Summary Kitura is a web framework and web server that is created for web services written in Swift. For more inf

Kitura 7.6k Dec 27, 2022