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

bhttp-js

deno doc Browser CI Node.js CI Deno CI Cloudflare Workers CI codecov

A BHTTP (RFC9292: Binary Representation of HTTP Messages) Encoder and Decoder written in TypeScript for Request/Response interface of the Fetch API. This module works on web browsers, Node.js, Deno and Cloudflare Workers.

Index

Supported Environments

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.2.0";
  // ...
</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.2.0/esm/mod.js";
  // ...
</script>

Node.js

Using npm:

npm install bhttp-js

Using yarn:

yarn add bhttp-js

Deno

Using deno.land:

// use a specific version
import * as bhttp from "https://deno.land/x/bhttp@v0.2.0/mod.ts";

// use the latest stable version
import * as bhttp from "https://deno.land/x/bhttp/mod.ts";

Cloudflare Workers

Downloads a single js file from esm.sh:

curl -sS -o $YOUR_SRC_PATH/bhttp.js https://esm.sh/v86/bhttp-js@0.2.0/es2022/bhttp-js.js
# if you want to use a minified version:
curl -sS -o $YOUR_SRC_PATH/bhttp.min.js https://esm.sh/v86/bhttp-js@0.2.0/es2022/bhttp.min.js

Emits a single js file by using deno bundle:

deno bundle https://deno.land/x/bhttp@0.2.0/mod.ts > $YOUR_SRC_PATH/bhttp.js

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.1.1';

      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 "https://deno.land/x/bhttp@v0.2.0/mod.ts";

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