Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

A one-byte asset is served with Content-Length: 0 and its byte still written, which corrupts a keep-alive connection

オープン 初心者向け
#69 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

@cezaraugusto がすでに取り組んでいます。

2026年9月23日 から。

  • #70 @cezaraugusto による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
75/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
javascript, node.js, webpack
領域
backend, devtools

調査の方向性

バグは src/utils/compatibleAPI.js(または webpack-dev-middleware の src/utils.js)にあり、1バイトのアセットに対して byteLength が誤って計算されています。まず createReadStreamOrReadFileSync 関数と calcStartAndEnd ヘルパーを調べてください。再現スクリプトは問題を示しています。実行すると誤った Content-Length が確認できます。修正には、開始と終了が両方ともゼロだがファイルが1バイトを持つというエッジケースに対して、バイト長の計算を調整することが含まれます。

索引モデルが issue の本文から書いたものです。

説明

a compilation asset of exactly one byte is served with Content-Length: 0, and the byte is still written after the headers. on a keep-alive socket the next response then fails to parse (HPE_INVALID_CONSTANT in a Node client). an empty asset and a two-byte asset are fine

the cause is the stream length in createReadStreamOrReadFileSync, src/utils/compatibleAPI.js in 2.0.4

byteLength = end === 0 ? 0 : end - start + 1;

calcStartAndEnd clamps end to Math.max(offset, offset + len - 1), so an empty file and a one-byte file both arrive as start = 0, end = 0. the special case was written for the empty one and swallows the other. webpack-dev-middleware 8.3.0 has the same line in src/utils.js

repro

const http = require("node:http"), net = require("node:net");
const webpack = require("webpack"), middleware = require("@rspack/dev-middleware");
const { sources } = webpack;
const compiler = webpack({
  mode: "development", devtool: false, context: __dirname, entry: "./src/index.js",
  output: { path: __dirname + "/dist", filename: "bundle.js" },
  plugins: [{ apply(c) { c.hooks.thisCompilation.tap("one", (compilation) => {
    compilation.hooks.processAssets.tap({ name: "one", stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL }, () => {
      compilation.emitAsset("one.txt", new sources.RawSource("a"));
      compilation.emitAsset("two.txt", new sources.RawSource("ab"));
    });
  }); } }],
});
const mw = middleware(compiler, { stats: false });
const server = http.createServer((req, res) => mw(req, res, () => { res.statusCode = 404; res.end(); }));
server.listen(0, () => mw.waitUntilValid(async () => {
  const port = server.address().port;
  for (const f of ["one.txt", "two.txt"]) {
    const raw = await new Promise((resolve) => {
      const s = net.connect(port, "127.0.0.1", () => s.write(`GET /${f} HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n`));
      const c = []; s.on("data", (d) => c.push(d)); s.on("close", () => resolve(Buffer.concat(c).toString()));
    });
    console.log(`--- ${f}\n${raw}`);
  }
  server.close(); mw.close();
}));

actual

--- one.txt
HTTP/1.1 200 OK
Content-Length: 0

a
--- two.txt
HTTP/1.1 200 OK
Content-Length: 2

ab

expected

Content-Length: 1 for one.txt

seen in practice through rspack's dev server: an empty stylesheet compiles to a single line feed in development, and every such stylesheet was served empty. I have a fix ready that sizes the stream from the byte count the caller already holds

主要言語
JavaScript
スター
6
フォーク
1
平均マージ
6時間 36分
マージ済み PR(30日)
2

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

rstackjs/rspack-dev-middleware のほかの issue

rstackjs/rspack-dev-middleware の issue をすべて見る

似ている issue

JavaScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。