Example #1
0
 /// <summary>
 ///   静的ページのハンドラを登録する。
 /// </summary>
 /// <param name="path">URL内のパス名(ディレクトリ名)。/から始まる。</param>
 /// <param name="page">静的ページを返すハンドラ。</param>
 /// <example>
 ///   \code
 ///   HttpServer sv = new HttpServer("MyServerName", "*", "80");
 ///   sv.AddStaticPage("/hoge", new HttpStaticPage("foo"));
 ///   \endcode
 ///   これで、"http://MyServerName/hoge/abcd.html"にアクセスすると"foo/abcd.html"が返されるようになる。
 /// </example>
 public void AddStaticPage(string path, HttpStaticPage page)
 {
     m_staticpagelist[path] = page;
 }
Example #2
0
        private void OnConnect(WorkerContext wc)
        {
            wc.Timer.Reset();
            wc.Timer.Start();
            wc.Count++;
            HttpListenerContext context = wc.Context;
            string requestmemo          = string.Format("{0} {1} from {2}",
                                                        context.Request.HttpMethod,
                                                        context.Request.RawUrl,
                                                        context.Request.RemoteEndPoint);

            LOG_DEBUG("Requested " + requestmemo);

            // 古いセッションを破棄
            PurgeSession();

            context.Response.KeepAlive = false;
            context.Response.AddHeader("Server", "MACS HttpServer");
            string path   = context.Request.Url.AbsolutePath;
            int    status = 0;

            try {
                // デフォルトページ?
                if ((path == "/") && (m_defaultpage != null))
                {
                    using (HttpPage page = new HttpPage()){
                        page.SetLogger(this.Logger);
                        page.SetServerContext(this, context, path);
                        page.Redirect(m_defaultpage);
                        status = 200;
                    }
                }

                // 静的ページを探す
                if (status == 0)
                {
                    foreach (KeyValuePair <string, HttpStaticPage> kv in m_staticpagelist)
                    {
                        if (path.StartsWith(kv.Key) && (path.Length > kv.Key.Length) && (path[kv.Key.Length] == '/'))
                        {
                            if (context.Request.HttpMethod == "GET")
                            {
                                lock (kv.Value){
                                    kv.Value.SetLogger(this.Logger);
                                    kv.Value.SetServerContext(this, context, path);
                                    kv.Value.PageLoad(path.Substring(kv.Key.Length));
                                }
                                status = 200;
                            }
                            else
                            {
                                status = 405;
                            }
                            break;
                        }
                    }
                }

                if (status == 0)
                {
                    // アプリケーションページを探す
                    foreach (KeyValuePair <string, Type> kv in m_pagelist)
                    {
                        if (path.StartsWith(kv.Key) && ((path.Length == kv.Key.Length) || (path[kv.Key.Length] == '/')))
                        {
                            // 動的ページにマッチした
                            Type pageClass = kv.Value;
                            // 動的ページは同時にMaxActivePages個しかレンダリングしない
                            lock (m_activepages_mutex) {
                                if (++m_activepages > m_maxactivepages)
                                {
                                    // オーバーした時は強制的にEmergencyPageでレンダリングする
                                    LOG_NOTICE("Number of active pages exceeds MaxActivePages({0}), use {1}", m_maxactivepages, m_emergencypage.Name);
                                    pageClass = m_emergencypage;
                                }
                            }
                            int timeout = 0; // ページレンダリングタイムアウト
                            try {
                                if ((context.Request.HttpMethod == "GET") || (context.Request.HttpMethod == "POST"))
                                {
                                    // セッション変数をクッキー管理する。
                                    Cookie           sessid = context.Request.Cookies[m_servername + "-SID"];
                                    ObjectDictionary sess;
                                    lock (m_sessiondict){
                                        if ((sessid != null) && m_sessiondict.ContainsKey(sessid.Value))
                                        {
                                            sess = m_sessiondict[sessid.Value];
                                        }
                                        else
                                        {
                                            sessid = new Cookie(m_servername + "-SID", m_rand.Next(9999999).ToString() + m_rand.Next(9999999).ToString());
                                            sess   = new ObjectDictionary();
                                            m_sessiondict[sessid.Value] = sess;
                                        }
                                        m_sessiontime[sessid.Value] = DateTime.Now;
                                    }
                                    sessid.Version = 1;
                                    sessid.Path    = "/";
                                    if (UseCookieExpires && (SessionTimeout > 0))
                                    {
                                        sessid.Expires = DateTime.Now.AddSeconds(SessionTimeout);
                                        //context.Response.AppendCookie(sessid);
                                        // なぜか正しいSet-Cookieヘッダを生成してくれないので、自力でヘッダを作る。
                                        context.Response.AppendHeader("Set-Cookie", string.Format("{0}={1}; expires={2}; path={3}", sessid.Name, sessid.Value, sessid.Expires.ToString("r"), sessid.Path));
                                    }
                                    else
                                    {
                                        context.Response.AppendHeader("Set-Cookie", string.Format("{0}={1}; path={2}", sessid.Name, sessid.Value, sessid.Path));
                                    }

                                    // ページレンダラの呼び出し
                                    using (HttpPage page = (HttpPage)(pageClass.GetConstructor(Type.EmptyTypes).Invoke(null))){
                                        page.SetLogger(this.Logger);
                                        page.SetServerContext(this, context, kv.Key.Substring(1));
                                        // ページレンダリングタイムアウトの設定
                                        timeout = page.Timeout;
                                        if (timeout < 0)
                                        {
                                            timeout = DefaultTimeout;
                                        }
                                        if (timeout > 0)
                                        {
                                            NThread.Watchdog(timeout, NThread.WatchdogMode.Abort);
                                        }
                                        // セッション変数アクセスの排他を行なうと、同一端末からのアクセスの処理はシリアライズされる。
                                        if (page.UseSession)
                                        {
                                            lock (sess) {
                                                page.SetSession(sess, m_appl);
                                                page.PageLoad(path.Substring(kv.Key.Length));
                                            }
                                        }
                                        else
                                        {
                                            page.SetSession(sess, m_appl);
                                            page.PageLoad(path.Substring(kv.Key.Length));
                                        }
                                        status = 200;
                                    }
                                }
                                else
                                {
                                    status = 405;
                                }
                                break;
                            } finally {
                                if (timeout > 0)
                                {
                                    NThread.SuspendWatchdog();
                                }
                                lock (m_activepages_mutex) {
                                    if (m_activepages > 0)
                                    {
                                        m_activepages--;
                                    }
                                }
                            }
                        }
                    }
                }

                if (status == 0)
                {
                    // ルート静的ページを探す
                    if (m_staticpagelist.ContainsKey("/"))
                    {
                        HttpStaticPage pg = m_staticpagelist["/"];
                        if (context.Request.HttpMethod == "GET")
                        {
                            lock (pg){
                                pg.SetLogger(this.Logger);
                                pg.SetServerContext(this, context, path);
                                pg.PageLoad(path);
                            }
                            status = 200;
                        }
                        else
                        {
                            status = 405;
                        }
                    }
                }

                if (status == 0)
                {
                    // 該当ページが無い。
                    status = 404;
                }
            } catch (PageRedirectException e) {
                using (HttpPage page = new HttpPage()){
                    page.SetLogger(this.Logger);
                    page.SetServerContext(this, context, path);
                    page.Redirect(e.m_pagename);
                    status = 200;
                }
            } catch (HttpListenerException) {
                // コンテンツ送信失敗。きっとクライアント側が切ったのだろう。
                status = 200; // とりあえず、こちら側の処理は成功したことにする。
                LOG_ERR("Client closed socket while sending contents.");
            } catch (IOException e) {
                // コンテンツ送信中にソケットが切れた(?)
                status = 200; // とりあえず、こちら側の処理は成功したことにする。
                LOG_DEBUG("IOError while sending contents: " + e.Message);
            } catch (ThreadInterruptedException) {
                using (HttpPage page = new HttpPage()){
                    page.SetLogger(this.Logger);
                    page.SetServerContext(this, context, "error");
                    page.PageLoad("503");
                }
            } catch (ThreadAbortException ex) {
                bool isTimeout = (ex.ExceptionState != null) && (ex.ExceptionState is TimeoutException);
                if (isTimeout)
                {
                    LOG_ERR("{0} is aborted due to timeout", path);
                }
                else
                {
                    LOG_ERR("{0} is aborted", path);
                }
                LOG_EXCEPTION(ex);
                using (HttpPage page = new HttpPage()){
                    page.SetLogger(this.Logger);
                    page.SetServerContext(this, context, "error");
                    page.PageLoad(isTimeout?"408":"500");
                }
            } catch (Exception e) {
                LOG_CRIT(String.Format("{0}: {1} in {2}", e.GetType().Name, e.Message, e.TargetSite));
                LOG_EXCEPTION(e);
                if (ShowStackTrace)
                {
                    using (HttpStackTracePage page = new HttpStackTracePage(e)) {
                        try {
                            page.SetLogger(this.Logger);
                            page.SetServerContext(this, context, "StackTrace");
                            page.PageLoad(e.Message);
                        } catch (Exception) {
                            // I can't do any more.
                        }
                    }
                    status = 200;
                }
                else
                {
                    status = 500;
                }
            }
            if (status != 200)
            {
                LOG_WARNING(string.Format("Failed to dispatch {0} (code={1})", requestmemo, status));
                using (HttpPage page = new HttpPage()){
                    try {
                        page.SetLogger(this.Logger);
                        page.SetServerContext(this, context, "error");
                        page.PageLoad(status.ToString());
                    } catch (Exception) {
                        // contextがもう使えない状態にあるらしい。きっとクライアント側が切ったのだろう。
                        // 無視。
                    }
                }
            }
            //context.Response.OutputStream.Close(); // 念のため。
            // 上の行は、なぜかDebian版monoでは戻ってこない。
            try {
                context.Response.Close();
            } catch (Exception) {
                // Close失敗は無視する。
            }

            wc.Timer.Stop();
            long elapsed = wc.Timer.ElapsedMilliseconds;

            if (elapsed > wc.MaxElapsed)
            {
                wc.MaxElapsed = elapsed;
            }
            wc.TotalElapsed += elapsed;
            LOG_DEBUG(string.Format("Finished {0} ({1}msec)", requestmemo, elapsed));
        }
Example #3
0
 /// <summary>
 ///   静的ページのハンドラを登録する。
 /// </summary>
 /// <param name="path">URL内のパス名(ディレクトリ名)。/から始まる。</param>
 /// <param name="dir">静的ページが入っているディレクトリ名。</param>
 /// <example>
 ///   \code
 ///   HttpServer sv = new HttpServer("MyServerName", "*", "80");
 ///   sv.AddStaticPage("/hoge", "foo");
 ///   \endcode
 ///   これで、"http://MyServerName/hoge/abcd.html"にアクセスすると"foo/abcd.html"が返されるようになる。
 /// </example>
 public void AddStaticPage(string path, string dir)
 {
     m_staticpagelist[path] = new HttpStaticPage(dir);
 }