//キャッシュ確認 public void CacheConform(Cache cache) { //キャッシュ対象のリクエストかどうかの確認 if (!_oneObj.Request.Cgi) { if (cache.IsTarget(_oneObj.Request.HostName, _oneObj.Request.Uri, _oneObj.Request.Ext)) { _isCacheTarget = true; // Pragma: no-cache が指定されている場合は、蓄積されたキャッシュを否定する var pragmaStr = _oneObj.Header[CS.Client].GetVal("Pragma"); if (pragmaStr != null && pragmaStr.ToLower().IndexOf("no-cache") >= 0) { _proxy.Logger.Set(LogKind.Detail, null, 16, _oneObj.Request.Uri); cache.Remove(_oneObj.Request.HostName, _oneObj.Request.Port, _oneObj.Request.Uri);//存在する場合は、無効化する } else { string modifiedStr = _oneObj.Header[CS.Client].GetVal("If-Modified-Since"); DateTime modified = Util.Str2Time(modifiedStr); OneCache oneCache = cache.Get(_oneObj.Request, modified); if (oneCache != null) //キャッシュが見つかった場合 { _proxy.Logger.Set(LogKind.Detail, null, 14, _oneObj.Request.Uri); _sideState[CS.Server] = HttpSideState.ServerSideRecvBody; //一気に受信完了 _sideState[CS.Client] = HttpSideState.ClientSideRecvRequest; //リクエスト受信完了まで進める _response.Recv("HTTP/1.1 200 OK"); _oneObj.Header[CS.Server] = new Header(oneCache.Header); _oneObj.Body[CS.Server].Set(new byte[oneCache.Body.Length]); //Buffer.BlockCopy(oneCache.Body, 0, oneObj.Body[CS.Server], 0, oneCache.Body.Length); _oneObj.Body[CS.Server].Set(oneCache.Body); _proxy.NoConnect(_oneObj.Request.HostName, _oneObj.Request.Port); //擬似的にContentLength形式で処理する _oneHttpKind = OneHttpKind.ContentLength; _contentLength = _oneObj.Body[CS.Server].Length; //キャッシュによる返答(このオブジェクトはキャッシュしない) _isCacheTarget = false; } } } } }
//キャッシュ確認 public void CacheConform(Cache cache) { //キャッシュ対象のリクエストかどうかの確認 if (!_oneObj.Request.Cgi) { if (cache.IsTarget(_oneObj.Request.HostName, _oneObj.Request.Uri, _oneObj.Request.Ext)) { _isCacheTarget = true; // Pragma: no-cache が指定されている場合は、蓄積されたキャッシュを否定する var pragmaStr = _oneObj.Header[CS.Client].GetVal("Pragma"); if (pragmaStr != null && pragmaStr.ToLower().IndexOf("no-cache") >= 0) { _proxy.Logger.Set(LogKind.Detail, null, 16, _oneObj.Request.Uri); cache.Remove(_oneObj.Request.HostName, _oneObj.Request.Port, _oneObj.Request.Uri);//存在する場合は、無効化する } else { string modifiedStr = _oneObj.Header[CS.Client].GetVal("If-Modified-Since"); DateTime modified = Util.Str2Time(modifiedStr); OneCache oneCache = cache.Get(_oneObj.Request, modified); if (oneCache != null) { //キャッシュが見つかった場合 _proxy.Logger.Set(LogKind.Detail, null, 14, _oneObj.Request.Uri); _sideState[CS.Server] = HttpSideState.ServerSideRecvBody;//一気に受信完了 _sideState[CS.Client] = HttpSideState.ClientSideRecvRequest;//リクエスト受信完了まで進める _response.Recv("HTTP/1.1 200 OK"); _oneObj.Header[CS.Server] = new Header(oneCache.Header); _oneObj.Body[CS.Server].Set(new byte[oneCache.Body.Length]); //Buffer.BlockCopy(oneCache.Body, 0, oneObj.Body[CS.Server], 0, oneCache.Body.Length); _oneObj.Body[CS.Server].Set(oneCache.Body); _proxy.NoConnect(_oneObj.Request.HostName, _oneObj.Request.Port); //擬似的にContentLength形式で処理する _oneHttpKind = OneHttpKind.ContentLength; _contentLength = _oneObj.Body[CS.Server].Length; //キャッシュによる返答(このオブジェクトはキャッシュしない) _isCacheTarget = false; } } } } }
//接続単位の処理 override public void _subThread(SockObj sockObj) { // 上位プロキシを使用するかどうかのフラグ bool useUpperProxy = this.OpBase.ValBool("useUpperProxy"); Dictionary <CS, TcpObj> sock = new Dictionary <CS, TcpObj>(2); sock[CS.CLIENT] = (TcpObj)sockObj; sock[CS.SERVER] = null; sock[CS.CLIENT].Timeout = timeout; //クライアント及びサーバ双方のヘッダを処理するクラス Dictionary <CS, Header> header = new Dictionary <CS, Header>(2); header[CS.CLIENT] = new Header(); header[CS.SERVER] = new Header(); //クライアント及びサーバ双方のバッファ Dictionary <CS, byte[]> buf = new Dictionary <CS, byte[]>(2); buf[CS.CLIENT] = new byte[0]; buf[CS.SERVER] = new byte[0]; Request request = new Request();//クライアントからのリクエストを処理するクラス //Response response = new Response();//サーバからのレスポンスを処理するクラス OneCache oneCache = null; while (true) { //*************************************************************** //クライアントからのデータを読み込む //*************************************************************** { //while (life && sock[CS.CLIENT].Length() == 0) { // Thread.Sleep(30); //} //接続されたが、クライアントからのリクエストが5秒間来ない場合は、スレッドを破棄する for (int i = 0; life && sock[CS.CLIENT].Length() == 0; i++) { Thread.Sleep(50); if (i > 100) { Logger.Set(LOG_KIND.DEBUG, sock[CS.CLIENT], 999, "デバッグ中 クライアントから5秒以上データが来ないので切断する"); goto end;//Ver5.0.0-a21 } } //リクエスト取得(内部データは初期化される)ここのタイムアウト値は、大きすぎるとブラウザの切断を取得できないでブロックしてしまう if (!request.Recv(this.Logger, sock[CS.CLIENT], timeout, ref life)) { //Logger goto end; } //bool useRequestLog リクエストを通常ログで表示する this.Logger.Set(useRequestLog ? LOG_KIND.NOMAL : LOG_KIND.DETAIL, null, 0, string.Format("{0}", request.RequestStr)); //*************************************************************** //URL制限 //*************************************************************** if (limitUrl.IsHit(request.RequestStr)) { this.Logger.Set(LOG_KIND.NOMAL, null, 10, request.RequestStr); goto end; } //*************************************************************** //上位プロキシのチェック //*************************************************************** if (useUpperProxy) { // 上位プロキシを経由しないサーバの確認 foreach (string hostName in disableAddressList) { if (request.Protocol == PROXY_PROTOCOL.SSL) { if (request.HostName.IndexOf(hostName) == 0) { useUpperProxy = false; break; } } else { string str = request.RequestStr.Substring(11); if (str.IndexOf(hostName) == 0) { useUpperProxy = false; break; } } } } //ヘッダの取得 if (!header[CS.CLIENT].Recv(sock[CS.CLIENT], timeout, ref life)) { //Logger goto end; } //ヘッダの追加処理 if (request.Protocol == PROXY_PROTOCOL.HTTP) { if (!this.OpBase.ValBool("useBrowserHedaer")) { if (this.OpBase.ValBool("addHeaderRemoteHost")) { header[CS.CLIENT].Append("Remote-Host-Wp", Define.ServerAddress()); } if (this.OpBase.ValBool("addHeaderXForwardedFor")) { header[CS.CLIENT].Append("X-Forwarded-For", Define.ServerAddress()); } if (this.OpBase.ValBool("addHeaderForwarded")) { string str = string.Format("by {0} (Version {1}) for {2}", Define.ApplicationName(), kanel.Ver.Version(), Define.ServerAddress()); header[CS.CLIENT].Append("Forwarded", str); } } } if (request.Protocol == PROXY_PROTOCOL.SSL) { if (!useUpperProxy) { //取得したリクエストをバッファに格納する buf[CS.CLIENT] = new byte[0]; buf[CS.SERVER] = Bytes.Create("HTTP/1.0 200 Connection established\r\n\r\n");//CONNECTが成功したことをクライアントに返す } else { //上位プロキシを使用する場合(リクエストラインはそのまま使用される) buf[CS.CLIENT] = Bytes.Create(request.SendLine(useUpperProxy), header[CS.CLIENT].GetBytes()); } } else if (request.Protocol == PROXY_PROTOCOL.HTTP) //HTTPの場合 //Ver5.0.0-b3 削除 //header[CS.CLIENT].Remove("Proxy-Connection"); //取得したリクエストをバッファに格納する //上位プロキシを使用する場合(リクエストラインはそのまま使用される) { buf[CS.CLIENT] = Bytes.Create(request.SendLine(useUpperProxy), header[CS.CLIENT].GetBytes()); //Ver5.0.0-a5 //POSTの場合は、更にクライアントからのデータを読み込む if (request.Method == HTTP_METHOD.POST) { //int len = 0; string strContentLength = header[CS.CLIENT].GetVal("Content-Length"); if (strContentLength != null) { try { int len = Convert.ToInt32(strContentLength); if (0 < len) { byte[] data = sock[CS.CLIENT].Recv(len, timeout); buf[CS.CLIENT] = Bytes.Create(buf[CS.CLIENT], data); } } catch { this.Logger.Set(LOG_KIND.ERROR, null, 22, request.Uri); goto end; } } } } } //キャッシュ対象のリクエストかどうかの確認 if (request.Protocol == PROXY_PROTOCOL.HTTP && !request.Cgi) { if (cache.IsTarget(request.HostName, request.Uri, request.Ext)) { string headerStr = header[CS.CLIENT].ToString(); bool noCache = false; if (headerStr.ToLower().IndexOf("no-cache") >= 0) { noCache = true; //キャッシュしない this.Logger.Set(LOG_KIND.DETAIL, null, 16, request.Uri); cache.Remove(request.HostName, request.Port, request.Uri); //存在する場合は、無効化する } else { string modifiedStr = header[CS.CLIENT].GetVal("If-Modified-Since"); DateTime modified = Util.Str2Time(modifiedStr); byte[] dat = cache.Get(request, modified); if (dat != null) //キャッシュが見つかった場合 { this.Logger.Set(LOG_KIND.DETAIL, null, 14, request.Uri); sock[CS.CLIENT].AsciiSend("HTTP/1.0 200 OK", OPERATE_CRLF.YES); int c = sock[CS.CLIENT].Send(dat); goto end; } } if (!noCache) { string url = string.Format("{0}:{1}{2}", request.HostName, request.Port, request.Uri); //キャッシュ対象の場合だけ、受信用のオブジェクトを生成する oneCache = new OneCache(request.HostName, request.Port, request.Uri); } } } //*************************************************************** // サーバとの接続 //*************************************************************** { string hostName = request.HostName; int port = request.Port; if (useUpperProxy) //上位プロキシを使用する場合 { hostName = this.OpBase.ValString("upperProxyServer"); port = this.OpBase.ValInt("upperProxyPort"); } List <Ip> ipList = new List <Ip>(); ipList.Add(new Ip(hostName)); if (ipList[0].ToString() == "0.0.0.0") { ipList = kanel.dnsCache.Get(hostName); if (ipList == null || ipList.Count == 0) { this.Logger.Set(LOG_KIND.ERROR, null, 11, hostName); goto end; } } SSL ssl = null; foreach (Ip ip in ipList) { sock[CS.SERVER] = Inet.Connect(ref life, kanel, this.Logger, ip, port, ssl); if (sock[CS.SERVER] != null) { break; } } if (sock[CS.SERVER] == null) { Logger.Set(LOG_KIND.DETAIL, sock[CS.CLIENT], 26, string.Format("{0}:{1}", ipList[0].ToString(), port)); return; } sock[CS.SERVER].Timeout = timeout; } //*************************************************************** // パイプ処理 //*************************************************************** if (request.Protocol == PROXY_PROTOCOL.HTTP || request.Protocol == PROXY_PROTOCOL.SSL) { // パイプ(HTTP/SSL) PipeHttp(sock, buf, request, header, oneCache);//パイプ処理 } else if (request.Protocol == PROXY_PROTOCOL.FTP) { // パイプ(FTP) dataPort = PipeFtp(sock, request, dataPort);//パイプ処理 if (dataPort > dataPortMax) { dataPort = dataPortMin; } } continue; end: break; //*************************************************************** // 終了処理 //*************************************************************** //if(sock[CS.CLIENT] != null) // sock[CS.CLIENT].Close(); //if(sock[CS.SERVER] != null) // sock[CS.SERVER].Close(); } //*************************************************************** // 終了処理 //*************************************************************** if (sock[CS.CLIENT] != null) { sock[CS.CLIENT].Close(); } if (sock[CS.SERVER] != null) { sock[CS.SERVER].Close(); } }