telnetでHTTP通信(GET,POST)をやってみる

フィヨルドブートキャンプのプラクティスで、telnetでHTTP通信してみたよーって話。

ホスト名はどこまで?

telnetを使ってHTTPメッセージを出すのは、ブラウザでポチポチして情報を取得していたのを、telnetのコマンドとして要求するようにするみたいなイメージでいた。

で、とりあえず試してみたのが下記コマンド。(リクエストメッセージのフォーマットに沿って、改行もしっかり入れた。)

% telnet dummy-bootcamp-fjord-jp.herokuapp.com 80
Trying 174.129.128.48...
Connected to dummy-bootcamp-fjord-jp.herokuapp.com.
Escape character is '^]'.
GET /articles HTTP/1.1

GET /articles HTTP/1.1を叩いて、しばらく待っていたけど何も変化しなくて、コネクションがクローズされてしまった😅何で??ってなったので、プラクティスの質問やネットを漁ってみると、リクエストのヘッダーフィールドを入力しないといけなかった(HTTP入門にも書いてあった😅)。必須だったのはHost:だったので入力して再度実行。

GET /articles HTTP/1.1
Host: http://dummy-bootcamp-fjord-jp.herokuapp.com/articles

そしたら、エラーが出てコンテンツがないという意味の404が出た。なんでや😭ってなってまた少し調査😅どうやらHost:にはホスト名を入れないといけないということだった。

自分の理解としては、http://dummy-bootcamp-fjord-jp.herokuapp.com/articlesがホスト名と思っていたけど全然違った。URLは下記の構文になっている(参考:Web技術の基本)。

URL.png

構成要素名 説明
スキーム プロトコルを指定する。
ホスト名
(ドメイン名)
接続先のサーバを指定する。IPアドレスでの指定も可
ポート番号 接続先のサーバのポート番号を指定。
プロトコル毎に決まったポート番号(well-knownポート)があるものは省略可能。
パス名 接続先サーバ上のディレクトリやファイルを指定

補足として、ドメイン名とホスト名は厳密には意味が違うらしい。

  • ドメイン名:ネットワークを特定する文字列
  • ホスト名:ネットワーク上のコンピュータにつける識別用文字列

ホスト名とドメイン名をつなげたものをFQDN(Fully Qualified Domain Name:完全修飾ドメイン)といい、こいつでネットワーク上のコンピュータを特定できる。概念的なイメージを載せておく。

domain.png

上記の通りなので、正しくは、dummy-bootcamp-fjord-jp.herokuapp.comがホスト名なので、コマンドを叩いてみる。

ちゃんと取得できました🤗

HTTPのコンテンツサイズ

『POSTも大体同じでしょ』ということで、下記を実施してみた。article[title],articles[body]の部分は、New Articleのページのソースを見て、入れるべき要素を特定した。

POST /articles/new HTTP/1.1
Host: dummy-bootcamp-fjord-jp.herokuapp.com

article[title]=April&article[body]=20220402

すると、コンテンツが存在しないことを示す404が出た。『/articles/newあるのになんでー???』となったが、QAによると、サーバ側で/articles/newにそんなサービスを用意していないということっぽい(と自分としては理解した💦)。なので、/articlesに対して、POSTしてみた。

POST /articles HTTP/1.1
Host: dummy-bootcamp-fjord-jp.herokuapp.com

article[title]=April&article[body]=20220402

そしたら、リクエスト不正の400のエラーコードが発生。ここも調べてみると、コンテンツサイズがないことが原因だった。コンテンツサイズが指定されていない場合、0byteのボディメッセージ扱いになる。POSTはデータを送信するメソッドなのに、データがないため不正リクエストになってしまったと考えられる。

というわけで、コンテンツサイズを入力すれば良い。が、コンテンツサイズってなんぼ入れればいいですか?となってしまった。コンテンツのサイズはメッセージボディなので、article[title]=April&article[body]=20220402のサイズを確認すれば良い。アルファベットと記号は1文字1byteで表現できるので、上の場合43文字なのでコンテンツサイズも43byteにしてあげれば良い。コマンドを叩いてみる。

ちゃんと取得できました🤗

その後に、『コンテンツサイズなんて送るデータよりも大きければ名でもいいじゃね?』と思って色々試してみた。結果として、送りたいデータのサイズをちゃんと送るのが一番という気付きを得られた、、、そりゃそうか😅。理由は下記。

  • 送りたいデータ>Content-Length:送るデータが途中で切られる
  • 送りたいデータ<Content-Length:送るデータがContent-Lengthになるまでメッセージが送信されない

post.png