Android: new WebSocket() crashes the app for a URL that OkHttp or java.net.URI rejects

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

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

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

2026年11月2日 から。

  • #59757 @sorinc03 による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
android, java, react-native
領域
mobile

調査の方向性

com.facebook.react.modules.websocket.WebSocketModule.java を読み、connect メソッドで Request.Builder().url(url)、getCookie、getDefaultOrigin が呼び出されるところを特定する。これらの呼び出しを IllegalArgumentException の try-catch で囲み、send と close が行うように JS に error/close イベントを dispatch する。Done は、無効な URL がアプリをクラッシュさせる代わりに WebSocket で error と close を発生させることを意味する。

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

説明

🌐Networking Needs: Author Feedback Needs: Repro Platform: Android
Description

On Android, new WebSocket(url) crashes the app when OkHttp or java.net.URI rejects url, such as ws://localhost:0/ (port 0) or ws://localhost:4000/a|b (a character RFC 2396 doesn't allow in a path). JavaScript gets no exception and no error or close event, and a release build dies with a fatal exception on the native modules thread.

Expected: the socket fires error and close, as it does when it can't connect, or the constructor throws in JavaScript.

Likely cause: WebSocketModule.connect calls Request.Builder().url(url), getCookie, and getDefaultOrigin outside a try, and they throw IllegalArgumentException for such URLs, while send and close catch their exceptions. #24427 reported the same crash in 0.59.

We found this in Evolu, a local-first platform, whose relay URL type now rejects such URLs.

Steps to reproduce
  1. Replace App.tsx of an app made from the reproducer template with the code below.
  2. Build it in release for Android and run it.
  3. Tap either button. The app crashes instead of showing error and close.
import { useState } from 'react';
import { Button, Text, View } from 'react-native';

// Each URL should report an error and close to JS. On Android, connect throws
// natively instead.
const urls = ['ws://localhost:0/', 'ws://localhost:4000/a|b'];

function App() {
  const [log, setLog] = useState<ReadonlyArray<string>>([]);
  const append = (line: string) => setLog(lines => [...lines, line]);

  return (
    <View style={{ padding: 48, gap: 16 }}>
      {urls.map(url => (
        <Button
          key={url}
          title={url}
          onPress={() => {
            const socket = new WebSocket(url);
            socket.onerror = () => append(`error ${url}`);
            socket.onclose = event => append(`close ${url} ${event.code}`);
          }}
        />
      ))}
      {log.map((line, index) => (
        <Text key={index}>{line}</Text>
      ))}
    </View>
  );
}

export default App;
React Native Version

0.88.1

Affected Platforms

Runtime - Android, Build - MacOS

Output of npx @react-native-community/cli info
System:
  OS: macOS 26.6.2
  CPU: (10) arm64 Apple M5
Binaries:
  Node: 24.22.0
npmPackages:
  react-native: 0.88.1
Android:
  hermesEnabled: true
  newArchEnabled: true
Device: Android 16 (API 36) arm64 emulator
Stacktrace or Logs
E AndroidRuntime: FATAL EXCEPTION: mqt_v_native
E AndroidRuntime: java.lang.IllegalArgumentException: Invalid URL port: "0"
E AndroidRuntime:   at t6.m(r8-map-id-50fb0331…:24)
E AndroidRuntime:   at vv.c(r8-map-id-50fb0331…:513)
E AndroidRuntime:   at xi.h(r8-map-id-50fb0331…:50)
E AndroidRuntime:   at com.facebook.react.modules.websocket.WebSocketModule.connect(r8-map-id-50fb0331…:118)
E AndroidRuntime:   at com.facebook.jni.NativeRunnable.run(Native Method)
E AndroidRuntime:   at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(…)

E AndroidRuntime: FATAL EXCEPTION: mqt_v_native
E AndroidRuntime: java.lang.IllegalArgumentException: Unable to set ws://localhost:4000/a|b as default origin header
E AndroidRuntime:   at com.facebook.react.modules.websocket.WebSocketModule.getCookie(r8-map-id-50fb0331…:8)
E AndroidRuntime:   at com.facebook.react.modules.websocket.WebSocketModule.connect(r8-map-id-50fb0331…:121)
MANDATORY Reproducer

No repository: the App.tsx in Steps to reproduce is the whole reproducer.

Screenshots and Videos

No response

主要言語
C++
スター
127k
フォーク
25.4k
平均マージ
3日 1時間
マージ済み PR(30日)
108

環境構築

はじめの一歩

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

react/react-native のほかの issue

react/react-native の issue をすべて見る

似ている issue

C++ の issue をもっと見る

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

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