From 7822f664b94255470dcb4edcd866953ec4fd9c3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jesu=CC=81s=20Gonza=CC=81lez?= <jesusgm@vmware.com>
Date: Fri, 4 Nov 2022 16:55:33 +0100
Subject: [PATCH] feat: Adding mod_wasm

---
 docs/manual/mod/allmodules.xml    |   1 +
 docs/manual/mod/mod_wasm.html     |   5 +
 docs/manual/mod/mod_wasm.html.en  | 332 +++++++++++++++++
 docs/manual/mod/mod_wasm.xml      | 326 ++++++++++++++++
 docs/manual/mod/mod_wasm.xml.meta |  12 +
 modules/wasm/Makefile.in          |  16 +
 modules/wasm/config.m4            | 150 ++++++++
 modules/wasm/mod_wasm.c           | 598 ++++++++++++++++++++++++++++++
 8 files changed, 1440 insertions(+)
 create mode 100644 docs/manual/mod/mod_wasm.html
 create mode 100644 docs/manual/mod/mod_wasm.html.en
 create mode 100644 docs/manual/mod/mod_wasm.xml
 create mode 100644 docs/manual/mod/mod_wasm.xml.meta
 create mode 100644 modules/wasm/Makefile.in
 create mode 100644 modules/wasm/config.m4
 create mode 100644 modules/wasm/mod_wasm.c

diff --git a/docs/manual/mod/allmodules.xml b/docs/manual/mod/allmodules.xml
index fb0599b4f8..c523861ccb 100644
--- a/docs/manual/mod/allmodules.xml
+++ b/docs/manual/mod/allmodules.xml
@@ -133,6 +133,7 @@
   <modulefile>mod_usertrack.xml</modulefile>
   <modulefile>mod_version.xml</modulefile>
   <modulefile>mod_vhost_alias.xml</modulefile>
+  <modulefile>mod_wasm.xml</modulefile>
   <modulefile>mod_watchdog.xml</modulefile>
   <modulefile>mod_xml2enc.xml</modulefile>
   <modulefile>mpm_common.xml</modulefile>
diff --git a/docs/manual/mod/mod_wasm.html b/docs/manual/mod/mod_wasm.html
new file mode 100644
index 0000000000..e3f1f13dba
--- /dev/null
+++ b/docs/manual/mod/mod_wasm.html
@@ -0,0 +1,5 @@
+# GENERATED FROM XML -- DO NOT EDIT
+
+URI: mod_wasm.html.en
+Content-Language: en
+Content-type: text/html; charset=UTF-8
diff --git a/docs/manual/mod/mod_wasm.html.en b/docs/manual/mod/mod_wasm.html.en
new file mode 100644
index 0000000000..f9b7946746
--- /dev/null
+++ b/docs/manual/mod/mod_wasm.html.en
@@ -0,0 +1,332 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
+<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
+<!--
+        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+              This file is generated from xml source: DO NOT EDIT
+        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+      -->
+<title>mod_wasm - Apache HTTP Server Version 2.4</title>
+<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" />
+<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" />
+<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" />
+<script src="../style/scripts/prettify.min.js" type="text/javascript">
+</script>
+
+<link href="../images/favicon.ico" rel="shortcut icon" /></head>
+<body>
+<div id="page-header">
+<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p>
+<p class="apache">Apache HTTP Server Version 2.4</p>
+<img alt="" src="../images/feather.png" /></div>
+<div class="up"><a href="./"><img title="&lt;-" alt="&lt;-" src="../images/left.gif" /></a></div>
+<div id="path">
+<a href="http://www.apache.org/">Apache</a> &gt; <a href="http://httpd.apache.org/">HTTP Server</a> &gt; <a href="http://httpd.apache.org/docs/">Documentation</a> &gt; <a href="../">Version 2.4</a> &gt; <a href="./">Modules</a></div>
+<div id="page-content">
+<div id="preamble"><h1>Apache Module mod_wasm</h1>
+<div class="toplang">
+<p><span>Available Languages: </span><a href="../en/mod/mod_wasm.html" title="English">&nbsp;en&nbsp;</a></p>
+</div>
+<table class="module"><tr><th><a href="module-dict.html#Description">Description:</a></th><td>Runs Wasm modules via Wasmtime engine
+    </td></tr>
+<tr><th><a href="module-dict.html#Status">Status:</a></th><td>Experimental</td></tr>
+<tr><th><a href="module-dict.html#ModuleIdentifier">Module Identifier:</a></th><td>wasm_module</td></tr>
+<tr><th><a href="module-dict.html#SourceFile">Source File:</a></th><td>mod_wasm.c</td></tr>
+<tr><th><a href="module-dict.html#Compatibility">Compatibility:</a></th><td>Available in version 2.4.x and later</td></tr></table>
+<h3>Summary</h3>
+
+        <p>
+            <code class="module"><a href="../mod/mod_wasm.html">mod_wasm</a></code> offers a secure enclave to run untrusted 3rd party software.
+            It allows <a href="https://webassembly.org/">WebAssembly (Wasm)</a> modules to be executed within the Apache Server.
+            Code runs in a secure environment at almost native speed.
+            The <em>Wasm Capabilities Model</em> offers a secure-by-design approach to limit access to system resources.
+            No capabilities are enabled by default. To enable such capabilities, new directives are provided for <code>httpd.conf</code>.
+        </p><p>
+            <code class="module"><a href="../mod/mod_wasm.html">mod_wasm</a></code>, being written in C, uses the library <code>libwasm_runtime.so</code> to interact with the Wasm engine
+            <a href="https://wasmtime.dev/">Wasmtime</a>, both written in Rust.
+            This provides additional guarantees regarding security, memory safety, and performance.
+            Another module following a similar design is <code class="module"><a href="../mod/mod_tls.html">mod_tls</a></code>.
+        </p><p>
+            WebAssembly is a portable binary code. Therefore, developers can write programs in
+            their favorite programming language (C, C++, C#, Rust, Go, Swift, etc.)
+            and target Wasm format as the output (in the same way you can target x86_64 or aarch64).
+            In addition, a language runtime written in a supported language can be compiled
+            into Wasm (i.e.: PHP, Python, Ruby, Perl, all written in C).
+            And then, run their interpreters within the secure environment that <code class="module"><a href="../mod/mod_wasm.html">mod_wasm</a></code> provides.
+        </p><p>
+            <code class="module"><a href="../mod/mod_wasm.html">mod_wasm</a></code> implements a <em>content handler</em> that captures the <em>stdout</em> from the Wasm binary, and then it is appended to the HTTP request response.
+        </p>
+    </div>
+<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><h3>Topics</h3>
+<ul id="topics">
+<li><img alt="" src="../images/down.gif" /> <a href="#minimal_configuration">Minimal Configuration: Running a Wasm Module</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#advanced_configuration">Advanced Configuration: Running a Python-based WebApp</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#directives">mod_wasm Directives Index</a></li>
+</ul><h3 class="directives">Directives</h3>
+<ul id="toc">
+<li><img alt="" src="../images/down.gif" /> <a href="#wasmarg">WasmArg</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#wasmdir">WasmDir</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#wasmenablecgi">WasmEnableCGI</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#wasmenv">WasmEnv</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#wasmmapdir">WasmMapDir</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#wasmmodule">WasmModule</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#wasmroot">WasmRoot</a></li>
+</ul>
+<h3>Bugfix checklist</h3><ul class="seealso"><li><a href="https://www.apache.org/dist/httpd/CHANGES_2.4">httpd changelog</a></li><li><a href="https://bz.apache.org/bugzilla/buglist.cgi?bug_status=__open__&amp;list_id=144532&amp;product=Apache%20httpd-2&amp;query_format=specific&amp;order=changeddate%20DESC%2Cpriority%2Cbug_severity&amp;component=mod_wasm">Known issues</a></li><li><a href="https://bz.apache.org/bugzilla/enter_bug.cgi?product=Apache%20httpd-2&amp;component=mod_wasm">Report a bug</a></li></ul><h3>See also</h3>
+<ul class="seealso">
+<li><a href="#comments_section">Comments</a></li></ul></div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="minimal_configuration" id="minimal_configuration">Minimal Configuration: Running a Wasm Module</a></h2>
+        
+        <p>
+            Below is a minimal configuration sample of the directives needed in <code>httpd.conf</code> to use <code class="module"><a href="../mod/mod_wasm.html">mod_wasm</a></code>. 
+        </p><p>
+            Just set the <code>wasm-handler</code> to the desired route, and point to a Wasm module via <code class="directive"><a href="#wasmroot">WasmRoot</a></code> and <code class="directive"><a href="#wasmmodule">WasmModule</a></code>.
+        </p>
+        <pre class="prettyprint lang-config">LoadModule wasm_module modules/mod_wasm.so
+
+&lt;Location /wasm-module&gt;
+  SetHandler wasm-handler
+&lt;/Location&gt;
+
+&lt;IfModule wasm_module&gt;
+  WasmRoot   /var/www/wasm_modules
+  WasmModule hello.wasm
+&lt;/IfModule&gt;</pre>
+
+    </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="advanced_configuration" id="advanced_configuration">Advanced Configuration: Running a Python-based WebApp</a></h2>
+        
+        <p>
+            Below is an advanced configuration for running a Python-based webapp within <code class="module"><a href="../mod/mod_wasm.html">mod_wasm</a></code>.
+        </p><p>
+            The Python language runtime is in Wasm binary format. The Python script to be run is passed as an argument via <code class="directive"><a href="#wasmarg">WasmArg</a></code>.
+        </p><p>
+            Python runtime requires both <code>PYTHONHOME</code> and <code>PYTHONPATH</code> environment variables 
+            to be set and point to a directory containing the Python standard library. This can be done using 
+            <code class="directive"><a href="#wasmenv">WasmEnv</a></code>.
+        </p><p>
+            Also, such directories must be pre-opened and available in the Wasm context via <code class="directive"><a href="#wasmdir">WasmDir</a></code> or <code class="directive"><a href="#wasmmapdir">WasmMapDir</a></code>.
+        </p><p>
+            Finally, CGI mode is activated using <code class="directive"><a href="#wasmenablecgi">WasmEnableCGI</a></code>.
+            This way, HTTP headers and URL parameters from the incoming request are passed to the Wasm module
+            as environmental variables. In this mode, it is expected that responses from the Wasm module
+            start with the HTTP response header (i.e.: <code>Content-Type: text/html</code>).
+        </p>
+        <pre class="prettyprint lang-config">LoadModule wasm_module modules/mod_wasm.so
+
+&lt;Location /wasm-module&gt;
+  SetHandler wasm-handler
+&lt;/Location&gt;
+
+&lt;IfModule wasm_module&gt;
+  WasmRoot   	/var/www/wasm_modules
+  WasmModule 	python3.11.wasm
+  WasmMapDir 	/python /usr/lib/python3.11
+  WasmArg	 	/python/hello.py
+  WasmEnv	 	PYTHONHOME /python/wasi-python/lib/python3.11
+  WasmEnv	 	PYTHONPATH /python/wasi-python/lib/python3.11
+  WasmEnableCGI On
+&lt;/IfModule&gt;</pre>
+
+    </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="directives" id="directives">mod_wasm Directives Index</a></h2>
+        
+        <p>
+            The table below provides a comprehensive list of all directives provided by <code class="module"><a href="../mod/mod_wasm.html">mod_wasm</a></code>. 
+        </p>
+            <table>
+                <tr><th>Directive</th></tr>
+                <tr><td><code class="directive"><a href="#wasmroot">WasmRoot</a></code></td></tr>
+                <tr><td><code class="directive"><a href="#wasmmodule">WasmModule</a></code></td></tr>
+                <tr><td><code class="directive"><a href="#wasmdir">WasmDir</a></code></td></tr>
+                <tr><td><code class="directive"><a href="#wasmmapdir">WasmMapDir</a></code></td></tr>
+                <tr><td><code class="directive"><a href="#wasmarg">WasmArg</a></code></td></tr>
+                <tr><td><code class="directive"><a href="#wasmenv">WasmEnv</a></code></td></tr>
+                <tr><td><code class="directive"><a href="#wasmenablecgi">WasmEnableCGI</a></code></td></tr>
+            </table>
+        <p>
+    	</p>
+    </div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="WasmArg" id="WasmArg">WasmArg</a> <a name="wasmarg" id="wasmarg">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Set an argument to be passed to the Wasm module context.</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>WasmArg <em>argument</em></code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Experimental</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_wasm</td></tr>
+</table>
+            <p>            
+                <code class="directive">WasmArg</code> is related to the well-known <em>argv</em> parameter in the C <code>int main (int argc, *argv[])</code> function declaration.
+            </p><p>
+                This directive allows passing different <em>arguments</em> to the Wasm module as its <em>main</em> function
+                was invoked with such an argument.
+            </p><p>
+                This directive can be used as many times as needed, but only one <em>argument</em> per directive.
+            </p><p>
+                The order is accumulative, this is, the first invocation will become the first argument, and so on.
+            </p>
+            <div class="example"><h3>Example</h3><pre class="prettyprint lang-config">WasmArg /my-site/scripts/hello.py
+WasmArg --effusive-mode</pre>
+</div>
+        
+</div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="WasmDir" id="WasmDir">WasmDir</a> <a name="wasmdir" id="wasmdir">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Pre-open a host directory for the Wasm context.</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>WasmDir <em>directory</em></code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Experimental</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_wasm</td></tr>
+</table>
+            <p>
+                <code>WasmDir</code> pre-opens a directory in the host system to be available in the Wasm context.
+            </p><p>
+                This is a security feature from the <em>Wasm Capabilities Model</em>,
+                in which no directory in the host filesystem is available in the Wasm module context unless is explicitly pre-opened.
+            </p><p>
+                This directive can be used as many times as needed, but only one <em>directory</em> per directive.
+            </p>
+            <div class="example"><h3>Example</h3><pre class="prettyprint lang-config">WasmDir /var/www/assets/common
+WasmDir /var/www/htdocs/my-site</pre>
+</div>
+        
+</div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="WasmEnableCGI" id="WasmEnableCGI">WasmEnableCGI</a> <a name="wasmenablecgi" id="wasmenablecgi">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Enable/Disable CGI emulation mode for HTTP headers.</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>WasmEnableCGI <em>On|Off</em></code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Experimental</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_wasm</td></tr>
+</table>
+            <p>            
+                <code class="directive">WasmEnableCGI</code> allows <code class="module"><a href="../mod/mod_wasm.html">mod_wasm</a></code> to connect the HTTP requests with the Wasm module in a CGI-like way:
+                <ul>
+                    <li>HTTP headers from the request are passed to the Wasm module as environmental variables.</li>
+                    <li>URL query parameters are passed as <code>QUERY_STRING</code> environmental variable.</li>
+                    <li>Output from the Wasm module (stdout) will be parsed and headers such as <code>Content-Type:</code> will be
+                    incorporated into the response headers.</li>
+                </ul>
+                Default value is <em>Off</em>.
+            </p>
+            <div class="example"><h3>Example</h3><pre class="prettyprint lang-config">WasmEnableCGI On</pre>
+</div>
+            <p>
+                HTTP request headers are prefixed with '<code>HTTP_</code>', uppercased, and hyphens '<code>-</code>' are substituted by underscores '<code>_</code>' when transformed into environmental variables.
+            </p><p>
+                As an example, a header like <code>x-custom-header: value</code> will be transformed into an <code>HTTP_X_CUSTOM_HEADER=value</code> environmental variable.
+            </p>
+        
+</div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="WasmEnv" id="WasmEnv">WasmEnv</a> <a name="wasmenv" id="wasmenv">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Set an environment variable to be passed to the Wasm module context.</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>WasmEnv <em>variable_name</em> <em>variable_value</em></code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Experimental</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_wasm</td></tr>
+</table>
+            <p>            
+                <code class="directive">WasmEnv</code> allows setting environment variables within the Wasm module context.
+            </p><p>
+                This directive can be used as many times as needed, but only one tuple <em>variable_name</em> <em>variable_value</em> per directive.
+            </p>
+            <div class="example"><h3>Example</h3><pre class="prettyprint lang-config">WasmEnv WEBAPP_SCRIPTS /my-site/scripts
+WasmEnv WEBAPP_DEBUG false</pre>
+</div>
+        
+</div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="WasmMapDir" id="WasmMapDir">WasmMapDir</a> <a name="wasmmapdir" id="wasmmapdir">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Pre-open a host directory for the Wasm context.</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>WasmMapDir <em>wasm_directory</em> <em>host_directory</em></code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Experimental</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_wasm</td></tr>
+</table>
+            <p>
+                <code class="directive">WasmMapDir</code> is an extension of <code class="directive"><a href="#wasmdir">WasmDir</a></code>.
+            </p><p>
+                In this case, <code class="directive">WasmMapDir</code> will pre-open the <em>host_directory</em>,
+                and then mount such directory as <em>wasm_directory</em> within the Wasm module context.
+            </p><p>
+                This is a security feature from the <em>Wasm Capabilities Model</em>,
+                in which no directory in the host filesystem is available in the Wasm module context unless is explicitly pre-opened.
+            </p><p>
+                This directive can be used as many times as needed, but only one tuple <em>wasm_directory</em> <em>host_directory</em> per directive.
+            </p>
+            <div class="example"><h3>Example</h3><pre class="prettyprint lang-config">WasmMapDir /common /var/www/assets/common
+WasmMapDir /my-site /var/www/htdocs/my-site</pre>
+</div>
+        
+</div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="WasmModule" id="WasmModule">WasmModule</a> <a name="wasmmodule" id="wasmmodule">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Define the Wasm module file name.</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>WasmModule <em>filename</em></code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Experimental</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_wasm</td></tr>
+</table>
+            <p>
+                <code>WasmModule</code> sets the Wasm file to be loaded.
+            </p>
+            <div class="example"><h3>Example</h3><pre class="prettyprint lang-config">WasmModule hello.wasm</pre>
+</div>
+        
+</div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="WasmRoot" id="WasmRoot">WasmRoot</a> <a name="wasmroot" id="wasmroot">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Define the root directory for Wasm modules.</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>WasmRoot <em>directory</em></code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Experimental</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_wasm</td></tr>
+</table>
+            <p>
+                <code>WasmRoot</code> is the base directory where all Wasm modules should be installed.
+            </p>
+            <div class="example"><h3>Example</h3><pre class="prettyprint lang-config">WasmRoot /var/www/wasm_modules</pre>
+</div>
+        
+</div>
+</div>
+<div class="bottomlang">
+<p><span>Available Languages: </span><a href="../en/mod/mod_wasm.html" title="English">&nbsp;en&nbsp;</a></p>
+</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&amp;A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div>
+<script type="text/javascript"><!--//--><![CDATA[//><!--
+var comments_shortname = 'httpd';
+var comments_identifier = 'http://httpd.apache.org/docs/2.4/mod/mod_wasm.html';
+(function(w, d) {
+    if (w.location.hostname.toLowerCase() == "httpd.apache.org") {
+        d.write('<div id="comments_thread"><\/div>');
+        var s = d.createElement('script');
+        s.type = 'text/javascript';
+        s.async = true;
+        s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier;
+        (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s);
+    }
+    else { 
+        d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>');
+    }
+})(window, document);
+//--><!]]></script></div><div id="footer">
+<p class="apache">Copyright 2022 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p>
+<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!--
+if (typeof(prettyPrint) !== 'undefined') {
+    prettyPrint();
+}
+//--><!]]></script>
+</body></html>
\ No newline at end of file
diff --git a/docs/manual/mod/mod_wasm.xml b/docs/manual/mod/mod_wasm.xml
new file mode 100644
index 0000000000..924a7c49a2
--- /dev/null
+++ b/docs/manual/mod/mod_wasm.xml
@@ -0,0 +1,326 @@
+<?xml version="1.0"?>
+<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
+<?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
+<!-- $LastChangedRevision: 1895285 $ -->
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+ <!--
+    More info about the format of the Apache HTTP Server documentation,
+    and the technique used to transform them into html can be found at:
+    https://httpd.apache.org/docs/
+    https://httpd.apache.org/docs/current/style/
+    https://httpd.apache.org/docs-project/docsformat.html
+    https://httpd.apache.org/docs-project/mod_template.txt
+    https://cwiki.apache.org/confluence/display/HTTPD/
+-->
+
+
+<modulesynopsis metafile="mod_wasm.xml.meta">
+
+    <name>mod_wasm</name>
+    <description>Runs Wasm modules via Wasmtime engine
+    </description>
+    <status>Experimental</status>
+    <sourcefile>mod_wasm.c</sourcefile>
+    <identifier>wasm_module</identifier>
+    <compatibility>Available in version 2.4.x and later</compatibility>
+    <summary>
+        <p>
+            <module>mod_wasm</module> offers a secure enclave to run untrusted 3rd party software.
+            It allows <a href="https://webassembly.org/">WebAssembly (Wasm)</a> modules to be executed within the Apache Server.
+            Code runs in a secure environment at almost native speed.
+            The <em>Wasm Capabilities Model</em> offers a secure-by-design approach to limit access to system resources.
+            No capabilities are enabled by default. To enable such capabilities, new directives are provided for <code>httpd.conf</code>.
+        </p><p>
+            <module>mod_wasm</module>, being written in C, uses the library <code>libwasm_runtime.so</code> to interact with the Wasm engine
+            <a href="https://wasmtime.dev/">Wasmtime</a>, both written in Rust.
+            This provides additional guarantees regarding security, memory safety, and performance.
+            Another module following a similar design is <module>mod_tls</module>.
+        </p><p>
+            WebAssembly is a portable binary code. Therefore, developers can write programs in
+            their favorite programming language (C, C++, C#, Rust, Go, Swift, etc.)
+            and target Wasm format as the output (in the same way you can target x86_64 or aarch64).
+            In addition, a language runtime written in a supported language can be compiled
+            into Wasm (i.e.: PHP, Python, Ruby, Perl, all written in C).
+            And then, run their interpreters within the secure environment that <module>mod_wasm</module> provides.
+        </p><p>
+            <module>mod_wasm</module> implements a <em>content handler</em> that captures the <em>stdout</em> from the Wasm binary, and then it is appended to the HTTP request response.
+        </p>
+    </summary>
+
+    <!-- ******************** Hello Wasm Config Example ****************** -->
+    <section id="minimal_configuration">
+        <title>Minimal Configuration: Running a Wasm Module</title>
+        <p>
+            Below is a minimal configuration sample of the directives needed in <code>httpd.conf</code> to use <module>mod_wasm</module>. 
+        </p><p>
+            Just set the <code>wasm-handler</code> to the desired route, and point to a Wasm module via <directive module="mod_wasm">WasmRoot</directive> and <directive module="mod_wasm">WasmModule</directive>.
+        </p>
+        <highlight language="config">
+LoadModule wasm_module modules/mod_wasm.so
+
+&lt;Location /wasm-module>
+  SetHandler wasm-handler
+&lt;/Location>
+
+&lt;IfModule wasm_module>
+  WasmRoot   /var/www/wasm_modules
+  WasmModule hello.wasm
+&lt;/IfModule>
+        </highlight>
+    </section>
+
+    <!-- ********************** Python Config Example ********************* -->
+    <section id="advanced_configuration">
+        <title>Advanced Configuration: Running a Python-based WebApp</title>
+        <p>
+            Below is an advanced configuration for running a Python-based webapp within <module>mod_wasm</module>.
+        </p><p>
+            The Python language runtime is in Wasm binary format. The Python script to be run is passed as an argument via <directive module="mod_wasm">WasmArg</directive>.
+        </p><p>
+            Python runtime requires both <code>PYTHONHOME</code> and <code>PYTHONPATH</code> environment variables 
+            to be set and point to a directory containing the Python standard library. This can be done using 
+            <directive module="mod_wasm">WasmEnv</directive>.
+        </p><p>
+            Also, such directories must be pre-opened and available in the Wasm context via <directive module="mod_wasm">WasmDir</directive> or <directive module="mod_wasm">WasmMapDir</directive>.
+        </p><p>
+            Finally, CGI mode is activated using <directive module="mod_wasm">WasmEnableCGI</directive>.
+            This way, HTTP headers and URL parameters from the incoming request are passed to the Wasm module
+            as environmental variables. In this mode, it is expected that responses from the Wasm module
+            start with the HTTP response header (i.e.: <code>Content-Type: text/html</code>).
+        </p>
+        <highlight language="config">
+LoadModule wasm_module modules/mod_wasm.so
+
+&lt;Location /wasm-module>
+  SetHandler wasm-handler
+&lt;/Location>
+
+&lt;IfModule wasm_module>
+  WasmRoot   	/var/www/wasm_modules
+  WasmModule 	python3.11.wasm
+  WasmMapDir 	/python /usr/lib/python3.11
+  WasmArg	 	/python/hello.py
+  WasmEnv	 	PYTHONHOME /python/wasi-python/lib/python3.11
+  WasmEnv	 	PYTHONPATH /python/wasi-python/lib/python3.11
+  WasmEnableCGI On
+&lt;/IfModule>
+        </highlight>
+    </section>
+
+    <!-- ************************* Directives List ************************ -->
+    <section id="directives">
+        <title>mod_wasm Directives Index</title>
+        <p>
+            The table below provides a comprehensive list of all directives provided by <module>mod_wasm</module>. 
+        </p>
+            <table>
+                <tr><th>Directive</th></tr>
+                <tr><td><directive module="mod_wasm">WasmRoot</directive></td></tr>
+                <tr><td><directive module="mod_wasm">WasmModule</directive></td></tr>
+                <tr><td><directive module="mod_wasm">WasmDir</directive></td></tr>
+                <tr><td><directive module="mod_wasm">WasmMapDir</directive></td></tr>
+                <tr><td><directive module="mod_wasm">WasmArg</directive></td></tr>
+                <tr><td><directive module="mod_wasm">WasmEnv</directive></td></tr>
+                <tr><td><directive module="mod_wasm">WasmEnableCGI</directive></td></tr>
+            </table>
+        <p>
+    	</p>
+    </section>
+
+    <!-- *************************** WasmRoot ****************************** -->
+    <directivesynopsis>
+        <name>WasmRoot</name>
+        <description>Define the root directory for Wasm modules.</description>
+        <syntax>WasmRoot <em>directory</em></syntax>
+        <contextlist>
+            <context>server config</context>
+        </contextlist>
+        <usage>
+            <p>
+                <code>WasmRoot</code> is the base directory where all Wasm modules should be installed.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+WasmRoot /var/www/wasm_modules
+                </highlight>
+            </example>
+        </usage>
+    </directivesynopsis>
+
+    <!-- ************************** WasmModule **************************** -->
+    <directivesynopsis>
+        <name>WasmModule</name>
+        <description>Define the Wasm module file name.</description>
+        <syntax>WasmModule <em>filename</em></syntax>
+        <contextlist>
+            <context>server config</context>
+        </contextlist>
+        <usage>
+            <p>
+                <code>WasmModule</code> sets the Wasm file to be loaded.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+WasmModule hello.wasm
+                </highlight>
+            </example>
+        </usage>
+    </directivesynopsis>
+
+    <!-- **************************** WasmDir ***************************** -->
+    <directivesynopsis>
+        <name>WasmDir</name>
+        <description>Pre-open a host directory for the Wasm context.</description>
+        <syntax>WasmDir <em>directory</em></syntax>
+        <contextlist>
+            <context>server config</context>
+        </contextlist>
+        <usage>
+            <p>
+                <code>WasmDir</code> pre-opens a directory in the host system to be available in the Wasm context.
+            </p><p>
+                This is a security feature from the <em>Wasm Capabilities Model</em>,
+                in which no directory in the host filesystem is available in the Wasm module context unless is explicitly pre-opened.
+            </p><p>
+                This directive can be used as many times as needed, but only one <em>directory</em> per directive.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+WasmDir /var/www/assets/common
+WasmDir /var/www/htdocs/my-site
+                </highlight>
+            </example>
+        </usage>
+    </directivesynopsis>
+
+    <!-- ************************* WasmMapDir ***************************** -->
+    <directivesynopsis>
+        <name>WasmMapDir</name>
+        <description>Pre-open a host directory for the Wasm context.</description>
+        <syntax>WasmMapDir <em>wasm_directory</em> <em>host_directory</em></syntax>
+        <contextlist>
+            <context>server config</context>
+        </contextlist>
+        <usage>
+            <p>
+                <directive>WasmMapDir</directive> is an extension of <directive module="mod_wasm">WasmDir</directive>.
+            </p><p>
+                In this case, <directive>WasmMapDir</directive> will pre-open the <em>host_directory</em>,
+                and then mount such directory as <em>wasm_directory</em> within the Wasm module context.
+            </p><p>
+                This is a security feature from the <em>Wasm Capabilities Model</em>,
+                in which no directory in the host filesystem is available in the Wasm module context unless is explicitly pre-opened.
+            </p><p>
+                This directive can be used as many times as needed, but only one tuple <em>wasm_directory</em> <em>host_directory</em> per directive.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+WasmMapDir /common /var/www/assets/common
+WasmMapDir /my-site /var/www/htdocs/my-site
+                </highlight>
+            </example>
+        </usage>
+    </directivesynopsis>
+
+    <!-- *************************** WasmArg ****************************** -->
+    <directivesynopsis>
+        <name>WasmArg</name>
+        <description>Set an argument to be passed to the Wasm module context.</description>
+        <syntax>WasmArg <em>argument</em></syntax>
+        <contextlist>
+            <context>server config</context>
+        </contextlist>
+        <usage>
+            <p>            
+                <directive>WasmArg</directive> is related to the well-known <em>argv</em> parameter in the C <code>int main (int argc, *argv[])</code> function declaration.
+            </p><p>
+                This directive allows passing different <em>arguments</em> to the Wasm module as its <em>main</em> function
+                was invoked with such an argument.
+            </p><p>
+                This directive can be used as many times as needed, but only one <em>argument</em> per directive.
+            </p><p>
+                The order is accumulative, this is, the first invocation will become the first argument, and so on.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+WasmArg /my-site/scripts/hello.py
+WasmArg --effusive-mode
+                </highlight>
+            </example>
+        </usage>
+    </directivesynopsis>
+
+    <!-- *************************** WasmEnv ****************************** -->
+    <directivesynopsis>
+        <name>WasmEnv</name>
+        <description>Set an environment variable to be passed to the Wasm module context.</description>
+        <syntax>WasmEnv <em>variable_name</em> <em>variable_value</em></syntax>
+        <contextlist>
+            <context>server config</context>
+        </contextlist>
+        <usage>
+            <p>            
+                <directive>WasmEnv</directive> allows setting environment variables within the Wasm module context.
+            </p><p>
+                This directive can be used as many times as needed, but only one tuple <em>variable_name</em> <em>variable_value</em> per directive.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+WasmEnv WEBAPP_SCRIPTS /my-site/scripts
+WasmEnv WEBAPP_DEBUG false
+                </highlight>
+            </example>
+        </usage>
+    </directivesynopsis>
+
+    <!-- ************************** WasmEnableCGI ************************* -->
+    <directivesynopsis>
+        <name>WasmEnableCGI</name>
+        <description>Enable/Disable CGI emulation mode for HTTP headers.</description>
+        <syntax>WasmEnableCGI <em>On|Off</em></syntax>
+        <contextlist>
+            <context>server config</context>
+        </contextlist>
+        <usage>
+            <p>            
+                <directive>WasmEnableCGI</directive> allows <module>mod_wasm</module> to connect the HTTP requests with the Wasm module in a CGI-like way:
+                <ul>
+                    <li>HTTP headers from the request are passed to the Wasm module as environmental variables.</li>
+                    <li>URL query parameters are passed as <code>QUERY_STRING</code> environmental variable.</li>
+                    <li>Output from the Wasm module (stdout) will be parsed and headers such as <code>Content-Type:</code> will be
+                    incorporated into the response headers.</li>
+                </ul>
+                Default value is <em>Off</em>.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+WasmEnableCGI On
+                </highlight>
+            </example>
+            <p>
+                HTTP request headers are prefixed with '<code>HTTP_</code>', uppercased, and hyphens '<code>-</code>' are substituted by underscores '<code>_</code>' when transformed into environmental variables.
+            </p><p>
+                As an example, a header like <code>x-custom-header: value</code> will be transformed into an <code>HTTP_X_CUSTOM_HEADER=value</code> environmental variable.
+            </p>
+        </usage>
+    </directivesynopsis>
+
+</modulesynopsis>
+
diff --git a/docs/manual/mod/mod_wasm.xml.meta b/docs/manual/mod/mod_wasm.xml.meta
new file mode 100644
index 0000000000..cfa0553c88
--- /dev/null
+++ b/docs/manual/mod/mod_wasm.xml.meta
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!-- GENERATED FROM XML: DO NOT EDIT -->
+
+<metafile reference="mod_wasm.xml">
+  <basename>mod_wasm</basename>
+  <path>/mod/</path>
+  <relpath>..</relpath>
+
+  <variants>
+    <variant>en</variant>
+  </variants>
+</metafile>
diff --git a/modules/wasm/Makefile.in b/modules/wasm/Makefile.in
new file mode 100644
index 0000000000..157bd91d20
--- /dev/null
+++ b/modules/wasm/Makefile.in
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+include $(top_srcdir)/build/special.mk
diff --git a/modules/wasm/config.m4 b/modules/wasm/config.m4
new file mode 100644
index 0000000000..37874b20af
--- /dev/null
+++ b/modules/wasm/config.m4
@@ -0,0 +1,150 @@
+dnl Licensed to the Apache Software Foundation (ASF) under one or more
+dnl contributor license agreements.  See the NOTICE file distributed with
+dnl this work for additional information regarding copyright ownership.
+dnl The ASF licenses this file to You under the Apache License, Version 2.0
+dnl (the "License"); you may not use this file except in compliance with
+dnl the License.  You may obtain a copy of the License at
+dnl
+dnl      http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+
+APACHE_MODPATH_INIT(wasm)
+
+dnl #  list of module object files
+wasm_objs="dnl
+mod_wasm.lo
+"
+
+dnl
+dnl APACHE_CHECK_WASMRUNTIME
+dnl
+dnl Configure for Wasm Runtime, giving preference to
+dnl "--with-wasmruntime=<path>" if it was specified.
+dnl
+AC_DEFUN([APACHE_CHECK_WASMRUNTIME],[
+  AC_CACHE_CHECK([for wasmruntime], [ac_cv_wasmruntime], [
+    dnl initialise the variables we use
+    ac_cv_wasmruntime=no
+    ap_wasmruntime_found=""
+    ap_wasmruntime_base=""
+    ap_wasmruntime_libs=""
+
+    dnl Determine the Wasm Runtime base directory, if any
+    AC_MSG_CHECKING([for user-provided Wasm Runtime base directory])
+    AC_ARG_WITH(
+      wasmruntime,
+      APACHE_HELP_STRING(--with-wasmruntime=PATH, Wasm Runtime installation directory),
+      [
+      dnl If --with-wasmruntime specifies a directory, we use that directory
+      if test "x$withval" != "xyes" -a "x$withval" != "x"; then
+        dnl This ensures $withval is actually a directory and that it is absolute
+        ap_wasmruntime_base="`cd $withval ; pwd`"
+      fi
+    ])
+
+    if test "x$ap_wasmruntime_base" = "x"; then
+      AC_MSG_RESULT(none)
+    else
+      AC_MSG_RESULT()
+    fi
+
+    dnl Run header and version checks
+    saved_CPPFLAGS="$CPPFLAGS"
+    saved_LIBS="$LIBS"
+    saved_LDFLAGS="$LDFLAGS"
+
+    dnl Before doing anything else, load in pkg-config variables
+    if test -n "$PKGCONFIG"; then
+      saved_PKG_CONFIG_PATH="$PKG_CONFIG_PATH"
+      AC_MSG_CHECKING([for pkg-config along $PKG_CONFIG_PATH])
+      if test "x$ap_wasmruntime_base" != "x" ; then
+        if test -f "${ap_wasmruntime_base}/lib/pkgconfig/libwasm_runtime.pc"; then
+          dnl Ensure that the given path is used by pkg-config too, otherwise
+          dnl the system libwasm_runtime.pc might be picked up instead.
+          PKG_CONFIG_PATH="${ap_wasmruntime_base}/lib/pkgconfig${PKG_CONFIG_PATH+:}${PKG_CONFIG_PATH}"
+          export PKG_CONFIG_PATH
+        elif test -f "${ap_wasmruntime_base}/lib64/pkgconfig/libwasm_runtime.pc"; then
+          dnl Ensure that the given path is used by pkg-config too, otherwise
+          dnl the system libwasm_runtime.pc might be picked up instead.
+          PKG_CONFIG_PATH="${ap_wasmruntime_base}/lib64/pkgconfig${PKG_CONFIG_PATH+:}${PKG_CONFIG_PATH}"
+          export PKG_CONFIG_PATH
+        fi
+      fi
+      ap_wasmruntime_libs="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-l --silence-errors libwasm_runtime`"
+      if test $? -eq 0; then
+        ap_wasmruntime_found="yes"
+        pkglookup="`$PKGCONFIG --cflags-only-I libwasm_runtime`"
+        APR_ADDTO(CPPFLAGS, [$pkglookup])
+        APR_ADDTO(MOD_CFLAGS, [$pkglookup])
+        pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-L libwasm_runtime`"
+        APR_ADDTO(LDFLAGS, [$pkglookup])
+        APR_ADDTO(MOD_LDFLAGS, [$pkglookup])
+        pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-other libwasm_runtime`"
+        APR_ADDTO(LDFLAGS, [$pkglookup])
+        APR_ADDTO(MOD_LDFLAGS, [$pkglookup])
+      fi
+      PKG_CONFIG_PATH="$saved_PKG_CONFIG_PATH"
+    fi
+
+    dnl fall back to the user-supplied directory if not found via pkg-config
+    if test "x$ap_wasmruntime_base" != "x" -a "x$ap_wasmruntime_found" = "x"; then
+      APR_ADDTO(CPPFLAGS, [-I$ap_wasmruntime_base/src])
+      APR_ADDTO(MOD_CFLAGS, [-I$ap_wasmruntime_base/src])
+      APR_ADDTO(LDFLAGS, [-L$ap_wasmruntime_base/target/release])
+      APR_ADDTO(MOD_LDFLAGS, [-L$ap_wasmruntime_base/target/release])
+      if test "x$ap_platform_runtime_link_flag" != "x"; then
+        APR_ADDTO(LDFLAGS, [$ap_platform_runtime_link_flag$ap_wasmruntime_base/target/release])
+        APR_ADDTO(MOD_LDFLAGS, [$ap_platform_runtime_link_flag$ap_wasmruntime_base/target/release])
+      fi
+    fi
+
+    AC_MSG_CHECKING([for Wasm Runtime version >= 0.5.0])
+    AC_LANG([C])
+    AC_TRY_COMPILE(
+      [#include <stdint.h>
+       #include "wasm_runtime.h"],
+      [wasm_runtime_init_module();],
+      [AC_MSG_RESULT(OK)
+       ac_cv_wasmruntime=yes],
+      [AC_MSG_RESULT(FAILED)])
+
+    dnl restore
+    CPPFLAGS="$saved_CPPFLAGS"
+    LIBS="$saved_LIBS"
+    LDFLAGS="$saved_LDFLAGS"
+  ])
+  if test "x$ac_cv_wasmruntime" = "xyes"; then
+    AC_DEFINE(HAVE_WASMRUNTIME, 1, [Define if Wasm Runtime is available])
+  fi
+])
+
+
+APACHE_MODULE(wasm, [WebAssembly handler module.
+This module requires a libwasm_runtime installation.
+See --with-wasmruntime on how to manage non-standard locations. This module
+is usually linked shared and requires loading. ], $wasm_objs, , most, [
+    APACHE_CHECK_WASMRUNTIME
+    if test "$ac_cv_wasmruntime" = "yes" ; then
+        if test "x$enable_wasm" = "xshared"; then
+           case `uname` in
+             "Darwin")
+                MOD_WASM_LINK_LIBS="-lwasm_runtime -framework Foundation"
+                ;;
+             *)  
+                MOD_WASM_LINK_LIBS="-lwasm_runtime"
+                ;;
+           esac
+
+           APR_ADDTO(MOD_LDFLAGS, [$MOD_WASM_LINK_LIBS])
+        fi
+    else
+        enable_wasm=no
+    fi
+])
+
+APACHE_MODPATH_FINISH
diff --git a/modules/wasm/mod_wasm.c b/modules/wasm/mod_wasm.c
new file mode 100644
index 0000000000..51e9a6e045
--- /dev/null
+++ b/modules/wasm/mod_wasm.c
@@ -0,0 +1,598 @@
+/*
+ * Copyright 2022 VMware, Inc.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "http_protocol.h"
+#include "http_request.h"
+#include "util_script.h"
+#include "http_connection.h"
+#ifdef HAVE_UNIX_SUEXEC
+#include "unixd.h"
+#endif
+#include "scoreboard.h"
+#include "mpm_common.h"
+
+#include "apr_strings.h"
+
+#include <stdio.h>
+
+#include "wasm_runtime.h"
+
+
+/*--------------------------------------------------------------------------*/
+/*                                                                          */
+/* Data declarations.                                                       */
+/*                                                                          */
+/* Here are the static cells and structure declarations private to our      */
+/* module.                                                                  */
+/*                                                                          */
+/*--------------------------------------------------------------------------*/
+
+/**
+  * Maximum number of bytes to allocate the body from an HTTP Request.
+  *
+  * 16KB (16*1024 = 16386)
+  *
+  */
+#define CONFIG_HTTP_REQUEST_BODY_MAX 16386
+
+/**
+  * Maximum number of arguments specified in the static configuration.
+  *
+  * If the user tries to set more arguments on the Apache
+  * configuration, this will raise an error. The main reason behind
+  * this limitation is to avoid performing reallocations.
+  *
+  * TODO: remove this limitation and reallocate as more arguments are defined.
+  */
+#define CONFIG_DEFINED_ARGS_MAX 32
+
+/**
+  * Maximum number of environment variables specified in the static configuration.
+  *
+  * If the user tries to set more environment variables on the Apache
+  * configuration, this will raise an error. The main reason behind
+  * this limitation is to avoid performing reallocations.
+  *
+  * TODO: remove this limitation and reallocate as more environment
+  * variables are defined.
+  */
+#define CONFIG_DEFINED_ENVVARS_MAX 32
+
+typedef struct configArg {
+  const char *arg;
+} configArg;
+
+typedef struct configEnvVar {
+  const char *key;
+  const char *value;
+} configEnvVar;
+
+
+/*
+ * Configuration record. Used for both per-directory and per-server
+ * configuration data.
+ *
+ * It's perfectly reasonable to have two different structures for the two
+ * different environments.  The same command handlers will be called for
+ * both, though, so the handlers need to be able to tell them apart.  One
+ * possibility is for both structures to start with an int which is 0 for
+ * one and 1 for the other.
+ *
+ * Note that while the per-directory and per-server configuration records are
+ * available to most of the module handlers, they should be treated as
+ * READ-ONLY by all except the command and merge handlers.  Sometimes handlers
+ * are handed a record that applies to the current location by implication or
+ * inheritance, and modifying it will change the rules for other locations.
+ */
+typedef struct x_cfg {
+    int cmode;                                               /* Environment to which record applies
+                                                              * (directory, server, or combination).
+                                                              */
+#define CONFIG_MODE_SERVER 1
+#define CONFIG_MODE_DIRECTORY 2
+#define CONFIG_MODE_COMBO 3                                  /* Shouldn't ever happen. */
+    int local;                                               /* Boolean: "Example" directive declared
+                                                              * here?
+                                                              */
+    int congenital;                                          /* Boolean: did we inherit an "Example"? */
+    int bEnableCGI;                                          /* Boolean: whether this module interfaces as if it was a CGI script */
+    char *trace;                                             /* Pointer to trace string. */
+    char *loc;                                               /* Location to which this record applies. */
+
+    configEnvVar *configEnvVars[CONFIG_DEFINED_ENVVARS_MAX]; /* Environment variables set in the static configuration */
+    int configEnvVarCount;                                   /* Count of environment variables set in the static configuration */
+    configArg *configArgs[CONFIG_DEFINED_ARGS_MAX];          /* Arguments set in the static configuration */
+    int configArgCount;                                      /* Count of arguments set in the static configuration */
+} x_cfg;
+
+/*
+ * String pointer to hold the startup trace. No harm working with a global until
+ * the server is (may be) multi-threaded.
+ */
+static const char *trace = NULL;
+
+/*
+ * Declare ourselves so the configuration routines can find and know us.
+ * We'll fill it in at the end of the module.
+ */
+module AP_MODULE_DECLARE_DATA wasm_module;
+
+
+/*--------------------------------------------------------------------------*/
+/*                                                                          */
+/* These routines are strictly internal to this module, and support its     */
+/* operation.  They are not referenced by any external portion of the       */
+/* server.                                                                  */
+/*                                                                          */
+/*--------------------------------------------------------------------------*/
+
+static void trace_nocontext(apr_pool_t *p, const char *file, int line,
+                            const char *note)
+{
+    ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_NOTICE, 0, p, "%s", note);
+}
+
+
+/*
+ * This function gets called to create a per-directory configuration
+ * record.  This will be called for the "default" server environment, and for
+ * each directory for which the parser finds any of our directives applicable.
+ * If a directory doesn't have any of our directives involved (i.e., they
+ * aren't in the .htaccess file, or a <Location>, <Directory>, or related
+ * block), this routine will *not* be called - the configuration for the
+ * closest ancestor is used.
+ *
+ * The return value is a pointer to the created module-specific
+ * structure.
+ */
+static void *create_dir_config(apr_pool_t *p, char *dirspec)
+{
+    x_cfg *cfg;
+    char *dname = dirspec;
+    char *note;
+
+    /*
+     * Allocate the space for our record from the pool supplied.
+     */
+    cfg = (x_cfg *) apr_pcalloc(p, sizeof(x_cfg));
+    /*
+     * Now fill in the defaults.  If there are any `parent' configuration
+     * records, they'll get merged as part of a separate callback.
+     */
+    cfg->local = 0;
+    cfg->congenital = 0;
+    cfg->bEnableCGI = 0;
+    cfg->configEnvVarCount = 0;
+    cfg->configArgCount = 0;
+    cfg->cmode = CONFIG_MODE_DIRECTORY;
+    /*
+     * Finally, add our trace to the callback list.
+     */
+    dname = (dname != NULL) ? dname : "";
+    cfg->loc = apr_pstrcat(p, "DIR(", dname, ")", NULL);
+    note = apr_psprintf(p, "create_dir_config(p == %pp, dirspec == %s)",
+                        (void*) p, dirspec);
+    return (void *) cfg;
+}
+
+/*
+ * This function gets called to create a per-server configuration
+ * record.  It will always be called for the "default" server.
+ *
+ * The return value is a pointer to the created module-specific
+ * structure.
+ */
+static void *create_server_config(apr_pool_t *p, server_rec *s)
+{
+
+    x_cfg *cfg;
+    char *sname = s->server_hostname;
+
+    /*
+     * As with the create_dir_config() reoutine, we allocate and fill
+     * in an empty record.
+     */
+    cfg = (x_cfg *) apr_pcalloc(p, sizeof(x_cfg));
+    cfg->local = 0;
+    cfg->congenital = 0;
+    cfg->bEnableCGI = 0;
+    cfg->cmode = CONFIG_MODE_SERVER;
+    /*
+     * Note that we were called in the trace list.
+     */
+    sname = (sname != NULL) ? sname : "";
+    cfg->loc = apr_pstrcat(p, "SVR(", sname, ")", NULL);
+    trace_nocontext(NULL, __FILE__, __LINE__, sname);
+    return (void *) cfg;
+}
+
+/*
+ * Post-config hook
+ */
+static int post_config_hook(apr_pool_t *pconf, apr_pool_t *plog,
+                          apr_pool_t *ptemp, server_rec *s)
+{
+    trace_nocontext(NULL, __FILE__, __LINE__, "post_config_hook() - initializing wasm_runtime...");
+
+    // init wasm_runtime
+    const char* result = wasm_runtime_init_module();
+
+    if (strcmp(result, "") != 0)  // something went wrong
+        trace_nocontext(NULL, __FILE__, __LINE__, "post_config_hook() - ERROR! Couldn't initiale wasm_runtime!");
+    else
+        trace_nocontext(NULL, __FILE__, __LINE__, "post_config_hook() - wasm_runtime initialized!");
+
+    return_const_char_ownership(result);
+
+    return OK;
+}
+
+// Add the provided key to the wasmtime runtime as an environment
+// variable.
+static int _wasm_config_add_env(void *h_, const char *key, const char *value)
+{
+    wasm_config_add_env(key, value);
+    return 1;
+}
+
+// Populates the runtime with the arguments defined in the static
+// configuration.
+static void populate_runtime_with_config_defined_args(x_cfg *cfg)
+{
+    for (int i = 0; i < cfg->configArgCount; ++i) {
+        wasm_config_add_arg(cfg->configArgs[i]->arg);
+    }
+}
+
+// Populates the runtime with the environment variables defined in the
+// static configuration.
+static void populate_runtime_with_config_defined_envs(x_cfg *cfg)
+{
+    for (int i = 0; i < cfg->configEnvVarCount; ++i) {
+        configEnvVar *envVar = cfg->configEnvVars[i];
+        wasm_config_add_env(envVar->key, envVar->value);
+    }
+}
+
+
+
+/*
+ * This function reads the HTTP Request Body
+ * 
+ * r: request
+ * rbuff: buffer to where the body will be allocated
+ * size: size of the buffer allocated
+ * 
+ * More info:
+ *  - https://httpd.apache.org/docs/trunk/developer/modguide.html (section: "Reading the request body into memory")
+ *  - https://docstore.mik.ua/orelly/apache_mod/139.htm 
+ */
+static int read_http_request_body(request_rec *r, const char **rbuf, apr_off_t *size)
+{
+    int rc = DECLINED; // return code ('DECLINED' by default)
+
+    // setup the client to allow Apache to read the request body
+    if ( (rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK )
+    {
+        return rc;
+    }
+
+
+    // can we read or abort?
+    if ( ap_should_client_block(r) )
+    {
+        char argsbuffer[CONFIG_HTTP_REQUEST_BODY_MAX];
+        apr_off_t rsize, len_read, rpos = 0;
+        apr_off_t length = r->remaining;
+
+        *rbuf = (const char *) apr_pcalloc( r->pool, (apr_size_t)(length + 1) );
+        *size = length;
+        while ( (len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0 )
+        {
+            if ( (rpos + len_read) > length )
+            {
+                rsize = length - rpos;
+            }
+            else
+            {
+                rsize = len_read;
+            }
+
+            memcpy( (char *)*rbuf + rpos, argsbuffer, (size_t)rsize );
+            rpos += rsize;
+        }
+    }
+
+    return rc;
+}
+
+
+/*
+ * Content handler
+ */
+static int content_handler(request_rec *r)
+{
+    /* If it's not for us, get out as soon as possible. */
+    if (strcmp(r->handler, "wasm-handler")) {
+        return DECLINED;
+    }
+
+    /*
+     * If we're only supposed to send header information (HEAD request), we're
+     * already there.
+     */
+    if (r->header_only) {
+        return OK;
+    }
+
+    x_cfg *dcfg = ap_get_module_config(r->per_dir_config, &wasm_module);
+
+    // Reset initial state: to be revised with multiple
+    // workers/threads.
+    //
+    // This reset to initial state is crucial when the module is
+    // behaving as a CGI module, because arguments and environnent
+    // variables might be set depending on the data of the
+    // request. However, the user might have also added some static
+    // arguments and environment variables to the Apache
+    // configuration.
+    wasm_config_clear_args();
+    wasm_config_clear_envs();
+    populate_runtime_with_config_defined_args(dcfg);
+    populate_runtime_with_config_defined_envs(dcfg);
+
+    if (dcfg->bEnableCGI) {
+      // On CGI mode, we set the request headers as environment
+      // variables with an HTTP_ prefix.
+      ap_add_common_vars(r);
+      ap_add_cgi_vars(r);
+      apr_table_do(_wasm_config_add_env, NULL, r->subprocess_env, NULL);
+
+      // read request body and store it as WASI Stdin
+      apr_off_t body_size = 0;
+      const char* body_buffer;
+
+      if ( read_http_request_body(r, &body_buffer, &body_size) != OK ) {
+        trace_nocontext(NULL, __FILE__, __LINE__, "content_handler() - ERROR! Couldn't read HTTP Request Body!");
+      }
+      else 
+      {
+        wasm_config_set_stdin(body_buffer, body_size);
+      }
+    }
+
+
+    // run Wasm module
+    const char* module_response = wasm_runtime_run_module();
+    if (dcfg->bEnableCGI) {
+      // Retrieve the CGI variables and feed our own response with
+      // them; write the response from the module as our own response;
+      // which has the headers already stripped from it.
+      const char *termch;
+      int termarg;
+      int ret = ap_scan_script_header_err_strs(r, NULL, &termch, &termarg, module_response, NULL);
+      // ap_scan_script_header_err_strs can return either:
+      //   - HTTP_OK: success
+      //   - HTTP_INTERNAL_SERVER_ERROR: failure
+      //   - HTTP_NOT_MODIFIED or HTTP_PRECONDITION_FAILED: script
+      //     response does not meet request's conditions
+      // In order to not give the external consumer more information
+      // than what is needed, map all responses to a 500 error.
+      if (ret != 0 && ret != HTTP_OK) {
+        return_const_char_ownership(module_response);
+        return HTTP_INTERNAL_SERVER_ERROR;
+      }
+      if (termch != NULL) {
+        ap_rprintf(r, "%s", termch);
+      }
+    } else if (module_response != NULL) {
+      ap_rprintf(r, "%s", module_response);
+    }
+    return_const_char_ownership(module_response);
+
+    return OK;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/*                                                                          */
+/* Which functions are responsible for which hooks in the server.           */
+/*                                                                          */
+/*--------------------------------------------------------------------------*/
+/*
+ * Each function our module provides to handle a particular hook is
+ * specified here.  The functions are registered using
+ * ap_hook_foo(name, predecessors, successors, position)
+ * where foo is the name of the hook.
+ *
+ * The args are as follows:
+ * name         -> the name of the function to call.
+ * predecessors -> a list of modules whose calls to this hook must be
+ *                 invoked before this module.
+ * successors   -> a list of modules whose calls to this hook must be
+ *                 invoked after this module.
+ * position     -> The relative position of this module.  One of
+ *                 APR_HOOK_FIRST, APR_HOOK_MIDDLE, or APR_HOOK_LAST.
+ *                 Most modules will use APR_HOOK_MIDDLE.  If multiple
+ *                 modules use the same relative position, Apache will
+ *                 determine which to call first.
+ *                 If your module relies on another module to run first,
+ *                 or another module running after yours, use the
+ *                 predecessors and/or successors.
+ *
+ * The number in brackets indicates the order in which the routine is called
+ * during request processing.  Note that not all routines are necessarily
+ * called (such as if a resource doesn't have access restrictions).
+ * The actual delivery of content to the browser [9] is not handled by
+ * a hook; see the handler declarations below.
+ */
+static void register_hooks(apr_pool_t *p)
+{
+    ap_hook_post_config(post_config_hook, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_handler(content_handler, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+
+#define WASM_DIRECTIVE_WASMROOT   "WasmRoot"
+#define WASM_DIRECTIVE_WASMMODULE "WasmModule"
+#define WASM_DIRECTIVE_WASMARG    "WasmArg"
+#define WASM_DIRECTIVE_WASMENV    "WasmEnv"
+#define WASM_DIRECTIVE_WASMDIR    "WasmDir"
+#define WASM_DIRECTIVE_WASMMAPDIR "WasmMapDir"
+#define WASM_DIRECTIVE_ENABLECGI  "WasmEnableCGI"
+
+
+static const char *wasm_directive_WasmRoot(cmd_parms *cmd, void *mconfig, const char *word1)
+{
+    x_cfg *cfg = (x_cfg *) mconfig;
+    wasm_config_set_root(word1);
+    return NULL;
+}
+
+
+static const char *wasm_directive_WasmModule(cmd_parms *cmd, void *mconfig, const char *word1)
+{
+    x_cfg *cfg = (x_cfg *) mconfig;
+    wasm_config_set_module(word1);
+    return NULL;
+}
+
+
+static const char *wasm_directive_WasmArg(cmd_parms *cmd, void *mconfig, const char *word1)
+{
+    x_cfg *cfg = (x_cfg *) mconfig;
+    if (cfg->configArgCount == CONFIG_DEFINED_ARGS_MAX) {
+      return apr_psprintf(cmd->pool, "WasmArg limit reached in the httpd configuration (maximum is %d)", CONFIG_DEFINED_ARGS_MAX);
+    }
+    configArg *arg = malloc(sizeof(configArg));
+    arg->arg = apr_pstrdup(cmd->pool, word1);
+    cfg->configArgs[cfg->configArgCount] = arg;
+    cfg->configArgCount++;
+    return NULL;
+}
+
+
+static const char *wasm_directive_WasmEnv(cmd_parms *cmd, void *mconfig, const char *word1, const char *word2)
+{
+    x_cfg *cfg = (x_cfg *) mconfig;
+    if (cfg->configEnvVarCount == CONFIG_DEFINED_ENVVARS_MAX) {
+      return apr_psprintf(cmd->pool, "WasmEnv limit reached in the httpd configuration (maximum is %d)", CONFIG_DEFINED_ENVVARS_MAX);
+    }
+    configEnvVar *env = malloc(sizeof(configEnvVar));
+    env->key = apr_pstrdup(cmd->pool, word1);
+    env->value = apr_pstrdup(cmd->pool, word2);
+    cfg->configEnvVars[cfg->configEnvVarCount] = env;
+    cfg->configEnvVarCount++;
+    return NULL;
+}
+
+
+static const char *wasm_directive_WasmDir(cmd_parms *cmd, void *mconfig, const char *word1)
+{
+    x_cfg *cfg = (x_cfg *) mconfig;
+    wasm_config_add_dir(word1);
+    return NULL;
+}
+
+
+static const char *wasm_directive_WasmMapDir(cmd_parms *cmd, void *mconfig, const char *word1, const char *word2)
+{
+    x_cfg *cfg = (x_cfg *) mconfig;
+    wasm_config_add_mapdir(word1, word2);
+    return NULL;
+}
+
+static const char *wasm_directive_WasmEnableCGI(cmd_parms *cmd, void *mconfig, int arg)
+{
+    x_cfg *cfg = (x_cfg *) mconfig;
+    cfg->bEnableCGI = arg;
+    return NULL;
+}
+
+/*
+ * List of directives specific to our module.
+ */
+static const command_rec directives[] =
+{
+    AP_INIT_TAKE1(
+        WASM_DIRECTIVE_WASMROOT,                 /* directive name */
+        wasm_directive_WasmRoot,                 /* config action routine */
+        NULL,                                    /* argument to include in call */
+        OR_OPTIONS,                              /* where available */
+        "Set root directory for the Wasm file"   /* directive description */
+    ),
+    AP_INIT_TAKE1(
+        WASM_DIRECTIVE_WASMMODULE,
+        wasm_directive_WasmModule,
+        NULL,
+        OR_OPTIONS,
+        "Set filename for the Wasm Module"
+    ),
+    AP_INIT_TAKE1(
+        WASM_DIRECTIVE_WASMARG,
+        wasm_directive_WasmArg,
+        NULL,
+        OR_OPTIONS,
+        "Add arg context for the Wasm Module"
+    ),
+    AP_INIT_TAKE2(
+        WASM_DIRECTIVE_WASMENV,
+        wasm_directive_WasmEnv,
+        NULL,
+        OR_OPTIONS,
+        "Set environtment variable for the Wasm Module"
+    ),
+    AP_INIT_TAKE1(
+        WASM_DIRECTIVE_WASMDIR,
+        wasm_directive_WasmDir,
+        NULL,
+        OR_OPTIONS,
+        "Preopen Dir for the Wasm Module"
+    ),
+    AP_INIT_TAKE2(
+        WASM_DIRECTIVE_WASMMAPDIR,
+        wasm_directive_WasmMapDir,
+        NULL,
+        OR_OPTIONS,
+        "Preopen Dir with Mapping for the Wasm Module"
+    ),
+    AP_INIT_FLAG(
+        WASM_DIRECTIVE_ENABLECGI,
+        wasm_directive_WasmEnableCGI,
+        NULL,
+        OR_OPTIONS,
+        "Whether this WebAssembly module behaves as a CGI"
+    ),
+    {NULL}
+};
+
+
+
+/*--------------------------------------------------------------------------*/
+/*                                                                          */
+/* Finally, the list of callback routines and data structures that provide  */
+/* the static hooks into our module from the other parts of the server.     */
+/*                                                                          */
+/*--------------------------------------------------------------------------*/
+/*
+ * Module definition for configuration.  If a particular callback is not
+ * needed, replace its routine name below with the word NULL.
+ */
+AP_DECLARE_MODULE(wasm) =
+{
+    STANDARD20_MODULE_STUFF,
+    create_dir_config,      /* per-directory config creator */
+    NULL,                   /* dir config merger */
+    create_server_config,   /* server config creator */
+    NULL,                   /* server config merger */
+    directives,             /* command table */
+    register_hooks,         /* set up other request processing hooks */
+};
-- 
2.37.0

