diff options
Diffstat (limited to 'llparse/examples/http')
-rw-r--r-- | llparse/examples/http/.gitignore | 6 | ||||
-rw-r--r-- | llparse/examples/http/Makefile | 11 | ||||
-rw-r--r-- | llparse/examples/http/index.ts | 51 | ||||
-rw-r--r-- | llparse/examples/http/main.c | 48 |
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; +} |