diff --git a/mongoose.c b/mongoose.c
index b56a0c08b6c85b1af24df08b97f7f29226e2bec4..485bd48a0d295bdf1264d62c365232912226d457 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -2179,6 +2179,42 @@ int mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
   return j;
 }
 
+// This function prints HTML pages, and expands "{{something}}" blocks
+// inside HTML by calling appropriate callback functions.
+// The output is done by the output function. In production case, the output
+// function sends data to mongoose. In test case, it prints into a string.
+// Note that {{@path/to/file}} construct outputs embedded file's contents,
+// which provides SSI-like functionality.
+void mg_template(struct mg_connection *conn, const char *s,
+                 struct mg_expansion *expansions) {
+  int i, j, pos = 0, inside_marker = 0;
+
+  for (i = 0; s[i] != '\0'; i++) {
+    if (inside_marker == 0 && !memcmp(&s[i], "{{", 2)) {
+      if (i > pos) {
+        mg_send_data(conn, &s[pos], i - pos);
+      }
+      pos = i;
+      inside_marker = 1;
+    }
+    if (inside_marker == 1 && !memcmp(&s[i], "}}", 2)) {
+      for (j = 0; expansions[j].keyword != NULL; j++) {
+        const char *kw = expansions[j].keyword;
+        if ((int) strlen(kw) == i - (pos + 2) &&
+            memcmp(kw, &s[pos + 2], i - (pos + 2)) == 0) {
+          expansions[j].handler(conn);
+          pos = i + 2;
+          break;
+        }
+      }
+      inside_marker = 0;
+    }
+  }
+  if (i > pos) {
+    mg_send_data(conn, &s[pos], i - pos);
+  }
+}
+
 #ifndef MONGOOSE_NO_FILESYSTEM
 static int must_hide_file(struct connection *conn, const char *path) {
   const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
diff --git a/mongoose.h b/mongoose.h
index 3d9e38d12e6ec4a4331b8b9910772814b0b1c730..67674a855d5799323af5478db87e6056eb85352a 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -113,6 +113,13 @@ void *mg_start_thread(void *(*func)(void *), void *param);
 char *mg_md5(char buf[33], ...);
 int mg_authorize_digest(struct mg_connection *c, FILE *fp);
 
+struct mg_expansion {
+  const char *keyword;
+  void (*handler)(struct mg_connection *);
+};
+void mg_template(struct mg_connection *, const char *text,
+                 struct mg_expansion *expansions);
+
 
 #ifdef __cplusplus
 }