curl の cookie オプションまとめ

いつもなんだっけ?となって検索しているので、ちゃんと man ページを読んだ。

cookie を送信するにはこの2つのオプションを使用できる。
-b, --cookie <data|filename>
-H, --header <header/@file>

レスポンスの cookie を保存する場合はこちらのオプションを使う。今回はスキップ。
-c, --cookie-jar <filename>

オプションの使い方をひとつずつ見ていこう。

1. -b <data>

curl "https://example.com" -b "cookie_name=cookie_value"

2. -b <filename>

curl "https://example.com" -b /path/to/cookie.txt

ファイルフォーマットは plain HTTP headers (Set-Cookie style)Netscape/Mozilla cookie file format に対応しているとのこと。
それぞれ下記のように記述する。

# plain HTTP headers (Set-Cookie style)
cat /path/to/cookie.txt

Set-Cookie: cookie_name=cookie_value; Domain=example.com
# Netscape/Mozilla cookie file format
cat /path/to/cookie.txt

.example.com    TRUE    /    FALSE    0    cookie_name    cookie_value

Netscape/Mozilla cookie file format の詳細についてはこちらが参考になる。
なお、区切り文字はスペースではなく、タブなので注意。

https://curl.se/docs/http-cookies.html

Fields in the file
Field number, what type and example data and the meaning of it:

string example.com - the domain name
boolean FALSE - include subdomains
string /foobar/ - path
boolean TRUE - send/receive over HTTPS only
number 1462299217 - expires at - seconds since Jan 1st 1970, or 0
string person - name of the cookie
string daniel - value of the cookie

3. -H <header>

curl "https://example.com" -H "Cookie: cookie_name=cookie_value"

4. -H <@file>

curl "https://example.com" -H @/path/to/header.txt
cat /path/to/header.txt

Cookie: cookie_name=cookie_value

以上。

sftp-server と sshfs のプロセス間通信について

概要

コンテナや仮想マシンとホストマシンで、ファイルシステムを共有するにはどうすればいいのかを知りたくて、いくつかのOSSソースコードを読んでみた。

今回は sftp-server と sshfs の組み合わせを題材に、その方法をまとめていく。
なお sshfs は現在積極的な開発が行われていないようなので、新規プロジェクトの場合は他のツールが適当と思われる。

手順

結論を先に書くと、ローカルで sftp-server を立てて、リモートからの sshfs (ローカルからのsshコマンドとして実行)と接続できるようにする。

そのために両プロセスの入出力を相互に接続してプロセス間通信を行う。
sshfs の man ページの表現を借りると、passive オプションにある communicate over stdin and stdout bypassing network というもの。

例えば Golang だとコマンドの入出力を宣言的に記述できるが、これをシェルで行う場合は名前付きパイプ(FIFO)を使って実現する。

fifo=/tmp/fifo-$$
mkfifo -m600 "$fifo"

これであたかも存在するファイルのようにパイプを扱うことができる。
この名前付きパイプへの write/read は他プロセスからの read/write があるまで、待機してくれるようなイメージ。

このパイプを使って、sftp-server と sshfs の入出力を接続し、プロセス間通信を行うには、このように書く。

< "$fifo" /usr/libexec/sftp-server -e -d /path/to/dir | ssh -p <port> <host> -- sshfs ":/path/to/dir" "/path/to/mountpoint" -o slave -o allow_other > "$fifo"

これで、リモートとローカルのファイルシステムを同期できる。 厳密に測定していないが、同期には1秒ほどかかり、同期されない場合はどちらかのディレクトリで ls などを叩くと反映される。

参考

github.com

Lima の環境構築でハマったこととか

概要

Lima 上で Docker 環境を構築したときに、いくつかのエラーに遭遇したので、概要と解決策をまとめていく。

環境

  • Apple M2 Pro
  • Ventura 13.5.2
  • Lima 0.17.2

exec format error

x86_64のイメージを実行した時に遭遇。
Podmanを使っていた時には発生しなかったので、何かのライブラリが不足しているのではという推測のもと、色々調べてみた。
qemuで異なるアーキテクチャのコンテナを実行するには qemu-user-static が必要らしいとわかった。

# in lima instance
sudo apt install qemu-user-static

Can't create TCP/IP socket

インスタンス内でアプリケーションコードをマウントして bundle install をしていた時に遭遇した。同じ事象の issue が下記。
Lima get stuck when certain frequency of DNS resolution occurs #1285
すでに修正がマージされたバージョンを使っていたから、原因は別にあるのではと思いつつ、このワークアラウンドで回避できる。

hostResolver:
  enabled: false

g++: fatal error: Killed signal terminated program cc1plus

結論から言うと、当初の Lima インスタンスへのメモリ割り当てが4GBで、gRPC gem のインストール時にメモリが枯渇していた。
2~3GBぐらい喰っていたみたい。単純に倍量を割り当てて解決した。

memory: "8GiB"

read only filesystem

ホームディレクトリはデフォルトで read only だった。単純に設定を変更すれば解決できる。

mounts:
  - location: "~"
    writable: true

番外編:ログイン時にバックグラウンドで起動する

ログインのたびに limactl start foo するのが面倒だったので、デーモン化したかった。
macOS なので launchd を使って実現できた。
今回はログインユーザーへの対応のみで十分だったので、~/LaunchAgents 配下に plist を作成。

vim ~/Library/LaunchAgents/lima.docker.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>lima.docker</string>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/bin/limactl</string>
        <string>start</string>
        <string>docker</string>
    </array>
    <key>inetdCompatibility</key>
    <dict>
        <key>Wait</key>
        <false/>
    </dict>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

検証のために手動で反映する。
plistファイルにStandardOutPathStandardErrorPathも指定できて、デバッグするときは追記する。

launchctl load ~/Library/LaunchAgents/lima.docker.plist

その他のプロパティについて、

  • inetdCompatibility: man ページを読むに、新しいプロジェクトでは非推奨らしいけど、これがないとプロセスが終了してしまう。
  • RunAtLoad: これも非推奨だけど、この設定なしではログイン時に起動されなかった。
  • PATH: いくつか減らしても動くかもしれない。

以上。