netcatでHTTP POSTするときに改行コードでハマった
雰囲気でHTTPを扱っていてハマった話。
環境
- OS: macOS Sierra
- Webサーバーの実行環境: Node.js1
netcatでHTTP GETする
HTTPの仕組みを理解するための勉強方法として、netcat2でHTTPプロトコルを手打ちするという方法があります。
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('working!');
});
app.listen(3000);
このようなWebサーバーを立てたとき、curlコマンドでアクセスすると次のようになります。
$ curl localhost:3000
working!
では、これと同じことをnetcat(以降nc)を使ってやってみましょう。
$ nc localhost 3000
GET / HTTP/1.1
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 8
ETag: W/"8-8rFUSOp1Q66VQKob7hAkNyUVaiI"
Date: Wed, 05 Feb 2020 16:01:00 GMT
Connection: keep-alive
working!
GET / HTTP/1.1
の部分をキーボード入力すると、 HTTP/1.1 200 OK
で始まる数行の文字列が返され、最後に working!
の文字列が表示されました。
という感じで、なんとなくHTTPの雰囲気を味わうことができます。
netcatでHTTP POSTする
ファイルをアップロードできる簡易的なWebサーバーを立てます。
const express = require('express');
const path = require('path');
const multer = require('multer');
const upload = multer({ dest: path.resolve('tmp') });
const app = express();
app.get('/form', (req, res) => {
res.send(`<html>
<body>
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="file"><br>
<input type="submit" value="upload">
</form>
</body>
</html>`);
});
app.get('/download/:fileName', (req, res) => {
const fileName = req.params.fileName;
res.download(path.resolve('tmp', fileName));
});
app.post('/upload', upload.single('file'), (req, res) => {
res.send({ download: '/download/' + req.file.filename });
});
app.listen(3000);
まずは、試しにブラウザからファイルをアップロードしてみます。
このときの通信内容をWireshark3でキャプチャすると次のようになります。
なるほど...こんな感じの内容で手打ちすればファイルがPOSTできそうです。
ということで、上の画像の赤色の部分の文字列をコピペして、ncコマンドに突っ込んでみます。
$ nc localhost 3000
POST /upload HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 196
Cache-Control: max-age=0
Origin: http://localhost:3000
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryGjg4YppOrQq8zAjm
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Referer: http://localhost:3000/form
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8
------WebKitFormBoundaryGjg4YppOrQq8zAjm
Content-Disposition: form-data; name="file"; filename="hoge.txt"
Content-Type: text/plain
hello, world!
------WebKitFormBoundaryGjg4YppOrQq8zAjm--
(反応が返ってこなかったので何度かReturn連打)
HTTP/1.1 500 Internal Server Error
X-Powered-By: Express
Content-Security-Policy: default-src 'none'
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=utf-8
Content-Length: 352
Date: Wed, 05 Feb 2020 16:56:40 GMT
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
~~以下省略~~
コピペした内容を、ncコマンドに突っ込んでみたものの、反応なし。その後何度かReturnキーを押すと Internal Server Error
が返りました。
改行コードがCRLFからLFに変わってしまった
ncコマンドに突っ込んだ方は改行コードがCRLFからLFに変わってしまったため、 Content-Length
が実際より長くなってしまったようです。
↓ ブラウザからアップロードした時のWiresharkのキャプチャ結果(16進数ダンプ)
↓ ncコマンド実行時のWiresharkのキャプチャ結果(16進数ダンプ)
改行が 0d 0a
(CRLF) から 0a
(LF) に変わっていました...
これだと一行あたり1byte短くなってしまう...
Content-Length
を短くして再度実行
Content-Length
を189にして再度ncコマンドに突っ込んでみます。
$ nc localhost 3000
POST /upload HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 189
~中略~
Accept-Language: ja,en-US;q=0.9,en;q=0.8
------WebKitFormBoundaryBR5buZN29ZTV1NcQ
Content-Disposition: form-data; name="file"; filename="hoge.txt"
Content-Type: text/plain
hello, world!
------WebKitFormBoundaryBR5buZN29ZTV1NcQ--
HTTP/1.1 500 Internal Server Error
X-Powered-By: Express
Content-Security-Policy: default-src 'none'
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=utf-8
Content-Length: 352
Date: Wed, 05 Feb 2020 17:35:27 GMT
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
~~以下省略~~
今度はすぐに反応が返ってきましたが、Internal Server Error
...
うまくいかない...
CRLFじゃないとだめらしい
RFC2616の3.7.2 Multipart Typesに次のような記述がありました...
https://tools.ietf.org/html/rfc2616#section-3.7.2
The message body is itself a protocol element and MUST therefore use only CRLF to represent line breaks between body-parts.
ということなので、改行をLFからCRLFに置換したものを、ncコマンドに突っ込んでみました。
$ perl -pe 's/\n/\r\n/' << EOS > reqest.txt
POST /upload HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 196
Cache-Control: max-age=0
Origin: http://localhost:3000
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBR5buZN29ZTV1NcQ
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Referer: http://localhost:3000/form
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8
------WebKitFormBoundaryBR5buZN29ZTV1NcQ
Content-Disposition: form-data; name="file"; filename="hoge.txt"
Content-Type: text/plain
hello, world!
------WebKitFormBoundaryBR5buZN29ZTV1NcQ--
EOS
$ cat reqest.txt - | nc localhost 3000
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 57
ETag: W/"39-ItS2HTg6ed8Zw1CrGzQL3ABlypc"
Date: Wed, 05 Feb 2020 18:38:11 GMT
Connection: keep-alive
{"download":"/download/bd29989fa6ae794857ba429ced286f3f"}
^C
$ curl localhost:3000/download/bd29989fa6ae794857ba429ced286f3f
hello, world!
-
\n
->\r\n
の置換はsedだとうまくいかなかったのでperlを使った - 一旦ファイルに書き出して
cat reqest.txt -
をしているのは、パイプの終端に達した時にncコマンドがレスポンスを受け取らずに接続を切ってしまう挙動をするため...これも結構ハマった
ちょっとぎこちないけど、まあ動いたのでよしとしましょう。
※ちなみに、macOSだとこのように問題になりますが、WindowsだとOSの改行コードがCRLFなので何も問題は起きません。
Author And Source
この問題について(netcatでHTTP POSTするときに改行コードでハマった), 我々は、より多くの情報をここで見つけました https://qiita.com/ttk1/items/345bbb1c9985bb5251e4著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .