HTTPプロトコル解析
ISO-OSIの7層ネットワークモデル
アプリケーション層
ウェブサービスとエンドユーザーの間のインターフェース。以下のプロトコルがあります。
プレゼンテーション層
データ表現、セキュリティ、圧縮。JPEG、ASCll、EBCDIC、暗号化フォーマットなど。
セッション層
セッションの確立、管理、終了。対応ホストプロセス、ローカルホストとリモートホスト間の進行中のセッション
トランスポート層
データを送信するためのプロトコル・ポート番号、フロー制御、エラー・チェックを定義します。プロトコルは、TCP UDP、パケットがネットワークカードを出ると、ネットワーク・トランスポート層に入ります。
ネットワーク・レイヤ 論理アドレス・アドレッシングを実行し、異なるネットワーク間のパス選択を可能にします。プロトコルは次のとおりです。
データリンク層
論理接続の確立、ハードウェアアドレスのアドレス指定、エラーチェックなどの機能。ビットをバイトとフレームに結合し、MACアドレスでメディアにアクセス。
物理層
物理的な接続の確立、維持、切断。
ストリーミング:ユニットの明確な分割はなく、前後の正しい順序のみが保証されます。
ポート:受信パケットは様々なアプリケーションに分配されます。
require('net'):ノード依存ライブラリ
パッケージ
IPアドレス
libnet/libpcap: libnet は IP パケットを構築して送信し、libpcap は NIC を流れる NIC からのすべてのパケットを取得します。
全二重チャンネルには優先順位関係はありませんが、HTTPはクライアントがリクエストを開始し、サーバーがレスポンスを返す必要があります。
サーバ側の環境準備
POST / HTTP/1.1
Request line
headers
field1=aaa&code=x%3D1
body
const http = require('http');
http.createServer((request, response) => {
let body = [];
request.on('error',(err) => {
console.error(err);
}).on('data',(chunk) =>{
body.push(chunk.toString())
}).on('end',()=>{
body = Buffer.concat(body).toString();
console.log('body:',body);
response.writeHead(200,{'Content-T':'text/html'});
response.end("<div style='width:200px;height:200px;background:red'>123</div>")
})
}).listen(8080);
console.log('server started');
HTTPリクエストの実装
const net = require("net");
class Request {
constructor(option) {
this.method = option.method || 'GET';
this.host = option.host;
this.port = option.port || 80;
this.path = option.path || '/';
this.body = option.body || {};
this.headers = option.headers || {};
if(!this.headers["Content-Type"]){
this.headers["Content-Type"] = "application/x-www-form-urlencoded"
}
if(this.headers["Content-Type"] ==="application/json"){
this.bodyText = JSON.stringify(this.body)
}else if(this.headers["Content-Type"] === "application/x-www-form-urlencoded"){
this.bodyText = Object.keys(this.body).map(key => `${key}=${encodeURIComponent(this.body[key])}`).join('&')
}
this.headers["Content-Length"] = this.bodyText.length;
}
send(){
return new Promise((resolve, reject) => {
//.....
});
}
}
void async function () {
let request = new Request({
method: "POST",
host: ".1",
port: "8088",
path: "/",
headers: {
["X-Foo2"]: "customed"
},
body: {
name: 'Midsummer'
}
})
let response = await request.send();
console.log(response);
}()
IV.書き込み関数を送信し、応答形式を理解します。
- state line HTTP/1.1 200 OK
- headers
- body
リクエストの送信
response
- レスポンスは分割して作成しなければならないので、ResponseParser で "組み立て" ます。
- ResponseParser は、ResponseText をセグメント化し、ステートマシンを使用してテキストの構造を分析します。
response body
- レスポンス本体はContent-Typeによって異なる構造を持つ可能性があるため、サブパーサーの構造を使用して問題を解決します。
- TrunkedBodyParserを例にとると、同じステートマシンがボディのフォーマット処理に使われます。