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

Typed parsers and formatters for common HTTP header values

オープン
#9,685 コメント 0 件 リアクション 0 件 担当者 1 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@effect-bot がすでに取り組んでいます。

2026年10月21日 から。

  • #9709 @tim-smart による — オープン

評価

この issue はまだ評価されていません。

説明

docker-made-me-do-it enhancement

Problem

effect/http treats header values as plain strings. Each place that needs to understand a value parses it on the spot, and the copies disagree.

Retry-After is parsed in eight places with six different rules. RFC 9110 §10.2.3 allows whole seconds or an HTTP date. For the invalid value -5:

  • HttpClient (http/HttpClient.ts:1461) falls through to Date.parse("-5"), which V8 reads as a date in 2001, so it retries after 1 ms.
  • The OTLP exporter and the Anthropic, OpenAI, OpenRouter and OpenAI-compatible clients return a delay of −5 seconds. These four AI clients also ignore HTTP dates and accept 1e3 and Infinity.
  • GraphQL and Cloudflare return undefined, and the typesafe client returns 0.

Other examples on main:

  • Media types are matched by substring (HttpServerRequest.ts:274, GraphQLProtocol.ts:260, HttpStaticServer.ts:438). The static server treats Accept: text/html;q=0, which means "never send HTML", as asking for HTML.
  • There are three separate Accept-style parsers: compression, McpServer and HttpApi.
  • HTTP dates go through Date.parse, which reads the asctime format in local time. With TZ=America/New_York, Sun Nov 6 08:49:37 1994 comes out five hours off.
  • Etag can format a tag but not parse or compare one. The static server splits If-None-Match on raw commas (HttpStaticServer.ts:448), but a comma is valid inside a tag.
  • There is nothing for Cache-Control, Range, Link, WWW-Authenticate or Structured Fields.

Two related bugs are filed separately: basicAuth encoding (#9678) and multipart filenames (#9679).

Proposal

Add one small module per header family to effect/http. Each one provides:

  • an immutable value;
  • parse, which returns a Result and is forgiving where the RFC allows;
  • format, which always produces the canonical form;
  • an Equivalence;
  • a Schema codec from string, so the value can be used directly in HttpApi headers schemas and in WithHeaders.
Module Standard
MediaType RFC 9110 §8.3.1
Accept, AcceptEncoding, AcceptLanguage, with negotiation RFC 9110 §12.5, RFC 4647
ContentDisposition RFC 6266, RFC 8187
HttpDate, RetryAfter RFC 9110 §5.6.7, §10.2.3
Etag lists and comparison, conditional requests RFC 9110 §8.8.3, §13
Range, ContentRange RFC 9110 §14
CacheControl RFC 9111 §5.2
Link RFC 8288
Authorization, WWW-Authenticate (Basic, Bearer) RFC 9110 §11, RFC 7617, RFC 6750
StructuredField RFC 9651
// names illustrative
RetryAfter.parse("Wed, 21 Oct 2015 07:28:00 GMT")  // Result<RetryAfter, HeaderValueError>
RetryAfter.delay(value, now)                         // Duration, never negative
Etag.parseList(`"a,b", W/"c"`)                       // two tags

HttpApiEndpoint.get("file", "/file", {
  headers: { "if-none-match": Schema.optional(Etag.ListFromString) }
})

Then switch Effect's own call sites over to these modules.

Why in Effect

  • Effect's own code needs these parsers, and today every bug has to be fixed in every copy.
  • Header values are wire data. Schema codecs give HttpApi users typed headers, decode errors and OpenAPI output without writing their own parsers.
  • Other ecosystems provide them too. Go has mime.ParseMediaType, http.ParseTime, and precondition and range handling in http.ServeContent. Rust has the headers and sfv crates. Node has jshttp's content-type, negotiator, range-parser and fresh.

Scope

In scope:

  • The modules above, and switching Effect's own call sites over to them.

Out of scope:

  • An HTTP cache.
  • Cookies and trace context, which already have modules.
  • Forwarded (#9681) and Problem Details (#9686), which have their own issues.
  • Accept-based response selection in HttpApi.

Open questions

  • Should conditional-request evaluation (If-Match, If-None-Match, If-Modified-Since, If-Range) be a public helper that any handler can call? The static server would then use it too.
  • One issue with a checklist, or one PR per module?
主要言語
TypeScript
スター
16.7k
フォーク
808
平均マージ
10時間 7分
マージ済み PR(30日)
808

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

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

Effect-TS/effect のほかの issue

Effect-TS/effect の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

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

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