public bool Add(OneCache oneCache) { if (AddCache(oneCache)) { //キャッシュ追加処理 Length += oneCache.Length; return true; } return false; }
abstract protected bool AddCache(OneCache oneCache);//キャッシュ追加処理 public bool Add(OneCache oneCache) { if (AddCache(oneCache)) //キャッシュ追加処理 { Length += oneCache.Length; return(true); } return(false); }
//キャッシュ追加処理 protected override bool AddCache(OneCache oneCache) { oneCache.LastAccess = DateTime.Now;//最終アクセス時刻の記録 // メモリ上のデータの差し替えに該当する場合 var o = Get(oneCache.HostName, oneCache.Port, oneCache.Uri); if (o != null) { Remove(oneCache.HostName, oneCache.Port, oneCache.Uri); } //キャッシュを追加 _ar.Add(oneCache); return true; }
//キャッシュ取得処理 public override OneCache Get(string hostName, int port, string uri) { var path = CreatePath(hostName, port, uri); if (File.Exists(path)) { var oneCache = new OneCache(hostName, port, uri); if (oneCache.Read(path)) { oneCache.LastAccess = DateTime.Now;//最終アクセス時刻の記録 return oneCache; } } return null; }
//キャッシュ追加処理 override protected bool AddCache(OneCache oneCache) { oneCache.LastAccess = DateTime.Now;//最終アクセス時刻の記録 // メモリ上のデータの差し替えに該当する場合 var o = Get(oneCache.HostName, oneCache.Port, oneCache.Uri); if (o != null) { Remove(oneCache.HostName, oneCache.Port, oneCache.Uri); } //キャッシュを追加 _ar.Add(oneCache); return(true); }
// アクセス時間が一番古いデータ取得する public OneCache Old() { OneCache result = null; var dt = DateTime.Now; foreach (var oneCache in _ar) { if (dt.Ticks > oneCache.LastAccess.Ticks) { result = oneCache; } } return(result); }
//キャッシュ確認 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 override OneCache Get(string hostName, int port, string uri) { var path = CreatePath(hostName, port, uri); if (File.Exists(path)) { var oneCache = new OneCache(hostName, port, uri); if (oneCache.Read(path)) { oneCache.LastAccess = DateTime.Now;//最終アクセス時刻の記録 return(oneCache); } } return(null); }
// �L���b�V���lj� public bool Add(OneCache oneCache) { if (!_useCache) return false; if (oneCache == null) return false; //�T�C�Y��0�̂�̂́A�L���b�V���ΏۊO�Ƃ��� if (oneCache.Length <= 0) { return false; } if (oneCache.Length > _maxSize * 1000) {//�ő�T�C�Y�����f�[�^�̓L���b�V���̑ΏۊO�ƂȂ� logger.Set(LogKind.Detail, null, 20, string.Format("{0}:{1}{2}", oneCache.HostName, oneCache.Port, oneCache.Uri)); return false; } lock (this) { // �r������ //�������L���b�V���ւ̕ۑ� if (_memoryCache != null) { //�������L���b�V���Ɏ��܂邩�ǂ����̔��f while (_memoryCache.Length + oneCache.Length > _memorySize * 1024) { OneCache old = _memoryCache.Old();//��ԌÂ���̂�擾���� if (old == null) return false; //��ԌÂ���̂�������L���b�V������폜���� _memoryCache.Remove(old.HostName, old.Port, old.Uri); //��ԌÂ���̂�f�B�X�N�L���b�V���ɕۑ����� if (_diskCache != null) _diskCache.Add(old); } if (_memoryCache.Add(oneCache)) { logger.Set(LogKind.Detail, null, 4, string.Format("{0}:{1}{2}", oneCache.HostName, oneCache.Port, oneCache.Uri)); return true; } } //�f�B�X�N�L���b�V���ւ̕ۑ� if (_diskCache != null) { if (_diskCache.Add(oneCache)) { logger.Set(LogKind.Detail, null, 5, string.Format("{0}:{1}{2}", oneCache.HostName, oneCache.Port, oneCache.Uri)); return true; } } } // �r������ logger.Set(LogKind.Detail, null, 18, string.Format("{0}:{1}{2}", oneCache.HostName, oneCache.Port, oneCache.Uri)); return false; }
//キャッシュ追加処理 protected override bool AddCache(OneCache oneCache) { //サイズ制限は無視して書き込む //サイズ制限をオーバーしたものは、Cache.Interval()で削除される if (oneCache.Uri.Length > 9600) { //ディスクキャッシュの場合は、これはきついかも //エラーにする? return false; } if (oneCache.Uri.IndexOf(':') != -1) { // URLに:が含まれているとき、ディスクには書き込まない return false; } var path = CreatePath(oneCache.HostName, oneCache.Port, oneCache.Uri); oneCache.Save(path); return true; }
//キャッシュ追加処理 override protected bool AddCache(OneCache oneCache) { //サイズ制限は無視して書き込む //サイズ制限をオーバーしたものは、Cache.Interval()で削除される if (oneCache.Uri.Length > 9600) { //ディスクキャッシュの場合は、これはきついかも //エラーにする? return(false); } if (oneCache.Uri.IndexOf(':') != -1) { // URLに:が含まれているとき、ディスクには書き込まない return(false); } var path = CreatePath(oneCache.HostName, oneCache.Port, oneCache.Uri); oneCache.Save(path); return(true); }
//キャッシュ確認 public void CacheWrite(Cache cache) { if (!_isCacheTarget)//キャッシュ対象外 { return; } if (_response.Code != 200)//レスポンスコードが200のものだけが対象 { return; } //Ver5.6.1 if (!_oneObj.Body[CS.Server].CanUse) { return; } var oneCache = new OneCache(_oneObj.Request.HostName, _oneObj.Request.Port, _oneObj.Request.Uri); oneCache.Add(_oneObj.Header[CS.Server], _oneObj.Body[CS.Server].Get()); cache.Add(oneCache); }
// �L���b�V���擾 public OneCache Get(Request request, DateTime modified) { // �r������ lock (this) { // �������L���b�V����ɑ��݂��邩�ǂ����H if (_memoryCache != null) { OneCache oneCache = _memoryCache.Get(request.HostName, request.Port, request.Uri); if (oneCache != null) { //�������L���b�V���Ńq�b�g���� if (modified.Ticks == 0 || oneCache.LastModified.Ticks == 0 || modified == oneCache.LastModified) { //�L������ long d = oneCache.Expires.Ticks; //�w�b�_�Ŏ����ꂽ�ꍇ if (d == 0) //�w�b�_�Ŏ�����Ă��Ȃ��ꍇ�́A�{�T�[�o�̃f�t�H���g�l���g�p����� { d = oneCache.CreateDt.AddHours(_expires).Ticks; } if (d > DateTime.Now.Ticks) //�L����������Ă��Ȃ����ǂ��� { return(oneCache); //�L���L���b�V�� } } // �������L���b�V���Ƀf�[�^�����݂��邪�u�L���������o�߂��Ă���v������́A�uModified����v���Ȃ��v�̂ō폜���� _memoryCache.Remove(request.HostName, request.Port, request.Uri); if (_diskCache != null) { _diskCache.Remove(request.HostName, request.Port, request.Uri); } return(null); } } // �f�B�X�N�L���b�V����ɑ��݂��邩�ǂ����H if (_diskCache != null) { OneCache oneCache = _diskCache.Get(request.HostName, request.Port, request.Uri); if (oneCache != null) { //�f�B�X�N�L���b�V���Ńq�b�g���� if (modified.Ticks == 0 || oneCache.LastModified.Ticks == 0 || modified == oneCache.LastModified) { //�L������ long d = oneCache.Expires.Ticks; //�w�b�_�Ŏ����ꂽ�ꍇ if (d == 0) //�w�b�_�Ŏ�����Ă��Ȃ��ꍇ�́A�{�T�[�o�̃f�t�H���g�l���g�p����� { d = oneCache.CreateDt.AddHours(_expires).Ticks; } if (d > DateTime.Now.Ticks) //�L����������Ă��Ȃ����ǂ��� //�������L���b�V���ւ̈ړ� { if (_memoryCache != null && _memoryCache.Add(oneCache)) { logger.Set(LogKind.Detail, null, 19, string.Format("{0}:{1}{2}", oneCache.HostName, oneCache.Port, oneCache.Uri)); } return(oneCache);//�L���L���b�V�� } } //�f�B�X�N�L���b�V���Ƀf�[�^�����݂��邪�u�L���������o�߂��Ă���v������́A�uModified����v���Ȃ��v�̂ō폜���� _diskCache.Remove(request.HostName, request.Port, request.Uri); return(null); } } }// �r������ return(null); }
//*************************************************************** // パイプ(HTTP/SSL) //*************************************************************** void PipeHttp(Dictionary <CS, TcpObj> sock, Dictionary <CS, byte[]> buf, Request request, Dictionary <CS, Header> header, OneCache oneCache) { Response response = new Response();//サーバからのレスポンスを処理するクラス //*************************************************************** // パイプ //*************************************************************** bool serverHeda = false; if (request.Protocol == PROXY_PROTOCOL.HTTP) { serverHeda = true; //ヘッダ受信するのはHTTPの時だけ } bool isText = false; //コンテンツ制限の対象かどうかのフラグ CHARSET charset = CHARSET.UNKNOWN; long contentLength = 0; //サーバのヘッダで示される受信データのサイズ long sendLength = 0; //クライアント側へ送信完了したデータのサイズ long timeoutCounter = 0; //タイムアウトカウンタ CS cs = CS.SERVER; while (life) { Thread.Sleep(0); cs = Reverse(cs);//サーバ側とクライアント側を交互に処理する //Thread.Sleep(0);//Ver5.0.0-a19 // クライアントの切断の確認 if (sock[CS.CLIENT].State != SOCKET_OBJ_STATE.CONNECT) { if (buf[CS.SERVER].Length == 0) { cache.Add(oneCache); } //クライアントが切断された場合は、処理を継続する意味が無い this.Logger.Set(LOG_KIND.DETAIL, null, 8, "close client"); break; } //******************************************************* //処理するデータが到着していない場合の処理 //******************************************************* if (sock[CS.CLIENT].Length() == 0 && sock[CS.SERVER].Length() == 0 && buf[CS.CLIENT].Length == 0 && buf[CS.SERVER].Length == 0) { // サーバの切断の確認 if (sock[CS.SERVER].State != SOCKET_OBJ_STATE.CONNECT) { cache.Add(oneCache); //送信するべきデータがなく、サーバが切断された場合は、処理終了 this.Logger.Set(LOG_KIND.DETAIL, null, 8, "close server"); break; } //Ver5.0.0-a3 HTTP/1.1対応(次のリクエスト待ちへ進む) if (!serverHeda) { int x = 10; } //Ver5.0.0-a11 //if (response.Code != 0 && <response.Code != 200) { if (response.Code != 0 && (response.Code < 200 && 300 <= response.Code)) { //見切り切断 this.Logger.Set(LOG_KIND.DETAIL, sock[CS.SERVER], 8, string.Format("Response Code = {0}", response.Code)); break; } //Thread.Sleep(50); Thread.Sleep(1);//Ver5.0.0-a19 //タイムアウトカウンタのインクリメント timeoutCounter++; //if(timeoutCounter*50>timeout*1000){ if (timeoutCounter > timeout * 1000) { //タイムアウト this.Logger.Set(LOG_KIND.NOMAL, sock[CS.SERVER], 3, string.Format("option TIMEOUT={0}sec", timeout)); break; } } else { timeoutCounter = 0;//タイムアウトカウンタのリセット } //******************************************************* // 受信処理 //******************************************************* if (buf[cs].Length == 0) //バッファが空の時だけ処理する { if (!serverHeda && cs == CS.CLIENT && buf[CS.SERVER].Length == 0) //次のリクエスト { int x = 10; } if (cs == CS.SERVER && serverHeda) // HTTPのヘッダ受信 { while (life && sock[CS.SERVER].State == SOCKET_OBJ_STATE.CONNECT && sock[CS.CLIENT].State == SOCKET_OBJ_STATE.CONNECT && sock[CS.SERVER].Length() == 0) { Thread.Sleep(30); } //レスポンスの取得 if (!response.Recv(this.Logger, sock[CS.SERVER], timeout, ref life)) { this.Logger.Set(LOG_KIND.ERROR, sock[CS.SERVER], 6, ""); break; } if (oneCache != null) { if (response.Code != 200) //200以外は、キャッシュ保存の対象にならないので無効化する //this.Logger.Set(LOG_KIND.DEBUG, 222, string.Format("response code [{0}]", response.Code)); { oneCache = null; } } //ヘッダの受信 v2.1.6 すべてのレスポンスをConnectint: close にして、リクエストの抜けを排除する HTTP/1.1でも擬似的に使用できるようになる if (!header[cs].Recv(sock[cs], timeout, ref life)) { this.Logger.Set(LOG_KIND.ERROR, sock[CS.SERVER], 7, ""); break; } //Ver5.0.0-a22 //サーバからのヘッダにno-cacheが指定されている場合も、キャッシュ対象からはずす string headerStr = header[cs].ToString(); if (headerStr.ToLower().IndexOf("no-cache") >= 0) { this.Logger.Set(LOG_KIND.DETAIL, null, 16, request.Uri); cache.Remove(request.HostName, request.Port, request.Uri);//存在する場合は、無効化する oneCache = null; } if (oneCache != null) { oneCache.Add(header[CS.SERVER]); } //サーバから受信したレスポンス及びヘッダをバッファに展開する buf[cs] = Bytes.Create(response.ToString(), "\r\n", header[cs].GetBytes()); serverHeda = false;//ヘッダ処理終了 string str = header[CS.SERVER].GetVal("Content-Length"); if (str != null) { contentLength = Convert.ToInt32(str); //Ver5.0.0-a19 //クライアントに送信するのは、本体+ヘッダとなるので contentLength += buf[cs].Length; } //コンテンツ制限の対象かどうかのフラグを設定する if (limitString != null)//コンテンツ制限に文字列が設定されている場合 { string contentType = header[CS.SERVER].GetVal("Content-Type"); if (contentType != null) { if (contentType.ToLower().IndexOf("text/h") == 0) { isText = true; } if (contentType.ToLower().IndexOf("text/t") == 0) { isText = true; } } } } else { //処理すべきデータ数の取得 int len = sock[cs].Length(); byte[] b = sock[cs].Recv(len, timeout); if (b != null) { if (cs == CS.CLIENT) { string s = Encoding.ASCII.GetString(b); int x = 10; } buf[cs] = Bytes.Create(buf[cs], b); //logger.Set(LOG_KIND.DEBUG, 0, string.Format("cs={0} Recv()={1}", cs, b.Length)); if (cs == CS.SERVER) { if (oneCache != null) { oneCache.Add(b);//キャッシュ } //コンテンツ制限 if (isText) { if (charset == CHARSET.UNKNOWN) { string s = Encoding.ASCII.GetString(b); int index = s.ToLower().IndexOf("charset"); if (0 <= index) { s = s.Substring(index + 8); if (s.ToLower().IndexOf("x-sjis") >= 0) { charset = CHARSET.SJIS; } else if (s.ToLower().IndexOf("shift_jis") >= 0) { charset = CHARSET.SJIS; } else if (s.ToLower().IndexOf("x-euc-jp") >= 0) { charset = CHARSET.EUC; } else if (s.ToLower().IndexOf("euc-jp") >= 0) { charset = CHARSET.EUC; } else if (s.ToLower().IndexOf("utf-8") >= 0) { charset = CHARSET.UTF8; } else if (s.ToLower().IndexOf("utf-7") >= 0) { charset = CHARSET.UTF7; } else if (s.ToLower().IndexOf("iso-2022-jp") >= 0) { charset = CHARSET.JIS; } else { //int k = 0; } } } string str = ""; switch (charset) { case CHARSET.ASCII: str = Encoding.ASCII.GetString(b); break; case CHARSET.SJIS: str = Encoding.GetEncoding("shift-jis").GetString(b); break; case CHARSET.EUC: str = Encoding.GetEncoding("euc-jp").GetString(b); break; case CHARSET.JIS: str = Encoding.GetEncoding(50222).GetString(b); break; case CHARSET.UTF8: str = Encoding.UTF8.GetString(b); break; case CHARSET.UTF7: str = Encoding.UTF7.GetString(b); break; case CHARSET.UNKNOWN: str = Encoding.ASCII.GetString(b); break; } //コンテンツ制限 string hitStr = limitString.IsHit(str); if (hitStr != null) { //制限にヒットした場合 this.Logger.Set(LOG_KIND.NOMAL, sock[CS.SERVER], 21, hitStr); break; } } } } } } //******************************************************* // 送信処理 //******************************************************* if (buf[cs].Length != 0) //バッファにデータが入っている場合だけ処理する { int c = 0; c = sock[Reverse(cs)].Send(buf[cs]); if (cs == CS.SERVER) //サーバ側から受信したデータをクライアント側に送信した分だけカウントする { if (contentLength != 0) { sendLength += c; //クライアント側への送信完了時に確認する //受信データサイズのすべてがクライアントへ送信完了したとき切断する if (contentLength <= sendLength) { cache.Add(oneCache); this.Logger.Set(LOG_KIND.DETAIL, sock[CS.SERVER], 8, "compleate"); break; } } } //logger.Set(LOG_KIND.DEBUG, 0, string.Format("cs={0} Send()={1}", Reverse(cs), c)); if (c == buf[cs].Length) { buf[cs] = new byte[0]; //クライアント側への送信完了時に確認する //if(cs==CS.SERVER){ // //受信データサイズのすべてがクライアントへ送信完了したとき切断する // if (contentLength != 0 && contentLength <= sendLength) { // cache.Add(oneCache); // this.Logger.Set(LOG_KIND.DETAIL,sock[CS.SERVER],8,"compleate"); // break; // } //} } else { this.Logger.Set(LOG_KIND.ERROR, sock[CS.SERVER], 9, string.Format("sock.Send() return {0}", c)); break; } } } }
//接続単位の処理 public override 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(); }
//キャッシュ確認 public void CacheWrite(Cache cache) { if (!_isCacheTarget)//キャッシュ対象外 return; if (_response.Code != 200)//レスポンスコードが200のものだけが対象 return; //Ver5.6.1 if (!_oneObj.Body[CS.Server].CanUse) return; var oneCache = new OneCache(_oneObj.Request.HostName, _oneObj.Request.Port, _oneObj.Request.Uri); oneCache.Add(_oneObj.Header[CS.Server], _oneObj.Body[CS.Server].Get()); cache.Add(oneCache); }
//*************************************************************** // パイプ(HTTP/SSL) //*************************************************************** void PipeHttp(Dictionary<CS, TcpObj> sock, Dictionary<CS, byte[]> buf, Request request, Dictionary<CS, Header> header, OneCache oneCache) { Response response = new Response();//サーバからのレスポンスを処理するクラス //*************************************************************** // パイプ //*************************************************************** bool serverHeda = false; if (request.Protocol == PROXY_PROTOCOL.HTTP) serverHeda = true;//ヘッダ受信するのはHTTPの時だけ bool isText = false;//コンテンツ制限の対象かどうかのフラグ CHARSET charset = CHARSET.UNKNOWN; long contentLength = 0;//サーバのヘッダで示される受信データのサイズ long sendLength = 0;//クライアント側へ送信完了したデータのサイズ long timeoutCounter = 0;//タイムアウトカウンタ CS cs = CS.SERVER; while (life) { Thread.Sleep(0); cs = Reverse(cs);//サーバ側とクライアント側を交互に処理する //Thread.Sleep(0);//Ver5.0.0-a19 // クライアントの切断の確認 if (sock[CS.CLIENT].State != SOCKET_OBJ_STATE.CONNECT) { if (buf[CS.SERVER].Length == 0) { cache.Add(oneCache); } //クライアントが切断された場合は、処理を継続する意味が無い this.Logger.Set(LOG_KIND.DETAIL,null,8,"close client"); break; } //******************************************************* //処理するデータが到着していない場合の処理 //******************************************************* if (sock[CS.CLIENT].Length() == 0 && sock[CS.SERVER].Length() == 0 && buf[CS.CLIENT].Length == 0 && buf[CS.SERVER].Length == 0) { // サーバの切断の確認 if (sock[CS.SERVER].State != SOCKET_OBJ_STATE.CONNECT) { cache.Add(oneCache); //送信するべきデータがなく、サーバが切断された場合は、処理終了 this.Logger.Set(LOG_KIND.DETAIL,null,8,"close server"); break; } //Ver5.0.0-a3 HTTP/1.1対応(次のリクエスト待ちへ進む) if(!serverHeda){ int x = 10; } //Ver5.0.0-a11 //if (response.Code != 0 && <response.Code != 200) { if (response.Code != 0 && (response.Code<200 && 300<=response.Code)) { //見切り切断 this.Logger.Set(LOG_KIND.DETAIL,sock[CS.SERVER],8,string.Format("Response Code = {0}",response.Code)); break; } //Thread.Sleep(50); Thread.Sleep(1);//Ver5.0.0-a19 //タイムアウトカウンタのインクリメント timeoutCounter++; //if(timeoutCounter*50>timeout*1000){ if(timeoutCounter > timeout*1000){ //タイムアウト this.Logger.Set(LOG_KIND.NOMAL,sock[CS.SERVER],3,string.Format("option TIMEOUT={0}sec",timeout)); break; } } else { timeoutCounter = 0;//タイムアウトカウンタのリセット } //******************************************************* // 受信処理 //******************************************************* if(buf[cs].Length==0){ //バッファが空の時だけ処理する if(!serverHeda && cs == CS.CLIENT && buf[CS.SERVER].Length == 0) {//次のリクエスト int x = 10; } if (cs == CS.SERVER && serverHeda) {// HTTPのヘッダ受信 while (life && sock[CS.SERVER].State == SOCKET_OBJ_STATE.CONNECT && sock[CS.CLIENT].State == SOCKET_OBJ_STATE.CONNECT && sock[CS.SERVER].Length() == 0) { Thread.Sleep(30); } //レスポンスの取得 if (!response.Recv(this.Logger, sock[CS.SERVER],timeout,ref life)) { this.Logger.Set(LOG_KIND.ERROR,sock[CS.SERVER],6,""); break; } if (oneCache != null) { if (response.Code != 200) {//200以外は、キャッシュ保存の対象にならないので無効化する //this.Logger.Set(LOG_KIND.DEBUG, 222, string.Format("response code [{0}]", response.Code)); oneCache = null; } } //ヘッダの受信 v2.1.6 すべてのレスポンスをConnectint: close にして、リクエストの抜けを排除する HTTP/1.1でも擬似的に使用できるようになる if (!header[cs].Recv(sock[cs], timeout, ref life)) { this.Logger.Set(LOG_KIND.ERROR,sock[CS.SERVER],7,""); break; } //Ver5.0.0-a22 //サーバからのヘッダにno-cacheが指定されている場合も、キャッシュ対象からはずす string headerStr = header[cs].ToString(); if(headerStr.ToLower().IndexOf("no-cache") >= 0) { this.Logger.Set(LOG_KIND.DETAIL,null,16,request.Uri); cache.Remove(request.HostName,request.Port,request.Uri);//存在する場合は、無効化する oneCache = null; } if (oneCache != null) oneCache.Add(header[CS.SERVER]); //サーバから受信したレスポンス及びヘッダをバッファに展開する buf[cs] = Bytes.Create(response.ToString(),"\r\n",header[cs].GetBytes()); serverHeda = false;//ヘッダ処理終了 string str = header[CS.SERVER].GetVal("Content-Length"); if (str != null) { contentLength = Convert.ToInt32(str); //Ver5.0.0-a19 //クライアントに送信するのは、本体+ヘッダとなるので contentLength += buf[cs].Length; } //コンテンツ制限の対象かどうかのフラグを設定する if(limitString!=null){//コンテンツ制限に文字列が設定されている場合 string contentType = header[CS.SERVER].GetVal("Content-Type"); if (contentType != null) { if (contentType.ToLower().IndexOf("text/h") == 0) { isText = true; } if (contentType.ToLower().IndexOf("text/t") == 0) { isText = true; } } } }else{ //処理すべきデータ数の取得 int len = sock[cs].Length(); byte[] b = sock[cs].Recv(len,timeout); if(b != null) { if(cs == CS.CLIENT) { string s = Encoding.ASCII.GetString(b); int x = 10; } buf[cs] = Bytes.Create(buf[cs],b); //logger.Set(LOG_KIND.DEBUG, 0, string.Format("cs={0} Recv()={1}", cs, b.Length)); if(cs == CS.SERVER) { if(oneCache != null) oneCache.Add(b);//キャッシュ //コンテンツ制限 if(isText) { if(charset == CHARSET.UNKNOWN) { string s = Encoding.ASCII.GetString(b); int index = s.ToLower().IndexOf("charset"); if(0 <= index) { s = s.Substring(index + 8); if(s.ToLower().IndexOf("x-sjis") >= 0) { charset = CHARSET.SJIS; } else if(s.ToLower().IndexOf("shift_jis") >= 0) { charset = CHARSET.SJIS; } else if(s.ToLower().IndexOf("x-euc-jp") >= 0) { charset = CHARSET.EUC; } else if(s.ToLower().IndexOf("euc-jp") >= 0) { charset = CHARSET.EUC; } else if(s.ToLower().IndexOf("utf-8") >= 0) { charset = CHARSET.UTF8; } else if(s.ToLower().IndexOf("utf-7") >= 0) { charset = CHARSET.UTF7; } else if(s.ToLower().IndexOf("iso-2022-jp") >= 0) { charset = CHARSET.JIS; } else { //int k = 0; } } } string str = ""; switch(charset) { case CHARSET.ASCII: str = Encoding.ASCII.GetString(b); break; case CHARSET.SJIS: str = Encoding.GetEncoding("shift-jis").GetString(b); break; case CHARSET.EUC: str = Encoding.GetEncoding("euc-jp").GetString(b); break; case CHARSET.JIS: str = Encoding.GetEncoding(50222).GetString(b); break; case CHARSET.UTF8: str = Encoding.UTF8.GetString(b); break; case CHARSET.UTF7: str = Encoding.UTF7.GetString(b); break; case CHARSET.UNKNOWN: str = Encoding.ASCII.GetString(b); break; } //コンテンツ制限 string hitStr = limitString.IsHit(str); if(hitStr != null) { //制限にヒットした場合 this.Logger.Set(LOG_KIND.NOMAL,sock[CS.SERVER],21,hitStr); break; } } } } } } //******************************************************* // 送信処理 //******************************************************* if (buf[cs].Length != 0) { //バッファにデータが入っている場合だけ処理する int c = 0; c = sock[Reverse(cs)].Send(buf[cs]); if (cs == CS.SERVER) {//サーバ側から受信したデータをクライアント側に送信した分だけカウントする if(contentLength!=0){ sendLength += c; //クライアント側への送信完了時に確認する //受信データサイズのすべてがクライアントへ送信完了したとき切断する if (contentLength <= sendLength) { cache.Add(oneCache); this.Logger.Set(LOG_KIND.DETAIL,sock[CS.SERVER],8,"compleate"); break; } } } //logger.Set(LOG_KIND.DEBUG, 0, string.Format("cs={0} Send()={1}", Reverse(cs), c)); if (c == buf[cs].Length) { buf[cs] = new byte[0]; //クライアント側への送信完了時に確認する //if(cs==CS.SERVER){ // //受信データサイズのすべてがクライアントへ送信完了したとき切断する // if (contentLength != 0 && contentLength <= sendLength) { // cache.Add(oneCache); // this.Logger.Set(LOG_KIND.DETAIL,sock[CS.SERVER],8,"compleate"); // break; // } //} } else { this.Logger.Set(LOG_KIND.ERROR,sock[CS.SERVER],9,string.Format("sock.Send() return {0}",c)); break; } } } }
protected abstract bool AddCache(OneCache oneCache);
//接続単位の処理 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(); } }
abstract protected bool AddCache(OneCache oneCache);//キャッシュ追加処理
// �L���b�V���lj� public bool Add(OneCache oneCache) { if (!_useCache) { return(false); } if (oneCache == null) { return(false); } //�T�C�Y��0�̂�̂́A�L���b�V���ΏۊO�Ƃ��� if (oneCache.Length <= 0) { return(false); } if (oneCache.Length > _maxSize * 1000) //�ő�T�C�Y�����f�[�^�̓L���b�V���̑ΏۊO�ƂȂ� { logger.Set(LogKind.Detail, null, 20, string.Format("{0}:{1}{2}", oneCache.HostName, oneCache.Port, oneCache.Uri)); return(false); } lock (this) { // �r������ //�������L���b�V���ւ̕ۑ� if (_memoryCache != null) { //�������L���b�V���Ɏ��܂邩�ǂ����̔��f while (_memoryCache.Length + oneCache.Length > _memorySize * 1024) { OneCache old = _memoryCache.Old();//��ԌÂ���̂�擾���� if (old == null) { return(false); } //��ԌÂ���̂�������L���b�V������폜���� _memoryCache.Remove(old.HostName, old.Port, old.Uri); //��ԌÂ���̂�f�B�X�N�L���b�V���ɕۑ����� if (_diskCache != null) { _diskCache.Add(old); } } if (_memoryCache.Add(oneCache)) { logger.Set(LogKind.Detail, null, 4, string.Format("{0}:{1}{2}", oneCache.HostName, oneCache.Port, oneCache.Uri)); return(true); } } //�f�B�X�N�L���b�V���ւ̕ۑ� if (_diskCache != null) { if (_diskCache.Add(oneCache)) { logger.Set(LogKind.Detail, null, 5, string.Format("{0}:{1}{2}", oneCache.HostName, oneCache.Port, oneCache.Uri)); return(true); } } } // �r������ logger.Set(LogKind.Detail, null, 18, string.Format("{0}:{1}{2}", oneCache.HostName, oneCache.Port, oneCache.Uri)); return(false); }