summaryrefslogtreecommitdiffstats
path: root/llparse/examples/http
diff options
context:
space:
mode:
Diffstat (limited to 'llparse/examples/http')
-rw-r--r--llparse/examples/http/.gitignore6
-rw-r--r--llparse/examples/http/Makefile11
-rw-r--r--llparse/examples/http/index.ts51
-rw-r--r--llparse/examples/http/main.c48
4 files changed, 116 insertions, 0 deletions
diff --git a/llparse/examples/http/.gitignore b/llparse/examples/http/.gitignore
new file mode 100644
index 0000000..fcfe02e
--- /dev/null
+++ b/llparse/examples/http/.gitignore
@@ -0,0 +1,6 @@
+http
+*.c
+*.ll
+*.h
+*.o
+*.dSYM
diff --git a/llparse/examples/http/Makefile b/llparse/examples/http/Makefile
new file mode 100644
index 0000000..323d2e3
--- /dev/null
+++ b/llparse/examples/http/Makefile
@@ -0,0 +1,11 @@
+CC ?= clang
+
+all: http
+
+http: main.c http_parser.bc
+ $(CC) -g3 -flto -Os -fvisibility=hidden -Wall -I. http_parser.c main.c -o $@
+
+http_parser.bc: index.ts
+ npx ts-node $<
+
+.PHONY = all
diff --git a/llparse/examples/http/index.ts b/llparse/examples/http/index.ts
new file mode 100644
index 0000000..dc7f28a
--- /dev/null
+++ b/llparse/examples/http/index.ts
@@ -0,0 +1,51 @@
+import { LLParse } from '../../src/api';
+
+const p = new LLParse('http_parser');
+
+const method = p.node('method');
+const beforeUrl = p.node('before_url');
+const urlSpan = p.span(p.code.span('on_url'));
+const url = p.node('url');
+const http = p.node('http');
+
+// Add custom uint8_t property to the state
+p.property('i8', 'method');
+
+// Store method inside a custom property
+const onMethod = p.invoke(p.code.store('method'), beforeUrl);
+
+// Invoke custom C function
+const complete = p.invoke(p.code.match('on_complete'), {
+ // Restart
+ 0: method
+}, p.error(4, '`on_complete` error'));
+
+method
+ .select({
+ 'HEAD': 0, 'GET': 1, 'POST': 2, 'PUT': 3,
+ 'DELETE': 4, 'OPTIONS': 5, 'CONNECT': 6,
+ 'TRACE': 7, 'PATCH': 8
+ }, onMethod)
+ .otherwise(p.error(5, 'Expected method'));
+
+beforeUrl
+ .match(' ', beforeUrl)
+ .otherwise(urlSpan.start(url));
+
+url
+ .peek(' ', urlSpan.end(http))
+ .skipTo(url);
+
+http
+ .match(' HTTP/1.1\r\n\r\n', complete)
+ .match(' HTTP/1.1\n\n', complete)
+ .otherwise(p.error(6, 'Expected HTTP/1.1 and two newlines'));
+
+// Build
+
+const fs = require('fs');
+const path = require('path');
+
+const artifacts = p.build(method);
+fs.writeFileSync(path.join(__dirname, 'http_parser.h'), artifacts.header);
+fs.writeFileSync(path.join(__dirname, 'http_parser.c'), artifacts.c);
diff --git a/llparse/examples/http/main.c b/llparse/examples/http/main.c
new file mode 100644
index 0000000..4721a19
--- /dev/null
+++ b/llparse/examples/http/main.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "http_parser.h"
+
+int on_url(http_parser_t* s, const char* p, const char* endp) {
+ if (p == endp)
+ return 0;
+
+ fprintf(stdout, "method=%d url_part=\"%.*s\"\n", s->method,
+ (int) (endp - p), p);
+ return 0;
+}
+
+
+int on_complete(http_parser_t* s, const char* p, const char* endp) {
+ fprintf(stdout, "on_complete\n");
+ return 0;
+}
+
+
+int main(int argc, char** argv) {
+ http_parser_t s;
+
+ http_parser_init(&s);
+
+ for (;;) {
+ char buf[16384];
+ const char* input;
+ const char* endp;
+ int code;
+
+ input = fgets(buf, sizeof(buf), stdin);
+ if (input == NULL)
+ break;
+
+ endp = input + strlen(input);
+ code = http_parser_execute(&s, input, endp);
+ if (code != 0) {
+ fprintf(stderr, "code=%d error=%d reason=%s\n", code, s.error, s.reason);
+ return -1;
+ }
+ }
+
+ return 0;
+}