Skip to main content
The Deno 2 Release Candidate is here
Learn more

bhttp-js

[![JSR](https://jsr.io/badges/@dajiaji/bhttp)](https://jsr.io/@dajiaji/bhttp) [![deno doc](https://doc.deno.land/badge.svg)](https://doc.deno.land/https/deno.land/x/bhttp/mod.ts) ![Browsers CI](https://github.com/dajiaji/bhttp-js/actions/workflows/ci_browsers.yml/badge.svg) ![Node.js CI](https://github.com/dajiaji/bhttp-js/actions/workflows/ci_node.yml/badge.svg) ![Deno CI](https://github.com/dajiaji/bhttp-js/actions/workflows/ci.yml/badge.svg) ![Cloudflare Workers CI](https://github.com/dajiaji/bhttp-js/actions/workflows/ci_cloudflare.yml/badge.svg) ![@fastly/js-compute CI](https://github.com/dajiaji/bhttp-js/actions/workflows/ci_fastly.yml/badge.svg) ![bun CI](https://github.com/dajiaji/bhttp-js/actions/workflows/ci_bun.yml/badge.svg) [![codecov](https://codecov.io/gh/dajiaji/bhttp-js/branch/main/graph/badge.svg?token=7I7JGKDDJ2)](https://codecov.io/gh/dajiaji/bhttp-js)
A BHTTP (RFC9292: Binary Representation of HTTP Messages) encoder and decoder written in TypeScript
for the Request/Response interface of Fetch API.
This module works on web browsers, Node.js, Deno and various other JavaScript runtimes.

Index

Supported Environments

  • Web browsers which support Request/Response interface of Fetch API.
  • Node.js: 18.x, 19.x, 20.x
  • Deno: 1.x
  • bun: 0.3-
  • Cloudflare Workers
  • @fastly/js-compute

Installation

Web Browser

Followings are how to use with typical CDNs. Other CDNs can be used as well.

Using esm.sh:

<!-- use a specific version -->
<script type="module">
  import * as bhttp from "https://esm.sh/bhttp-js@0.3.3";
  // ...
</script>

<!-- use the latest stable version -->
<script type="module">
  import * as bhttp from "https://esm.sh/bhttp-js";
  // ...
</script>

Using unpkg:

<!-- use a specific version -->
<script type="module">
  import * as bhttp from "https://unpkg.com/bhttp-js@0.3.3/esm/mod.js";
  // ...
</script>

Node.js

Using npm:

npm install bhttp-js

Using yarn:

yarn add bhttp-js

Deno

Using jsr:

deno add @dajiaji/bhttp
import * as bhttp from "@dajiaji/bhttp";

Cloudflare Workers

Using jsr:

npx jsr add @dajiaji/bhttp
import * as bhttp from "@dajiaji/bhttp";

Usage

This section shows some typical usage examples.

Web Browser / Cloudflare Workers

BHTTP client on Web Browser:

<html>
  <head></head>
  <body>
    <script type="module">
      import { BHttpEncoder, BHttpDecoder } from 'https://esm.sh/bhttp-js@0.3.3';

      globalThis.doBHttp = async () => {

        try {
          const encoder = new BHttpEncoder();
          const req = new Request("https://target.example/query?foo=bar");
          const bReq = await encoder.encodeRequest(req);
          const res = await fetch("https://bin.example/to_target", {
            method: "POST",
            headers: {
              "Content-Type": "message/bhttp",
            },
            body: bReq,
          });

          const decoder = new BHttpDecoder();
          const decodedRes = decoder.decodeResponse(await res.arrayBuffer());
          // decodedRes.status === 200;
          const body = await decodedRes.text();
          // body === "baz"

        } catch (err) {
          alert(err.message);
        }
      }
      
    </script>
    <button type="button" onclick="doBHttp()">do BHTTP</button>
  </body>
</html>

BHTTP server on Cloutflare Workers:

import { BHttpDecoder, BHttpEncoder } from "./bhttp.js";

export default {
  async fetch(request) {
    const decoder = new BHttpDecoder();
    const encoder = new BHttpEncoder();
    const url = new URL(request.url);

    if (url.pathname === "/to_target") {
      try {
        if (request.headers.get("content-type") !== "message/bhttp") {
          throw new Error("Invalid content-type.");
        }
        const reqBody = await request.arrayBuffer();
        const decodedReq = decoder.decodeRequest(reqBody);
        const res = new Response("baz", {
          headers: { "Content-Type": "text/plain" },
        });
        const bRes = await encoder.encodeResponse(res);
        return new Response(bRes, {
          headers: { "Content-Type": "message/bhttp" },
        });
      } catch (err) {
        return new Response(
          await encoder.encodeResponse(
            new Response(err.message, { status: 400 }),
          ),
          { status: 400, headers: { "Content-Type": "message/bhttp" } },
        );
      }
    }
    return new Response(
      await encoder.encodeResponse(new Response("", { status: 404 })),
      { status: 404, headers: { "Content-Type": "message/bhttp" } },
    );
  },
};

Node.js

const { BHttpEncoder, BHttpDecoder } = require("bhttp-js");

async function doBHttp() {
  const req = new Request("https://www.example.com/hello.txt", {
    method: "GET",
    headers: {
      "User-Agent": "curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3",
      "Accept-Language": "en, mi",
    },
  });

  // Encode a Request object to a BHTTP binary string.
  const encoder = new BHttpEncoder();
  const binReq = await encoder.encodeRequest(req);

  // Decode the BHTTP binary string to a Request object.
  const decoder = new BHttpDecoder();
  const decodedReq = decoder.decodeRequest(binReq);
}

doBHttp();

Deno

import { BHttpDecoder, BHttpEncoder } from "@dajiaji/bhttp";

const req = new Request("https://www.example.com/hello.txt", {
  method: "GET",
  headers: {
    "User-Agent": "curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3",
    "Accept-Language": "en, mi",
  },
});

// Encode a Request object to a BHTTP binary string.
const encoder = new BHttpEncoder();
const binReq = await encoder.encodeRequest(req);

// Decode the BHTTP binary string to a Request object.
const decoder = new BHttpDecoder();
const decodedReq = decoder.decodeRequest(binReq);

Contributing

We welcome all kind of contributions, filing issues, suggesting new features or sending PRs.

References