17
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

netcatでHTTPリクエストを送ってみる

Posted at

やりたいこと

かっこよくターミナルからHTTPリクエストを送りたいと思いませんか?
TCPコネクションを nc コマンドで確立し、その後TCP通信で GET リクエストを送りましょう。
リクエストを送るホストは、ご存知の google.comポート 80 とします。

その前にHTTPとは?

OSI参照モデルでいうアプリケーション層にあるHTTPというプロトコルは、Webページをブラウジングするためや、ログインIDやパスワードを送ることにも利用されるWWW(World Wide Web)を代表するプロトコルです。
Webサーバは、HTTPのフォーマットで書かれた HTTPリクエスト をクライアント(ブラウザ)から受け取り、 ステータスコードとともに HTTPレスポンス をクライアントに返します。

HTTPリクエストのメソッド

メソッド名 説明
GET URIを用いてサーバから情報を受け取るためのメソッド。サーバ側の情報を書き換えるといったことはしない。
HEAD GETと基本的には同じだが、ステータスコードとヘッダーのみを返す点が異なる。
POST クライアントからサーバになにかしらのデータを送る時に使われる。
PUT クライアントが既に知っているURIにあるリソースを作ったり上書きしたりするために用いる。
DELETE URIにあるリソースを削除するために用いる。
CONNECT URIで指定されるサーバとのコネクションを確立する。
OPTIONS 対象リソースとの通信のためのオプションを返す。
TRACE 対象リソースへの経路に沿ったループバックテストを行う。

https://www.tutorialspoint.com/http/http_requests.htm のなかで紹介された表を訳しただけです。
POSTとPUTの違いは、https://www.keycdn.com/support/put-vs-post を参考にしました。

TCPコネクションを確立する

何はともあれ、TCPコネクションを確立しないとHTTP通信をすることはできません。
nc コマンドでは、トランスポート層のプロトコルであるTCPUDPを使ったコネクションを作ることができます。
なにもオプションを指定しない場合は、TCPコネクションを確立しようとします。

$ nc -v google.com 80
found 0 associations
found 1 connections:
     1:	flags=82<CONNECTED,PREFERRED>
	outif en0
	src 192.168.128.246 port 52041
	dst 172.217.161.206 port 80
	rank info not available
	TCP aux info available

Connection to google.com port 80 [tcp/http] succeeded!

google.com のWebサーバ(ポート80)とのTCPコネクションを結ぶことに成功しました。

このコネクションを通じて、対象とするホストにあるポートに対して、データの送受信をすることができます。

GETリクエスト

このTCPコネクションを用いて、GETリクエストでHTMLを取得してみましょう。

GET / HTTP/1.1

と入力した後、改行し、もう一度空行を送信します。
すると、HTTPリクエストが返ってきます。

HTTP/1.1 200 OK
Date: Thu, 23 May 2019 16:04:22 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2019-05-23-16; expires=Sat, 22-Jun-2019 16:04:22 GMT; path=/; domain=.google.com
Set-Cookie: NID=184=rWXmA7VSwF4GNfvX7kNWjSzTx4sRBODwanmpsOznfM1qEnjS_taYCnk_mit7kYqE6WcNdgHXApOPuNnXEGwExSI0fsdiWV3e2dykYLNY2Kdmca4cwIhn1S7l0THIeiM9Pfh1quKMHM4H1GN6h6lN30InP85WKgpbuu8H2D-Osvw; expires=Fri, 22-Nov-2019 16:04:22 GMT; path=/; domain=.google.com; HttpOnly
Accept-Ranges: none
Vary: Accept-Encoding
Transfer-Encoding: chunked

52b6
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja">
... (数十行にも及ぶため、省略)

一番上の行にある200というステータスコードによって、サーバから返されるレスポンスがどのようなものであるかがわかります。
ステータスコードの詳細は、https://developer.mozilla.org/ja/docs/Web/HTTP/Status でみることができます。
ざっくりいうと、200番台が成功300番台がリダイレクトメッセージ400番台がクライアントエラー500番台がサーバエラーのように分類されています。
200というステータスコードについて、上のURL内では次のように説明されています。

200 OK
リクエストが成功したことを示します。成功が意味することは、 HTTP メソッドにより異なります:
GET: リソースが取り出され、メッセージ本文で転送されます。
HEAD: エンティティヘッダーがメッセージ本文内にあります。
PUT 又は POST: アクションの結果を表すリソースがメッセージ本文で転送されます。
TRACE: サーバーが受理したリクエストメッセージがメッセージ本文に含まれています。

この場合、GETリクエストでしたので、指定したURIからリソースが取り出され、メッセージ本文がヘッダーの後に送られてきています。

ついでに、HEADメソッドでも同様に送ってみましょう。

HEAD / HTTP/1.1

HTTP/1.1 200 OK
Date: Thu, 23 May 2019 16:19:50 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2019-05-23-16; expires=Sat, 22-Jun-2019 16:19:50 GMT; path=/; domain=.google.com
Set-Cookie: NID=184=pcNHM2fGSG7yQ8gkR1EgmWbAffLvLPXabxORlTrqWjHBablDRBEYc91PKbUwfnPS15_i7-Vt906vQkTIFpbvXUiJ8jfDaL4Pqsz4M_bz58uu6BCRNhs3Z_RqdYQyrC1z6Mxr9z-iANryEApMFiLYQHMyhPM5Vr-uOykygtTdJYg; expires=Fri, 22-Nov-2019 16:19:50 GMT; path=/; domain=.google.com; HttpOnly
Transfer-Encoding: chunked
Accept-Ranges: none
Vary: Accept-Encoding

リクエストヘッダーを変えてみる

ここまでは、1行のHTTPリクエストをWebサーバに送信してきましたが、HTTPリクエストにもヘッダーを追加することで、Webサーバに情報を与えてあげることができます。
指定できるヘッダーはたくさんあります(https://flaviocopes.com/http-request-headers/ )。

もちろん、GETだけでなく、POSTやPUTであっても同じようにヘッダーを用いることで通信の可能性を広げることができます。
Cookieもこのリクエストヘッダに追加することができます。

例えば、User-Agentを指定することで、特定のブラウザからアクセスしたという情報をWebサーバに伝えることができます。

GET / HTTP/1.1
User-Agent: Mozilla/5.0

ちょっとMozilla/5.0からアクセスしたと嘘をついてみましょう。

HTTP/1.1 200 OK
Date: Thu, 23 May 2019 16:33:52 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=UTF-8
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2019-05-23-16; expires=Sat, 22-Jun-2019 16:33:52 GMT; path=/; domain=.google.com
Set-Cookie: NID=184=pKW_xUk70PPzuhvxzOxfHncQGORwfmqmE-IRr6VDf0j45_G58VZO9x3kpARSAvjzVtZGm8ID1AflpCX7_uwhjufqflgtdJOdKc5uJJj3yWj6ayGDPt_HjhOi8sxnDlLn_I8whAC29ySo1sqW7YvLGlFkkTNHq_HUbbRwahQrr5w; expires=Fri, 22-Nov-2019 16:33:52 GMT; path=/; domain=.google.com; HttpOnly
Accept-Ranges: none
Vary: Accept-Encoding
Transfer-Encoding: chunked

51ca
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="世界中のあらゆる情報を検索するためのツールを提供しています。さまざまな検索機能を活用して、お探しの情報を見つけてください。" name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type">

少し細かい話ですが、レスポンスヘッダのなかのcharsetUTF-8に変更されました。
そのおかげでメッセージ部分が日本語で表示されるようになっています。

まとめ

HTTPという超有名プロトコルも、元を正せばTCPコネクションでの特定フォーマットを用いたデータの送受信に過ぎないということがわかっていただけたでしょうか?
APIあたりの話も今後追加していこうと思います。

17
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?