webプロキシ HTTP1.0 ヒント

webプロキシ HTTP1.0 ヒント
CS-B3
ネットワークプログラミング
&情報科学科実験I
このスライドについて
このスライドでは皆さんがプログラムを書いたり,関数を調べたり
する過程で行き詰ると予想される部分について簡単に解説します.
このスライドの目的は自主学習のサポートであり,説明が簡略化さ
れています.完全な理解には自主学習が必要なので注意してくださ
い.
目次





webプロキシとは
何を実装すればよいのか
実装方法の例
webサーバの特定方法
実装をする上での注意
webプロキシとは
一般的な通信は直接通信
webサーバ
ブラウザ
webプロキシとは
proxy = 「代理」
webサーバとのデータのやりとりを中継する
webサーバ
ブラウザ
プロキシ
$./proxy
何を実装すればよいのか
プログラムの流れ
webサーバ
ブラウザ
proxy側
listen()
プロキシ
$./proxy
webサーバ
listen()
何を実装すればよいのか
プログラムの流れ
webサーバ
ブラウザ
proxy側
listen()
プロキシ
$./proxy
ブラウザ側の
connect()
webサーバ
listen()
何を実装すればよいのか
プログラムの流れ
webサーバ
ブラウザ
プロキシ
$./proxy
プロキシ側で
accept()
webサーバ
listen()
何を実装すればよいのか
プログラムの流れ
webサーバ
ブラウザ
ブラウザからの
リクエスト
プロキシ
$./proxy
webサーバ
listen()
何を実装すればよいのか
プログラムの流れ
webサーバ
ブラウザ
プロキシ
$./proxy
リクエストから
webサーバを特定
webサーバ
listen()
何を実装すればよいのか
プログラムの流れ
webサーバ
ブラウザ
プロキシ
webサーバ
listen()
$./proxy
webサーバへの
connect()
何を実装すればよいのか
プログラムの流れ
webサーバ
ブラウザ
プロキシ
$./proxy
webサーバが
accept()
何を実装すればよいのか
プログラムの流れ
ブラウザ
プロキシ
$./proxy
ブラウザからの
リクエストを
転送
webサーバ
何を実装すればよいのか
プログラムの流れ
webサーバ
ブラウザ
プロキシ
$./proxy
webサーバからの
レスポンス
何を実装すればよいのか
プログラムの流れ
webサーバ
ブラウザ
プロキシ
$./proxy
webサーバからの
レスポンスを
転送
何を実装すればよいのか
プログラムの流れ
webサーバ
ブラウザ
プロキシ
$./proxy
ソケットクローズ
何を実装すればよいのか
HTTP1.0では
1リクエスト + 1レスポンス = 1コネクション
各リクエストごとに接続を確立します.
何を実装すればよいのか
さらに,ブラウザからのconnectを複数受け付けるには
webサーバ
ブラウザ
プロキシ
$./proxy
何を実装すればよいのか
さらに,ブラウザからのconnectを複数受け付けるには
webサーバ
ブラウザ
proxy側
listen()
プロキシ
$./proxy
ブラウザ側の
connect()
webサーバ
listen()
何を実装すればよいのか
さらに,ブラウザからのconnectを複数受け付けるには
webサーバ
ブラウザ
プロキシ
$./proxy
プロキシ側で
accept()
webサーバ
listen()
何を実装すればよいのか
さらに,ブラウザからのconnectを複数受け付けるには
webサーバ
ブラウザ
listen用ソケット
は残しておく
プロキシ
webサーバ
listen()
$./proxy
別スレッド,または別プロセス
accept()したら
後は並列処理に任せる
proxy
何を実装すればよいのか
さらに,ブラウザからのconnectを複数受け付けるには
webサーバ
ブラウザ
listen用ソケット
は残しておく
プロキシ
webサーバ
listen()
$./proxy
別スレッド,または別プロセス
proxy
何を実装すればよいのか
さらに,ブラウザからのconnectを複数受け付けるには
webサーバ
ブラウザ
プロキシ
ブラウザ側の
connect()
webサーバ
listen()
$./proxy
別スレッド,または別プロセス
proxy
何を実装すればよいのか
さらに,ブラウザからのconnectを複数受け付けるには
webサーバ
ブラウザ
プロキシ
プロキシ側で
accept()
webサーバ
listen()
$./proxy
別スレッド,または別プロセス
proxy
何を実装すればよいのか
さらに,ブラウザからのconnectを複数受け付けるには
webサーバ
ブラウザ
listen用ソケット
は残しておく
プロキシ
webサーバ
listen()
$./proxy
別スレッド,または別プロセス
proxy
proxy
実装方法の例
main {
listenSocket = listen中のソケットを作成;
sockaddr_in変数の各種メンバの設定;
bind();
listen();
while (1) {
browserSocket = accept(listenSocket, …); /* ブラウザからlistenSocketへの接続要求をaccept(); */
スレッド(またはプロセス)の作成;
/*子スレッドor子プロセスに送受信処理を実行させる*/
/*browserSocketをスレッド(またはプロセス)に渡す*/
}/*main関数はaccept→子スレッドorプロセスの作成を繰り返す*/
}
※あくまでも一例です.また,引数や実装方法が簡略化されています.
実装方法の例
スレッド(またはプロセス) {
recv(browserSocketからの文字列 → buffer);
webserverSocket = socket();
hostName = bufferからwebサーバのホスト名を抜き出す;
hostAddress = hostNameからwebサーバのIPアドレスを求める;
hostPort = webサーバならば通常は80を代入;(well-known port)
sockaddr_in型変数のメンバへの設定;
connect();
send(bufferの文字列 → webserverSocket)
スレッドorプロセス
によって作成した子の中で
Selectを用いればよい
while(1) {
browserSocketまたはwebserverSocketが読み取り可能になるまで待機;
if (browserSocketからrecv()できるなら) {
recv(browserSocketからの文字列 → buffer); /* ① */
if (recv()が失敗したら) break;
send(bufferの文字列 → webserverSocket) /* リクエストの転送 */
if (①のrecv()の結果,browserSocketがクーロズされていたとわかった(つまり0バイト受信)) {
break;
}
}
if (webserverSocketからrecv()できるなら) {
recv(webserverSocketからの文字列 → buffer); /* ② */
if (recv()が失敗したら) break;
send(bufferの文字列 → browserSocket) /* レスポンスの転送 */
if (②のrecv()の結果,webserverSocketがクーロズされていたとわかった(つまり0バイト受信)) {
break;
}
}
}
close(browserSocket);
close(webserverSocket);
return 0;
}
※あくまでも一例です.また,引数や実装方法が簡略化されています.
webサーバの特定方法
HTTPのリクエスト,レスポンスはテキストデータである.
HTTP1.0 プロキシを用いたリクエスト
GET http://www.inf.shizuoka.ac.jp/ HTTP/1.0\r\n
Host: www.inf.shizuoka.ac.jp\r\n
(以下省略)
webサーバの特定方法
HTTP1.0 プロキシを用いたリクエスト
GET http://www.inf.shizuoka.ac.jp/ HTTP/1.0\r\n
Host: www.inf.shizuoka.ac.jp\r\n
(以下省略)
ホスト名が特定できた
=名前解決でIPアドレスが分かる
※接続先ポート番号は今回は80番で固定でOK
webサーバの特定方法
HTTP1.0 プロキシを用いたリクエスト
GET http://www.inf.shizuoka.ac.jp/ HTTP/1.0\r\n
Host: www.inf.shizuoka.ac.jp\r\n
(以下省略)
“Host: ”がないならば
“GET”からホスト名を特定
※接続先ポート番号は今回は80番で固定でOK
実装上の注意
webブラウザによっては…
プロキシを使う場合と使わない場合ではリクエストが異なる!
プロキシ使用
プロキシ未使用
GET http://www.inf.shizuoka.ac.jp/ HTTP/1.0\r\n
Host: www.inf.shizuoka.ac.jp\r\n
(以下省略)
GET / HTTP/1.0\r\n
Host: www.inf.shizuoka.ac.jp\r\n
(以下省略)
実装上の注意
webブラウザによっては…
プロキシを使う場合と使わない場合ではリクエストが異なる!
プロキシ使用
プロキシ未使用
GET http://www.inf.shizuoka.ac.jp/ HTTP/1.0\r\n
Host: www.inf.shizuoka.ac.jp\r\n
(以下省略)
GET / HTTP/1.0\r\n
Host: www.inf.shizuoka.ac.jp\r\n
(以下省略)
リクエストをwebサーバに転送するときは“GET”メソッドから
“http://ホスト名”を削除しておこう!!
※メソッドは”GET”だけとは限りません
あくまでも“http://ホスト名”を削除するだけで
それ以外の部分をプロキシ側で書き換えてはいけません
まとめ
webプロキシプログラムは
1. ブラウザからのconnect()をaccept()する
2. ブラウザとの通信用のソケットを並列処理に持っていく
以下,並列処理
1. ブラウザからリクエストを受け取る
2. ブラウザのリクエストからwebサーバを特定する
3. webサーバとの通信用ソケットを作成し,connect()する
4. ブラウザのリクエスト,webサーバからのレスポンスを転送す
る(このとき,リクエストはあらかじめ適切に変換しておく)
5. ソケットを閉じる