void HttpProxy_AfterSessionComplete(Session session)
        {
            Utility.Configuration.ConfigurationData.ConfigConnection c = Utility.Configuration.Config.Connection;

            string baseurl = session.Request.PathAndQuery;

            //debug
            //Utility.Logger.Add( 1, baseurl );


            // request
            if (baseurl.Contains("/kcsapi/"))
            {
                string url  = baseurl;
                string body = session.Request.BodyAsString;

                //保存
                if (c.SaveReceivedData && c.SaveRequest)
                {
                    Task.Run((Action)(() => {
                        SaveRequest(url, body);
                    }));
                }


                UIControl.BeginInvoke((Action)(() => { LoadRequest(url, body); }));
            }



            //response
            //保存

            if (c.SaveReceivedData)
            {
                try {
                    if (!Directory.Exists(c.SaveDataPath))
                    {
                        Directory.CreateDirectory(c.SaveDataPath);
                    }


                    if (c.SaveResponse && baseurl.Contains("/kcsapi/"))
                    {
                        // 非同期で書き出し処理するので取っておく
                        // stringはイミュータブルなのでOK
                        string url  = baseurl;
                        string body = session.Response.BodyAsString;

                        Task.Run((Action)(() => {
                            SaveResponse(url, body);
                        }));
                    }
                    else if (baseurl.Contains("/kcs/") &&
                             ((c.SaveSWF && session.Response.MimeType == "application/x-shockwave-flash") || c.SaveOtherFile))
                    {
                        string saveDataPath = c.SaveDataPath;                         // スレッド間の競合を避けるため取っておく
                        string tpath        = string.Format("{0}\\{1}", saveDataPath, baseurl.Substring(baseurl.IndexOf("/kcs/") + 5).Replace("/", "\\"));
                        {
                            int index = tpath.IndexOf("?");
                            if (index != -1)
                            {
                                if (Utility.Configuration.Config.Connection.ApplyVersion)
                                {
                                    string over   = tpath.Substring(index + 1);
                                    int    vindex = over.LastIndexOf("VERSION=", StringComparison.CurrentCultureIgnoreCase);
                                    if (vindex != -1)
                                    {
                                        string version = over.Substring(vindex + 8).Replace('.', '_');
                                        tpath  = tpath.Insert(tpath.LastIndexOf('.', index), "_v" + version);
                                        index += version.Length + 2;
                                    }
                                }

                                tpath = tpath.Remove(index);
                            }
                        }

                        // 非同期で書き出し処理するので取っておく
                        byte[] responseCopy = new byte[session.Response.Body.Length];
                        Array.Copy(session.Response.Body, responseCopy, session.Response.Body.Length);

                        Task.Run((Action)(() => {
                            try {
                                lock (this) {
                                    // 同時に書き込みが走るとアレなのでロックしておく

                                    Directory.CreateDirectory(Path.GetDirectoryName(tpath));

                                    //System.Diagnostics.Debug.WriteLine( oSession.fullUrl + " => " + tpath );
                                    using (var sw = new System.IO.BinaryWriter(System.IO.File.OpenWrite(tpath))) {
                                        sw.Write(responseCopy);
                                    }
                                }

                                Utility.Logger.Add(1, string.Format("通信からファイル {0} を保存しました。", tpath.Remove(0, saveDataPath.Length + 1)));
                            } catch (IOException ex) {                                  //ファイルがロックされている; 頻繁に出るのでエラーレポートを残さない
                                Utility.Logger.Add(3, "通信内容の保存に失敗しました。 " + ex.Message);
                            }
                        }));
                    }
                } catch (Exception ex) {
                    Utility.ErrorReporter.SendErrorReport(ex, "通信内容の保存に失敗しました。");
                }
            }



            if (baseurl.Contains("/kcsapi/") && session.Response.MimeType == "text/plain")
            {
                // 非同期でGUIスレッドに渡すので取っておく
                // stringはイミュータブルなのでOK
                string url  = baseurl;
                string body = session.Response.BodyAsString;
                UIControl.BeginInvoke((Action)(() => { LoadResponse(url, body); }));

                // kancolle-db.netに送信する
                if (Utility.Configuration.Config.Connection.SendDataToKancolleDB)
                {
                    Task.Run((Action)(() => DBSender.ExecuteSession(session)));
                }
            }


            if (ServerAddress == null && baseurl.Contains("/kcsapi/"))
            {
                ServerAddress = session.Request.Headers.Host;
            }
        }
        private void ProxyServer_BeforeResponse(object sender, Titanium.Web.Proxy.EventArguments.SessionEventArgs e)
        {
            Utility.Configuration.ConfigurationData.ConfigConnection c = Utility.Configuration.Config.Connection;

            string path = e.ProxySession.Request.RequestUri.PathAndQuery;

            if (path.Contains(".mp3"))
            {
                var   cacheControlHeader = e.ProxySession.Response.ResponseHeaders.Where(h => h.Name == "Cache-Control").First();
                var   lastModifiedHeader = e.ProxySession.Response.ResponseHeaders.Where(h => h.Name == "Last-Modified").First();
                Regex re    = new Regex("([0-9]+)");
                var   match = re.Match(cacheControlHeader.Value);
                if (!string.IsNullOrWhiteSpace(match.Value))
                {
                    int seconds = int.Parse(match.Value);
                    cacheControl.Add(path, new Tuple <DateTime, DateTime>(DateTime.Parse(lastModifiedHeader.Value), DateTime.Now.AddSeconds(seconds)));
                }
                cacheControlHeader.Value = "public, no-cache, max-age=0";
            }
            if (c.SaveReceivedData)
            {
                try
                {
                    if (!Directory.Exists(c.SaveDataPath))
                    {
                        Directory.CreateDirectory(c.SaveDataPath);
                    }


                    if (c.SaveResponse && path.Contains("/kcsapi/"))
                    {
                        // 非同期で書き出し処理するので取っておく
                        // stringはイミュータブルなのでOK
                        string body = e.GetResponseBodyAsString();

                        Task.Run((Action)(() => {
                            SaveResponse(path, body);
                        }));
                    }
                    else if (path.Contains("/kcs/") &&
                             ((c.SaveSWF && e.ResponseContentType == "application/x-shockwave-flash") || c.SaveOtherFile))
                    {
                        string saveDataPath = c.SaveDataPath; // スレッド間の競合を避けるため取っておく
                        string tpath        = string.Format("{0}\\{1}", saveDataPath, path.Substring(path.IndexOf("/kcs/") + 5).Replace("/", "\\"));
                        {
                            int index = tpath.IndexOf("?");
                            if (index != -1)
                            {
                                if (Utility.Configuration.Config.Connection.ApplyVersion)
                                {
                                    string over   = tpath.Substring(index + 1);
                                    int    vindex = over.LastIndexOf("VERSION=", StringComparison.CurrentCultureIgnoreCase);
                                    if (vindex != -1)
                                    {
                                        string version = over.Substring(vindex + 8).Replace('.', '_');
                                        tpath  = tpath.Insert(tpath.LastIndexOf('.', index), "_v" + version);
                                        index += version.Length + 2;
                                    }
                                }

                                tpath = tpath.Remove(index);
                            }
                        }

                        // 非同期で書き出し処理するので取っておく
                        byte[] responseCopy = e.GetResponseBody();

                        Task.Run((Action)(() => {
                            try
                            {
                                lock (this)
                                {
                                    // 同時に書き込みが走るとアレなのでロックしておく

                                    Directory.CreateDirectory(Path.GetDirectoryName(tpath));

                                    //System.Diagnostics.Debug.WriteLine( oSession.fullUrl + " => " + tpath );
                                    using (var sw = new System.IO.BinaryWriter(System.IO.File.OpenWrite(tpath)))
                                    {
                                        sw.Write(responseCopy);
                                    }
                                }

                                Utility.Logger.Add(1, string.Format(LoggerRes.SavedAPI, tpath.Remove(0, saveDataPath.Length + 1)));
                            }
                            catch (IOException ex)
                            {   //ファイルがロックされている; 頻繁に出るのでエラーレポートを残さない
                                Utility.Logger.Add(3, LoggerRes.FailedSaveAPI + ex.Message);
                            }
                        }));
                    }
                }
                catch (Exception ex)
                {
                    Utility.ErrorReporter.SendErrorReport(ex, LoggerRes.FailedSaveAPI);
                }
            }



            if (path.Contains("/kcsapi/") && e.ResponseContentType == "text/plain")
            {
                // 非同期でGUIスレッドに渡すので取っておく
                // stringはイミュータブルなのでOK
                string body = e.GetResponseBodyAsString();
                UIControl.BeginInvoke((Action)(() => { LoadResponse(path, body); }));

                // kancolle-db.netに送信する
                if (Utility.Configuration.Config.Connection.SendDataToKancolleDB)
                {
                    Task.Run((Action)(() => DBSender.ExecuteSession(e)));
                }
            }

            if (ServerAddress == null && path.Contains("/kcsapi/"))
            {
                ServerAddress = e.ProxySession.Request.RequestUri.Host;
            }
        }