Changeset 183 for SimpleHttpServer

Show
Ignore:
Timestamp:
07/25/07 03:49:16 (18 months ago)
Author:
mayuki
Message:
 
Files:
1 modified

Legend:

Unmodified
Added
Removed
  • SimpleHttpServer/SimpleHttpServer/SimpleHttpServer.cs

    r182 r183  
    1919        private SimpleHttpServer _server; 
    2020 
     21        private Response _response; 
    2122        private Dictionary<String, String> _headers; 
     23 
    2224        public String RequestUri; 
    2325        public String Method; 
     
    3840        public Dictionary<String, String> Headers 
    3941        { 
    40             get 
    41             { 
    42                 return _headers; 
    43             } 
     42            get { return _headers; } 
    4443        } 
    4544        public Stream Stream 
    4645        { 
    47             get 
    48             { 
    49                 return _stream; 
    50             } 
     46            get { return _stream; } 
     47        } 
     48        public Response Response 
     49        { 
     50            get { return _response; } 
    5151        } 
    5252 
     
    5656            _tcpClient = tcpClient; 
    5757            _server = server; 
    58  
    59             _headers = new Dictionary<string, string>(); 
    60  
    61             Contexts[Thread.CurrentThread.ManagedThreadId] = this; 
     58            _response = new Response(this); 
     59 
     60            _headers = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); 
     61             
     62            lock (Contexts) 
     63            { 
     64                Contexts[Thread.CurrentThread.ManagedThreadId] = this; 
     65            } 
    6266        } 
    6367 
     
    96100                    if (ctx.Headers.ContainsKey(headerField[0])) 
    97101                    { 
    98                         ctx.Headers[headerField[1]] += ", "+headerField[1]; 
     102                        ctx.Headers[headerField[1]] += ", " + headerField[1].Trim(); 
    99103                    } 
    100104                    else 
    101105                    { 
    102                         ctx.Headers[headerField[0]] = headerField[1]; 
     106                        ctx.Headers[headerField[0]] = headerField[1].Trim(); 
    103107                    } 
    104108                } 
     
    114118            Dispose(); 
    115119        } 
     120 
    116121 
    117122        #region IDisposable �����o 
     
    133138    } 
    134139 
     140    public class Response : IDisposable 
     141    { 
     142        private Context _ctx; 
     143        private HttpStatusCode _statusCode; 
     144        private Dictionary<String, String> _headers; 
     145        private String _contentType; 
     146        private String _charSet; 
     147        private HttpStream _httpStream; 
     148 
     149        public Response(Context ctx) 
     150        { 
     151            _ctx = ctx; 
     152            _contentType = "text/html"; 
     153            _charSet = "UTF-8"; 
     154            _statusCode = HttpStatusCode.OK; 
     155            _headers = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); 
     156            _httpStream = new HttpStream(_ctx.Stream, HttpStream_OnBeforeWrite); 
     157        } 
     158 
     159        private void HttpStream_OnBeforeWrite(Object sender, EventArgs e) 
     160        { 
     161            WriteHeaders(); 
     162        } 
     163 
     164        public Stream OutputStream 
     165        { 
     166            get { return _httpStream; } 
     167        } 
     168        public Dictionary<String, String> Headers 
     169        { 
     170            get { return _headers; } 
     171        } 
     172        public HttpStatusCode StatusCode 
     173        { 
     174            set { _statusCode = value; } 
     175            get { return _statusCode; } 
     176        } 
     177        public String ContentType 
     178        { 
     179            set { _contentType = value.Replace('\n', ' '); } 
     180            get { return _contentType; } 
     181        } 
     182        public String CharSet 
     183        { 
     184            set { _charSet = value.Replace('\n', ' '); } 
     185            get { return _charSet; } 
     186        } 
     187 
     188        private Boolean _alreadySentHeaders = false; 
     189        public void WriteHeaders() 
     190        { 
     191            if (_alreadySentHeaders) 
     192                return; 
     193 
     194            StreamWriter sw = new StreamWriter(_ctx.Stream); 
     195            sw.WriteLine("HTTP/1.0 {0} {1}", (Int32)_statusCode, _statusCode.ToString()); 
     196            foreach (KeyValuePair<String, String> pair in _headers) 
     197            { 
     198                sw.WriteLine("{0}: {1}", pair.Key, pair.Value); 
     199            } 
     200            if (!_headers.ContainsKey("Server")) 
     201            { 
     202                sw.WriteLine("Server: {0}", _ctx.Server.VersionString); 
     203            } 
     204            if (!_headers.ContainsKey("Content-Type")) 
     205            { 
     206                if (ContentType.StartsWith("text/")) 
     207                { 
     208                    sw.WriteLine("Conetent-Type: {0}; CharSet={1}", ContentType, CharSet); 
     209                } 
     210                else 
     211                { 
     212                    sw.WriteLine("Conetent-Type: {0}", ContentType); 
     213                } 
     214            } 
     215            sw.WriteLine("Connection: close"); 
     216            sw.WriteLine(); 
     217            sw.Flush(); 
     218 
     219            _alreadySentHeaders = true; 
     220        } 
     221 
     222        private Boolean _responseEnded = false; 
     223        public void End() 
     224        { 
     225            WriteHeaders(); 
     226            _ctx.Stream.Flush(); 
     227            _ctx.Stream.Close(); 
     228 
     229            _responseEnded = true; 
     230        } 
     231 
     232        #region IDisposable �����o 
     233 
     234        public void Dispose() 
     235        { 
     236            if (!_responseEnded) 
     237            { 
     238                End(); 
     239            } 
     240        } 
     241 
     242        #endregion 
     243    } 
     244 
     245    #region HTTP �T�[�o�N���X 
    135246    public delegate void RequestEventHandler(Context ctx); 
    136247    public class SimpleHttpServer 
     
    175286        protected void OnRequest(Context ctx) 
    176287        { 
    177             if (Request != null) 
    178             { 
    179                 Request(ctx); 
    180             } 
    181             else 
    182             { 
    183                 // not handled 
    184                 Trace.WriteLineIf(_loggingEnabled, "Request Not Handled", "error"); 
    185                 throw new HttpException(501, "Not Implemented"); 
     288            try 
     289            { 
     290                if (Request != null) 
     291                { 
     292                    Request(ctx); 
     293                    ctx.Response.End(); 
     294                } 
     295                else 
     296                { 
     297                    // not handled 
     298                    Trace.WriteLineIf(_loggingEnabled, "Request Not Handled", "error"); 
     299                    throw new HttpException(501, "Not Implemented"); 
     300                } 
     301            } 
     302            catch (Exception ex) 
     303            { 
     304                if (ex is HttpException || (ex is IOException && ex.InnerException is SocketException)) 
     305                    throw; 
     306                else  
     307                    throw new HttpException(500, "Internal Server Error", ex); 
    186308            } 
    187309        } 
     
    204326                    sw.WriteLine("Connection: close"); 
    205327                    sw.WriteLine(""); 
     328                    sw.WriteLine("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">"); 
    206329                    sw.WriteLine("<title>{0} {1}</title>", he.GetHttpCode(), he.Message); 
    207330                    sw.WriteLine("<h1>{0} {1}</h1>", he.GetHttpCode(), he.Message); 
    208331                    sw.WriteLine("<p>{0}</p>", he.GetHtmlErrorMessage()); 
    209                     sw.WriteLine("<h2>��</h2>"); 
    210                     sw.WriteLine("<pre>{0}</pre>", HttpUtility.HtmlEncode(he.ToString())); 
     332                    if (IPAddress.IsLoopback(((IPEndPoint)Context.Current.TcpClient.Client.RemoteEndPoint).Address)) 
     333                    { 
     334                        sw.WriteLine("<h2>��</h2>"); 
     335                        sw.WriteLine("<pre>{0}</pre>", HttpUtility.HtmlEncode(he.ToString())); 
     336                    } 
    211337                } 
    212338            } 
     
    235361                } 
    236362            } 
     363            catch (IOException) 
     364            { 
     365                // 
     366            } 
    237367            catch (Exception e) 
    238368            { 
    239                 Trace.WriteLineIf(_loggingEnabled, e.Message, "error"); 
    240                 sw.WriteLine("HTTP/1.0 500 Internal Server Error"); 
    241                 sw.WriteLine("Content-Type: text/html; charset=utf-8"); 
    242                 sw.WriteLine("Server: {0}", VersionString); 
    243                 sw.WriteLine("Connection: close"); 
    244                 sw.WriteLine(""); 
    245                 sw.WriteLine("<title>500 Internal Server Error</title>"); 
    246                 sw.WriteLine("<h1>500 Internal Server Error</h1>"); 
    247                 sw.WriteLine("<p>�T�[�o�ŏ�����s���ɃG���[���������܂����B</p>"); 
    248                 if (IPAddress.IsLoopback(((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address)) 
    249                 { 
    250                     sw.WriteLine("<h2>��</h2>"); 
    251                     sw.WriteLine("<pre>{0}</pre>", HttpUtility.HtmlEncode(e.ToString())); 
    252                 } 
    253                 sw.Flush(); 
     369                Trace.WriteLineIf(_loggingEnabled, e.ToString(), "error"); 
     370                if (stream.CanWrite) 
     371                { 
     372                    sw.WriteLine("HTTP/1.0 500 Internal Server Error"); 
     373                    sw.WriteLine("Content-Type: text/html; charset=utf-8"); 
     374                    sw.WriteLine("Server: {0}", VersionString); 
     375                    sw.WriteLine("Connection: close"); 
     376                    sw.WriteLine(""); 
     377                    sw.WriteLine("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">"); 
     378                    sw.WriteLine("<title>500 Internal Server Error</title>"); 
     379                    sw.WriteLine("<h1>500 Internal Server Error</h1>"); 
     380                    sw.WriteLine("<p>�T�[�o�ŏ�����s���ɃG���[���������܂����B</p>"); 
     381                    if (IPAddress.IsLoopback(((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address)) 
     382                    { 
     383                        sw.WriteLine("<h2>��</h2>"); 
     384                        sw.WriteLine("<pre>{0}</pre>", HttpUtility.HtmlEncode(e.ToString())); 
     385                    } 
     386                    sw.Flush(); 
     387                } 
    254388            } 
    255389            finally 
     
    268402        } 
    269403 
    270          
     404 
    271405        public void Start(IPEndPoint endPoint) 
    272406        { 
     
    275409            _tcpListener = new TcpListener(endPoint); 
    276410            _AcceptTcpClientCallback = new AsyncCallback(AcceptTcpClientCallback); 
    277              
     411 
    278412            _tcpListener.Start(); 
    279413            _tcpListener.BeginAcceptTcpClient(_AcceptTcpClientCallback, _tcpListener); 
    280414            _isRunning = true; 
    281              
     415 
    282416            //TcpClient tcpClient; 
    283417            //while ((tcpClient = _tcpListener.AcceptTcpClient()) != null) 
     
    297431        private void AcceptTcpClientCallback(IAsyncResult ar) 
    298432        { 
    299             //TcpListener tcpListener = ar.AsyncState as TcpListener; 
    300             TcpClient tcpClient = _tcpListener.EndAcceptTcpClient(ar); 
    301             _tcpListener.BeginAcceptTcpClient(_AcceptTcpClientCallback, _tcpListener); 
     433            if (!_isRunning) 
     434                return; 
    302435            try 
    303436            { 
    304                 HandleRequest(tcpClient); 
    305             } 
    306             catch (Exception e) 
    307             { 
    308                 Trace.WriteLineIf(_loggingEnabled, e.Message, "error"); 
     437                _tcpListener.BeginAcceptTcpClient(_AcceptTcpClientCallback, _tcpListener); 
     438                TcpClient tcpClient = _tcpListener.EndAcceptTcpClient(ar); 
     439 
     440                try 
     441                { 
     442                    HandleRequest(tcpClient); 
     443                } 
     444                catch (Exception e) 
     445                { 
     446                    Trace.WriteLineIf(_loggingEnabled, e.Message, "error"); 
     447                    if (!(e.InnerException is SocketException)) 
     448                    { 
     449                        throw; 
     450                    } 
     451                } 
     452            } 
     453            catch (SocketException se) 
     454            { 
     455                Trace.WriteLineIf(_loggingEnabled, se.Message, "error"); 
    309456            } 
    310457        } 
     
    312459        public void Stop() 
    313460        { 
     461            _isRunning = false; 
    314462            _tcpListener.Stop(); 
    315463        } 
     
    328476        } 
    329477    } 
     478    #endregion 
     479 
     480    #region HttpStream �N���X 
     481    public class HttpStream : Stream 
     482    { 
     483        private Stream _baseStream; 
     484        private Boolean _contentWritten = false; 
     485        public event EventHandler BeforeWrite; 
     486 
     487        public HttpStream(Stream stream, EventHandler beforeWriteHandler) 
     488        { 
     489            _baseStream = stream; 
     490            BeforeWrite += beforeWriteHandler; 
     491        } 
     492        public Stream BaseStream 
     493        { 
     494            get { return _baseStream; } 
     495        } 
     496        public override bool CanRead 
     497        { 
     498            get { return _baseStream.CanRead; } 
     499        } 
     500 
     501        public override bool CanSeek 
     502        { 
     503            get { return _baseStream.CanSeek; } 
     504        } 
     505 
     506        public override bool CanWrite 
     507        { 
     508            get { return _baseStream.CanWrite; } 
     509        } 
     510 
     511        public override void Flush() 
     512        { 
     513            _baseStream.Flush(); 
     514        } 
     515 
     516        public override long Length 
     517        { 
     518            get { return _baseStream.Length; } 
     519        } 
     520 
     521        public override long Position 
     522        { 
     523            get 
     524            { 
     525                return _baseStream.Position; 
     526            } 
     527            set 
     528            { 
     529                _baseStream.Position = value; 
     530            } 
     531        } 
     532 
     533        public override int Read(byte[] buffer, int offset, int count) 
     534        { 
     535            return _baseStream.Read(buffer, offset, count); 
     536        } 
     537 
     538        public override long Seek(long offset, SeekOrigin origin) 
     539        { 
     540            return _baseStream.Seek(offset, origin); 
     541        } 
     542 
     543        public override void SetLength(long value) 
     544        { 
     545            _baseStream.SetLength(value); 
     546        } 
     547 
     548        public override void Write(byte[] buffer, int offset, int count) 
     549        { 
     550            if (BeforeWrite != null && !_contentWritten) 
     551            { 
     552                _contentWritten = true; 
     553                BeforeWrite(this, EventArgs.Empty); 
     554            } 
     555 
     556            _baseStream.Write(buffer, offset, count); 
     557        } 
     558    } 
     559    #endregion 
    330560 
    331561    public class LoggingTraceListener : ConsoleTraceListener