Hosting Web content in Warp 10

Why bother with a dedicated web server when Warp 10 can host your Web content?

Hosting Web Content in Warp 10

We introduced the Warp 10 HTTP Plugin in 2018 as part of the 2.0 release. This post aims at demonstrating how you can use this plugin to host the content of a complete website. As an immediate spoiler, know that the Warp 10 Sandbox is entirely hosted on Warp 10.

Overview

The HTTP Plugin works by executing WarpScript code for specific HTTP requests, passing the parameters to the said code. The idea behind the hosting of any Web content in Warp 10 is to define a set of macros, one for each resource you want to serve, and to call those macros from the routing macro defined in your HTTP Plugin configuration.

Generating content macros

Each static resource in your Web content should be converted to a WarpScript macro. The behavior of those macros is very simple. They simply return the content of the original file from which they were generated.

As an example, the macro for the Sandbox main page is:

'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'
B64-> UNGZIP
 'bytes' STORE
<% !$bytes %>

This macro returns a byte array containing the actual page. This macro is available on the sandbox as @sandbox.senx.io/index.html. The content returned by this macro will be returned by the routing macro to the requesting browser, along with the right set of HTTP headers.

The following shell script will generate WarpScript macros for a hierarchy of files. Run it from the root of the content you wish to convert and pipe its output to a tar -cT - command to create an archive of all the generated macros.

./convert.sh | tar -cT - >../macros.tar
#!/bin/sh
## Convert each file in a hierarchy into a WarpScript™ macro which produces the content of the file as a byte array
## Pipe into tar -T - > macros.tar
find . -type f | while read f
do
  CONTENT=`gzip -9c "${f}"|base64 -i -w0 - `
  cat <<EOF > "${f}.mc2"
'${CONTENT}' B64-> UNGZIP 'bytes' STORE
<%
  !\$bytes
%>
EOF
done

find . -name "*.mc2"

On the machine running your Warp 10 instance, create a directory under macros and untar the content of the archive you just created. We will assume the directory you created is called webcontent.

Declaring a routing macro

Now that you have converted your content, you need to configure the HTTP Plugin to serve it. You can do it in two steps. First you have to enable the HTTP Plugin, then you need to create a WarpScript file describing how you will serve your content. Such a file is shown below:

//
// These are the MIME types we support
//
{
  'html' 'text/html'
  'js' 'text/javascript'
  'png' 'image/png' 
  'jpg' 'image/jpeg' 
  'jpeg' 'image/jpeg'
  'svg' 'image/svg+xml'
  'css' 'text/css' 
  'woff' 'font/woff' 
  'woff2' 'font/woff2'
} 'MIMETYPES' STORE
           
{
  // Our macro will serve anything under '/'
  'path' '/'  // '/' is only a prefix, we will consider any path under '/'
  'prefix' true  // This is the macro executed for each request
  'macro' <%
    // Disable the WarpFleet™ Resolver
    WFOFF
    
    // Extract the requested path and replace / by /index.html
    'target' GET 'target' STORE
    $target '/' ==
    <% '/index.html' 'target' STORE %> IFT
    
    // Retrieve content via a macro call, the called macro
    // is the name of the directory in which the content macros were
    // placed followed by the requested path
    '@webcontent' $target + EVAL 'body' STORE
    
    // Retrieve MIME type from extension
    $target '.*\.' '' REPLACEALL 'extension' STORE
    !$MIMETYPES $extension GET 'type' STORE
    
    // Default type is application/octet-stream
    $type ISNULL <% 'application/octet-stream' 'type' STORE %> IFT
    
    // Emit output
    {
      'body' $body
      'headers' { 'Content-Type' $type }    
    }
  %>
}

Profit!

That's all there is to it! You can now very easily host your Web content entirely in Warp 10 and not rely on an external web server, thus simplifying your overall infrastructure.