/// <summary> /// OnReceiveResponseをoverrideし、レスポンスデータを読み取る。 /// </summary> protected override void OnReceiveResponse() { AfterReadResponseHeaders?.Invoke(new HttpResponse(this.ResponseStatusLine, this.ResponseHeaders, null)); //200だけ if (this.ResponseStatusLine.StatusCode != 200) { return; } // GetContentだけやるとサーバーからデータ全部読み込むけどクライアントに送らないってことになる。 // のでTransferEncodingとContentLengthを書き換えてchunkedじゃないレスポンスとしてクライアントに送信してやる必要がある。 // // RFC 7230 の 3.3.1 を見る限りだと、Transfer-Encoding はリクエスト/レスポンスチェーンにいるどの recipient も // デコードしておっけーみたいに書いてあるから、HTTP的には問題なさそう。 // https://tools.ietf.org/html/rfc7230#section-3.3.1 // // ただ4.1.3のロジックとTrotiNetのとを見比べると trailer フィールドへの対応が足りてるのかどうか疑問が残る。 // https://tools.ietf.org/html/rfc7230#section-4.1.3 var response = this.ResponseHeaders.IsUnknownLength() ? this.GetContentWhenUnknownLength() : this.GetContent(); this.State.NextStep = null; //既定の後続動作(SendResponse)をキャンセル(自前で送信処理を行う) //Content-Encoding対応っぽい using (var ms = new MemoryStream()) { var stream = this.GetResponseMessageStream(response); stream.CopyTo(ms); var content = ms.ToArray(); this.currentSession.Response = new HttpResponse(this.ResponseStatusLine, this.ResponseHeaders, content); } // Transfer-Encoding: Chunked をやめて Content-Length を使うようヘッダ書き換え this.ResponseHeaders.TransferEncoding = null; this.ResponseHeaders.ContentLength = (uint)response.Length; this.SendResponseStatusAndHeaders(); //クライアントにHTTPステータスとヘッダ送信 this.SocketBP.TunnelDataTo(this.TunnelBP, response); //クライアントにレスポンスボディ送信 //keep-aliveとかじゃなかったら閉じる if (!this.State.bPersistConnectionPS) { this.SocketPS?.CloseSocket(); this.SocketPS = null; } //AfterSessionCompleteイベント AfterSessionComplete?.Invoke(this.currentSession); }
/// <summary> /// Override OnReceiveResponse to read response data /// </summary> protected override void OnReceiveResponse() { #region Nekoxy Code AfterReadResponseHeaders?.Invoke(new HttpResponse(this.ResponseStatusLine, this.ResponseHeaders, null)); if (this.ResponseStatusLine.StatusCode != 200) { return; } var response = this.ResponseHeaders.IsUnknownLength() ? this.GetContentWhenUnknownLength() : this.GetContent(); this.State.NextStep = null; using (var ms = new MemoryStream()) { var stream = this.GetResponseMessageStream(response); stream.CopyTo(ms); var content = ms.ToArray(); this.currentSession.Response = new HttpResponse(this.ResponseStatusLine, this.ResponseHeaders, content); } #endregion if (BeforeResponse != null) { response = BeforeResponse?.Invoke(this.currentSession, this.currentSession.Response.Body); this.ResponseHeaders.ContentEncoding = null; // remove gzip and chunked... } #region Nekoxy Code this.ResponseHeaders.TransferEncoding = null; this.ResponseHeaders.ContentLength = (uint)response.Length; this.SendResponseStatusAndHeaders(); // Send HTTP status & head to client this.SocketBP.TunnelDataTo(this.TunnelBP, response); // Send response body to client if (!this.State.bPersistConnectionPS) { this.SocketPS?.CloseSocket(); this.SocketPS = null; } AfterSessionComplete?.Invoke(this.currentSession); #endregion }
private static void InvokeAfterReadResponseHeaders(HttpResponse response) => AfterReadResponseHeaders?.Invoke(response);