Skip to content

[Bug][internal] OPTIONS requests return :invalid_request from :httpc #9

Description

@gsmlg

Requesting repo: gsmlg-dev/http_fetch on branch main

HTTP.fetch/2 with method: "OPTIONS" resolves to {:error, :invalid_request} regardless of the URL, headers, or body.

Root cause (observed)

This is an upstream :httpc limitation rather than a bug in http_fetch itself. :httpc.request/4 is documented to reject OPTIONS with {:error, :invalid_request} because the :httpc profile (an old HTTP/1.0 client) does not implement OPTIONS. The error is returned synchronously by :httpc.request/4 before any network I/O happens, regardless of the request target.

The e2e/methods_test.exs OPTIONS test exercises the local Go test server's /options route (which returns 204 No Content with an Allow header listing the supported methods) and currently fails because HTTP.fetch(method: "OPTIONS") short-circuits to {:error, :invalid_request} before any request is sent.

Reproduction

resp =
  "http://127.0.0.1:<port>/options"
  |> HTTP.fetch(method: "OPTIONS")
  |> HTTP.Promise.await()

# Expected: %HTTP.Response{status: 204, headers: %{"allow" => "GET, POST, ..."}}
# Actual:   {:error, :invalid_request}

Impact

  • HTTP.fetch/2 is documented as a browser-like fetch API; OPTIONS (used for CORS preflight) is a first-class HTTP verb that the library does not actually support.
  • The current behaviour is silent — the user sees an opaque :invalid_request atom with no hint that :httpc is the source.

Suggested direction (not requesting a specific implementation)

  1. For OPTIONS specifically, build the request manually using :gen_tcp/:ssl (or a small dedicated module) and parse the response, since :httpc will not be updated to support it.
  2. If switching transports is out of scope, detect the OPTIONS method in HTTP.fetch/2 and raise a clear ArgumentError with a message explaining that :httpc does not support OPTIONS, instead of letting the opaque :invalid_request propagate.

Environment

  • Elixir 1.18+
  • Erlang/OTP 28

Severity

nice-to-have (OPTIONS/CORS preflight is typically handled by the browser; server-to-server OPTIONS is uncommon, and the failure mode is obvious enough that users can work around it)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    internal requestInternal request originating from another repo in the gsmlg org

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions