バグ #1259
完了特定の URI 文字列を含むツイートを表示すると落ちる
説明
https://twitter.com/neta__/status/1003680831829766150
を mikutter で表示すると以下の現象になるようです。
- ツイート表示が error 画像になる
- その error 表示のツイート部分をクリックすると mikutter がクラッシュする or ハングする
クラレポは以下
Addressable::URI::InvalidURIError Invalid character in host: 'www\.apple' /usr/pkg/lib/ruby/gems/2.4.0/gems/addressable-2.5.2/lib/addressable/uri.rb:2438:in `validate' /usr/pkg/lib/ruby/gems/2.4.0/gems/addressable-2.5.2/lib/addressable/uri.rb:2357:in `defer_validation' /usr/pkg/lib/ruby/gems/2.4.0/gems/addressable-2.5.2/lib/addressable/uri.rb:796:in `initialize' /usr/pkg/lib/ruby/gems/2.4.0/gems/addressable-2.5.2/lib/addressable/uri.rb:136:in `new' /usr/pkg/lib/ruby/gems/2.4.0/gems/addressable-2.5.2/lib/addressable/uri.rb:136:in `parse' /usr/pkg/lib/ruby/gems/2.4.0/gems/diva-0.3.2/lib/diva/uri.rb:123:in `rescue in generate_uri_by_string' /usr/pkg/lib/ruby/gems/2.4.0/gems/diva-0.3.2/lib/diva/uri.rb:120:in `generate_uri_by_string' /usr/pkg/lib/ruby/gems/2.4.0/gems/diva-0.3.2/lib/diva/uri.rb:113:in `generate_uri' /usr/pkg/lib/ruby/gems/2.4.0/gems/diva-0.3.2/lib/diva/uri.rb:75:in `to_uri' /usr/pkg/lib/ruby/gems/2.4.0/gems/diva-0.3.2/lib/diva/uri.rb:104:in `method_missing' {MIKUTTER_DIR}/core/plugin/search/model/search.rb:13:in `block in <class:Search>' {MIKUTTER_DIR}/core/lib/diva_hacks/model.rb:100:in `block (2 levels) in handle' /usr/pkg/lib/ruby/gems/2.4.0/gems/pluggaloid-1.1.1/lib/pluggaloid/filter.rb:28:in `filtering' /usr/pkg/lib/ruby/gems/2.4.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:59:in `block (2 levels) in filtering' /usr/pkg/lib/ruby/gems/2.4.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:58:in `each' /usr/pkg/lib/ruby/gems/2.4.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:58:in `reduce' /usr/pkg/lib/ruby/gems/2.4.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:58:in `block in filtering' /usr/pkg/lib/ruby/gems/2.4.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:57:in `catch' /usr/pkg/lib/ruby/gems/2.4.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:57:in `filtering' /usr/pkg/lib/ruby/gems/2.4.0/gems/pluggaloid-1.1.1/lib/pluggaloid/plugin.rb:63:in `filtering' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_quote.rb:35:in `block (2 levels) in initialize' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_quote.rb:38:in `each' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_quote.rb:38:in `each' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_quote.rb:38:in `each' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_quote.rb:38:in `each' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_quote.rb:38:in `each' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_quote.rb:38:in `find' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_quote.rb:38:in `block in initialize' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_quote.rb:33:in `map' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_quote.rb:33:in `initialize' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_helper.rb:21:in `new' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_helper.rb:21:in `block in subparts' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_helper.rb:21:in `map' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_helper.rb:21:in `subparts' {MIKUTTER_DIR}/core/lib/uithreadonly.rb:22:in `block (2 levels) in singleton class' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_helper.rb:41:in `_subparts_height' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_helper.rb:34:in `subparts_height' {MIKUTTER_DIR}/core/lib/uithreadonly.rb:22:in `block (2 levels) in singleton class' {MIKUTTER_DIR}/core/mui/cairo_coordinate_module.rb:48:in `height' {MIKUTTER_DIR}/core/lib/uithreadonly.rb:22:in `block (2 levels) in singleton class' {MIKUTTER_DIR}/core/mui/cairo_coordinate_module.rb:53:in `mainpart_height' {MIKUTTER_DIR}/core/lib/uithreadonly.rb:22:in `block (2 levels) in singleton class' {MIKUTTER_DIR}/core/mui/cairo_sub_parts_voter.rb:18:in `block in initialize' {MIKUTTER_DIR}/core/mui/gtk_extension.rb:35:in `block in safety_signal_connect' {MIKUTTER_DIR}/core/lib/uithreadonly.rb:22:in `signal_emit' {MIKUTTER_DIR}/core/lib/uithreadonly.rb:22:in `block (2 levels) in singleton class' {MIKUTTER_DIR}/core/mui/cairo_miracle_painter.rb:152:in `clicked' {MIKUTTER_DIR}/core/lib/uithreadonly.rb:22:in `block (2 levels) in singleton class' {MIKUTTER_DIR}/core/mui/cairo_cell_renderer_message.rb:160:in `block in event_hooks' {MIKUTTER_DIR}/core/mui/gtk_extension.rb:35:in `block in safety_signal_connect' {MIKUTTER_DIR}/core/mui/cairo_cell_renderer_message.rb:97:in `signal_emit' {MIKUTTER_DIR}/core/mui/cairo_cell_renderer_message.rb:97:in `block in tree=' {MIKUTTER_DIR}/core/mui/gtk_extension.rb:35:in `block in safety_signal_connect' {MIKUTTER_DIR}/core/plugin/gtk/mainloop.rb:10:in `main' {MIKUTTER_DIR}/core/plugin/gtk/mainloop.rb:10:in `mainloop' {MIKUTTER_DIR}/mikutter.rb:66:in `boot!' {MIKUTTER_DIR}/mikutter.rb:102:in `<main>'
apple\.com という文字列が addressable の秘孔を突いている感じ?
addressable のバージョンは (pkgsrc 環境の) 2.5.2 です。
ファイル
cob odo さんが6年以上前に更新
- ステータス を 分類待ち から 実装待ち に変更
クラッシュに至るまでの流れは以下の通り。
- 描画時、まず最初にscoreをつくる。
Plugin[:twitter].score_by_entity
が、tweetのjsonに含まれるentityを使ってscore(候補のひとつ)を構成する。tweet[:entities][:urls]
に「twitterがURLだと認識した」ものが入っている- URLを取り出してtweetテキストを置き換える範囲(
Range
)とHyperLinkNote
の組を作る- このとき、
HyperLinkNote
のコンストラクタでURL文字列をDiva::URI
オブジェクトにするが、この時点ではURLのパースは走らない。
- このとき、
- ↑の組を使ってテキストを置き換え、scoreを構成していく。
- sub_parts_quoteが引用の処理をする。
- scoreから
HyperLinkNote
をすべて取り出してURLにする - URLに対応するカスタムModelがあるか
model_of_uri
フィルタで問い合わせる - searchプラグインの
Plugin::Search::Search
モデルのhandle
の判定文が走る- ↑の中で
uri.host
の呼び出し Diva::URI#method_missing
によりDiva::URI#to_uri
が呼ばれ、URI.parse
が呼ばれて失敗し、Addressable::URI.new
が呼ばれて失敗する
- ↑の中で
- scoreから
Addressable::URI.new
が投げた例外を捕捉できずクラッシュ
トレースはこの2~3の流れを示していますが、searchモデル以外のhandleでももちろん発生しますし、sub_parts_quote以外の処理(例えばクリック時のintent処理)でも発生するため、1の段階でチェックして対処するのがよさそうです。
Diva::URI.new()
して.freeze
すればその時点でパースさせられるので、エラーを検出したら(それは妥当なURLではないので)HyperLinkNote
を作るのをやめてTextNote
を作るようにすれば、クラッシュはしなくなります。
この例のtweet https://twitter.com/neta__/status/1003680831829766150 の場合、そういうコードに書き換えれば確かにクラッシュはしなくなるものの、
www\.appleの部分がt.coで短縮されたものとして表示されることになります。これは、このリンク以外にentityが含まれておらず、scoreの生成時にTextNote3つで構成したものが却下されてしまうからです。つまり #1233 と同様です。
このチケットでは単にクラッシュを防ぐにとどめ、scoreの優先順位の問題は #1233 や #1241 で議論するのがいいかなと思います。
今夜あたりにパッチを書くつもりです。
toshi_a 初音 さんが6年以上前に更新
TwitterがURLでないものを送ってくる可能性について失念していました。t.coがあって本当に良かった。
修正はこの方針で良いと思います。
Diva::Model#uri
をModelごとにいちいち作っているとmikutterの動作がかなり遅くなった- ほとんどの場合、
Diva::Model#uri
は同一性の判定に使われるのみなので、Stringの比較で良い- が、URIのフォーマットに従っている必要がある
と、どちらも Diva::Model#uri
に使われるときのための配慮です。HyperLinkNote程度であれば、正格評価されても特に問題なさそうです。
これは、このリンク以外にentityが含まれておらず、scoreの生成時にTextNote3つで構成したものが却下されてしまうからです。つまり #1233 と同様です。
このチケットでは単にクラッシュを防ぐにとどめ、scoreの優先順位の問題は #1233 や #1241 で議論するのがいいかなと思います。
そうしましょう。
Izumi Tsutsui さんが6年以上前に更新
- ファイル neta__-1003680831829766150.png neta__-1003680831829766150.png を追加
- ステータス を レビュー待ち から マージ待ち に変更
- 担当者 を Izumi Tsutsui から cob odo に変更
テストしてみて、クラッシュしなくなるという点ではOKっぽいです。ありがとうございます。