Browse Source

Add h2o.cr (Crystal bindings to h2o) (#3861)

* add h2o.cr

* copy helloword source in this repository
YOU 7 years ago
parent
commit
4836346a54

+ 7 - 0
frameworks/Crystal/h2o.cr/README.md

@@ -0,0 +1,7 @@
+# h2o.cr
+
+Crystal bindings to h2o
+
+### Plaintext
+
+h2o.cr currently only support plaintext requests

+ 25 - 0
frameworks/Crystal/h2o.cr/benchmark_config.json

@@ -0,0 +1,25 @@
+{
+  "framework": "h2o.cr",
+  "tests": [
+    {
+      "default": {
+        "plaintext_url": "/hello",
+        "port": 7890,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "None",
+        "framework": "h2o.cr",
+        "language": "Crystal",
+        "flavor": "None",
+        "orm": "Raw",
+        "platform": "None",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "crystal-h2o",
+        "notes": "",
+        "versus": "None"
+      }
+    }
+  ]
+}

+ 22 - 0
frameworks/Crystal/h2o.cr/h2o.cr.dockerfile

@@ -0,0 +1,22 @@
+FROM debian:testing
+
+RUN apt update \
+  && apt install -yqq libh2o-evloop-dev libwslay-dev libyaml-0-2 libevent-dev libpcre3-dev \
+    gcc wget git libssl-dev libuv1-dev ca-certificates --no-install-recommends
+
+RUN wget -q https://github.com/crystal-lang/crystal/releases/download/0.24.2/crystal-0.24.2-1-linux-x86_64.tar.gz \
+  && tar --strip-components=1 -xzf crystal-0.24.2-1-linux-x86_64.tar.gz -C /usr/ \
+  && rm -f *.tar.gz
+
+WORKDIR /crystal
+
+ENV GC_MARKERS 1
+
+COPY ./ ./
+
+RUN shards install
+RUN gcc -shared -O3 lib/h2o/src/ext/h2o.c -I/usr/include -fPIC -o h2o.o
+ENV CRYSTAL_PATH=lib:/usr/share/crystal/src
+RUN crystal build --prelude=empty --no-debug --release -Dgc_none -Dfiber_none -Dexcept_none -Dhash_none -Dtime_none -Dregex_none -Dextreme h2o_evloop_hello.cr --link-flags="-Wl,-s $PWD/h2o.o -DH2O_USE_LIBUV=0" -o server.out
+
+CMD bash run.sh

+ 92 - 0
frameworks/Crystal/h2o.cr/h2o_evloop_hello.cr

@@ -0,0 +1,92 @@
+require "reset/prelude"
+require "reset/patches"
+require "h2o/h2o_evloop"
+
+class H2oHello < H2o
+  @config = LibH2o::H2oGlobalconfT.new
+  @ctx = LibH2o::H2oContextT.new
+  @accept_ctx = LibH2o::H2oAcceptCtxT.new
+  @loop : LibH2o::H2oLoopT*
+
+  macro hello
+    Handler.new do |handler, req|
+      generator = uninitialized LibH2o::H2oGeneratorT[2]
+      body = h2o_iovec_init("Hello, World!")
+      req.value.res.status = 200
+      req.value.res.reason = "OK"
+      req.value.res.content_length = body.len
+
+      # require h2o.c extension
+      h2o_add_header(req, H2O_TOKEN_CONTENT_TYPE, "text/plain")
+      h2o_start_response(req, generator)
+      h2o_send(req, pointerof(body), 1, LibH2o::H2oSendState::H2OSendStateFinal)
+      0
+    end
+  end
+
+  def on_accept(listener : LibH2o::H2oSocketT*, err : LibC::Char*) : Void
+    return if err
+    return unless s = h2o_evloop_socket_accept(listener)
+    h2o_accept(pointerof(@accept_ctx), s)
+  end
+
+  def create_listener : Int32
+    addr = uninitialized LibC::SockaddrIn
+
+    pointerof(addr).clear
+    addr.sin_family = LibC::AF_INET
+    addr.sin_addr.s_addr = 0 # 0x100007f # b32(0x7f000001)
+    addr.sin_port = 0xd21e   # b16(7890)
+
+    option = 1
+    if (fd = socket(LibC::AF_INET, LibC::SOCK_STREAM | LibC::O_NONBLOCK | LibC::O_CLOEXEC, 0)) == -1 ||
+       setsockopt(fd, LibC::SOL_SOCKET, LibC::SO_REUSEADDR, pointerof(option), 4) != 0 ||
+       setsockopt(fd, LibC::SOL_SOCKET, LibC::SO_REUSEPORT, pointerof(option), 4) != 0 ||
+       setsockopt(fd, LibC::IPPROTO_TCP, LibC::TCP_QUICKACK, pointerof(option), 4) != 0 ||
+       ((option = H2O_DEFAULT_HANDSHAKE_TIMEOUT_IN_SECS) &&
+       setsockopt(fd, LibC::IPPROTO_TCP, LibC::TCP_DEFER_ACCEPT, pointerof(option), 4) != 0) ||
+       ((option = DEFAULT_TCP_FASTOPEN_QUEUE_LEN) &&
+       setsockopt(fd, LibC::IPPROTO_TCP, LibC::TCP_FASTOPEN, pointerof(option), 4) != 0) ||
+       bind(fd, pointerof(addr).as(LibC::Sockaddr*), sizeof(LibC::SockaddrIn)) != 0 ||
+       listen(fd, LibC::SOMAXCONN) != 0
+      return -1
+    end
+
+    sock = h2o_evloop_socket_create(@ctx.loop, fd, H2O_SOCKET_FLAG_DONT_READ)
+    h2o_socket_read_start(sock, LibH2o::H2oSocketCb.new { |listener, err|
+      {{@type}}.instance.on_accept(listener, err)
+    })
+    0
+  end
+
+  def register_handler(hostconf : LibH2o::H2oHostconfT*, path : String, on_req : Handler) : Void
+    pathconf = h2o_config_register_path(hostconf, path, 0)
+    handler = h2o_create_handler(pathconf, sizeof(LibH2o::H2oHandlerT))
+    handler.value.on_req = on_req
+  end
+
+  def initialize
+    @loop = h2o_evloop_create()
+  end
+
+  def run : Void
+    h2o_config_init(pointerof(@config))
+    hostconf = h2o_config_register_host(pointerof(@config), h2o_iovec_init("default"), 65535)
+    register_handler(hostconf, "/hello", hello)
+
+    h2o_context_init(pointerof(@ctx), @loop, pointerof(@config))
+
+    @accept_ctx.ctx = pointerof(@ctx)
+    @accept_ctx.hosts = @config.hosts
+
+    if create_listener != 0
+      return 1
+    end
+
+    while h2o_evloop_run(@ctx.loop, Int32::MAX) == 0; end
+  end
+end
+
+H2oHello.run
+
+

+ 7 - 0
frameworks/Crystal/h2o.cr/run.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+for i in $(seq 1 $(nproc --all)); do
+  ./server.out &
+done
+
+wait

+ 15 - 0
frameworks/Crystal/h2o.cr/shard.yml

@@ -0,0 +1,15 @@
+name: crystal-h2o
+version: 0.0.1
+
+license: MIT
+
+crystal: 0.24.2
+
+dependencies:
+  h2o:
+    github: s-you/h2o.cr
+  uv:
+    github: s-you/uv.cr
+  reset:
+    github: s-you/reset.cr
+    branch: h2o