├── .gitattributes ├── example ├── static │ └── img │ │ ├── sevenfm-logo.png │ │ └── engine-2682239-1920.jpg ├── templates │ ├── form.html │ ├── stream.html │ ├── cover.html │ └── chat.html └── main.zig ├── .gitignore ├── zig.mod ├── src ├── templates │ ├── not-found.html │ ├── style.css │ └── error.html ├── zhp.zig ├── middleware.zig ├── url.zig ├── response.zig ├── cookies.zig ├── simd.zig ├── status.zig ├── websocket.zig ├── template.zig ├── headers.zig ├── forms.zig ├── mimetypes.zig ├── handlers.zig └── util.zig ├── .github ├── workflows │ └── ci.yml └── FUNDING.yml ├── tests ├── bench.zig ├── tornadoweb.py ├── basic.zig ├── parser.zig ├── raw.zig ├── search.zig └── http-requests.txt ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | example/static/** linguist-vendored 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /example/static/img/sevenfm-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frmdstryr/zhp/HEAD/example/static/img/sevenfm-logo.png -------------------------------------------------------------------------------- /example/static/img/engine-2682239-1920.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frmdstryr/zhp/HEAD/example/static/img/engine-2682239-1920.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | zig-cache/ 2 | zig-out/ 3 | 4 | .kdev4/ 5 | *.kdev4 6 | *.kate-swp 7 | 8 | callgrind.* 9 | 10 | __pycache__/ 11 | 12 | -------------------------------------------------------------------------------- /zig.mod: -------------------------------------------------------------------------------- 1 | id: nqpxq5symwcw6oyphfhn0t5em5x1ds15g8j5ij90q5ampntp 2 | name: zhp 3 | main: src/zhp.zig 4 | license: MIT 5 | description: A HTTP server written in Zig. 6 | dependencies: 7 | -------------------------------------------------------------------------------- /src/templates/not-found.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |The requested url does not exist.
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/templates/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Arial,x-locale-body,sans-serif; 3 | } 4 | 5 | pre { 6 | background-color: #eee; 7 | border-left: 4px solid #3d7e9a; 8 | color: #333; 9 | font-size: 1rem; 10 | font-family: consolas,monaco,"Andale Mono",monospace; 11 | overflow: auto; 12 | padding: 1em; 13 | } 14 | -------------------------------------------------------------------------------- /src/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |{% yield stacktrace %}
12 | {{request}}
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on: [push]
3 | jobs:
4 | test:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - uses: actions/checkout@v2
8 | - name: Install dependencies
9 | run: |
10 | sudo snap install zig --classic --edge
11 | sudo docker pull williamyeh/wrk
12 | zig version
13 | - name: Module test
14 | run: zig test -OReleaseSafe src/app.zig
15 | - name: Parser test
16 | run: zig run --pkg-begin zhp src/zhp.zig --pkg-end -OReleaseSafe tests/parser.zig
17 | - name: Build
18 | run: zig build -Drelease-safe=true install
19 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: frmdstryr
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
14 |
--------------------------------------------------------------------------------
/tests/bench.zig:
--------------------------------------------------------------------------------
1 | const std = @import("std");
2 |
3 | const server_cmd = [_][]const u8{
4 | "timeout", "-s", "SIGINT", "15s", "./zig-cache/bin/zhttpd",
5 | };
6 |
7 | const wrk_cmd = [_][]const u8{ "docker", "run", "--rm", "--net", "host", "williamyeh/wrk", "-t2", "-c10", "-d10s", "--latency", "http://127.0.0.1:9000/" };
8 |
9 | pub fn main() anyerror!void {
10 | const allocator = std.heap.page_allocator;
11 | var server_process = try std.ChildProcess.init(server_cmd[0..], allocator);
12 | defer server_process.deinit();
13 | try server_process.spawn();
14 |
15 | // Wait for it to start
16 | std.time.sleep(1 * std.time.ns_per_s);
17 |
18 | var wrk_process = try std.ChildProcess.init(wrk_cmd[0..], allocator);
19 | defer wrk_process.deinit();
20 | try wrk_process.spawn();
21 |
22 | var r = wrk_process.wait();
23 | r = server_process.wait();
24 | }
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 frmdstryr
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/tests/tornadoweb.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import tornado.httpserver
4 | import tornado.ioloop
5 | import tornado.options
6 | import tornado.web
7 |
8 | from tornado.options import define, options
9 |
10 | define("port", default=8888, help="run on the given port", type=int)
11 |
12 | with open('example/templates/cover.html') as f:
13 | template = f.read()
14 |
15 |
16 | class MainHandler(tornado.web.RequestHandler):
17 | def get(self):
18 | self.write("Hello, world")
19 |
20 |
21 | class TemplateHandler(tornado.web.RequestHandler):
22 | def get(self):
23 | self.write(template)
24 |
25 |
26 | def main():
27 | tornado.options.parse_command_line()
28 | application = tornado.web.Application([
29 | (r"/", TemplateHandler),
30 | (r"/hello", MainHandler),
31 | ])
32 | http_server = tornado.httpserver.HTTPServer(application)
33 | http_server.listen(options.port)
34 | tornado.ioloop.IOLoop.current().start()
35 |
36 |
37 | if __name__ == "__main__":
38 | try:
39 | import uvloop
40 | uvloop.install()
41 | except ImportError as e:
42 | print(e)
43 | main()
44 |
--------------------------------------------------------------------------------
/example/templates/form.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
21 |
22 | Enter a username: 26 | 27 |
28 |37 | 38 | 39 |
40 |
17 |
75 |