11using System ;
22using System . IO ;
33using System . Net ;
4+ using System . Text ;
45using System . Text . RegularExpressions ;
56
67class SimpleHttpServer
@@ -18,6 +19,7 @@ class SimpleHttpServer
1819{ ".svg" , "image/svg+xml" } ,
1920{ ".json" , "application/json" } ,
2021{ ".zip" , "application/zip" } ,
22+ { ".pdf" , "application/pdf" } ,
2123} ;
2224static string port = "8000" ;
2325static string host = "+" ;
@@ -33,7 +35,8 @@ static void Main(string[] args)
3335}
3436try
3537{
36- string prefixPath = Regex . Replace ( prefix , @"https?://[^/]*" , "" ) ;
38+ string prefixPath = WebUtility . UrlDecode (
39+ Regex . Replace ( prefix , @"https?://[^/]*" , "" ) ) ;
3740using ( var listener = new HttpListener ( ) )
3841{
3942listener . Prefixes . Add ( prefix ) ;
@@ -45,36 +48,46 @@ static void Main(string[] args)
4548var request = context . Request ;
4649using ( var response = context . Response )
4750{
48- string rawUrl = request . RawUrl ;
49- if ( 0 < prefixPath . Length && rawUrl . StartsWith ( prefixPath ) )
51+ string rawPath = WebUtility . UrlDecode (
52+ Regex . Replace ( request . RawUrl , "[?;].*$" , "" ) ) ;
53+ if ( 0 < prefixPath . Length && rawPath . StartsWith ( prefixPath ) )
5054{
51- rawUrl = rawUrl . Substring ( prefixPath . Length - 1 ) ;
55+ rawPath = rawPath . Substring ( prefixPath . Length - 1 ) ;
5256}
53- string path = ( root + Regex . Replace ( rawUrl , "[?;].*$" , "" ) )
54- . Replace ( "//" , "/" ) . Replace ( "/" , @"\" ) ;
55- if ( path . EndsWith ( @"\" ) )
57+ string path = ( root + rawPath ) . Replace ( "//" , "/" ) . Replace ( "/" , @"\" ) ;
58+ if ( path . EndsWith ( @"\" ) && File . Exists ( path + "index.html" ) )
5659{
5760path += "index.html" ;
5861}
5962byte [ ] content = null ;
6063if ( ! request . HttpMethod . Equals ( "GET" ) )
6164{
62- response . StatusCode = ( int ) HttpStatusCode . NotImplemented ;
65+ response . StatusCode = ( int ) HttpStatusCode . NotImplemented ; // 501
6366}
6467else if ( path . Contains ( @"\..\" ) || path . EndsWith ( @"\.." ) )
6568{
66- response . StatusCode = ( int ) HttpStatusCode . BadRequest ;
69+ response . StatusCode = ( int ) HttpStatusCode . BadRequest ; // 400
70+ }
71+ else if ( path . EndsWith ( @"\" )
72+ && Directory . Exists ( path . Substring ( 0 , path . Length - 1 ) ) )
73+ {
74+ string indexPage = CreateIndexPage ( path , rawPath ) ;
75+ content = Encoding . UTF8 . GetBytes ( indexPage ) ;
76+ response . ContentType = "text/html" ;
77+ response . OutputStream . Write ( content , 0 , content . Length ) ;
6778}
6879else if ( Directory . Exists ( path ) )
6980{
7081var hosts = request . Headers . GetValues ( "Host" ) ;
7182var thisHost = ( hosts != null ) ? hosts [ 0 ] : request . UserHostAddress ;
72- response . Headers . Set ( "Location" , string . Format ( "http://{0}{1}/" , thisHost , request . RawUrl ) ) ;
73- response . StatusCode = ( int ) HttpStatusCode . MovedPermanently ;
83+ response . Headers . Set (
84+ "Location" ,
85+ string . Format ( "http://{0}{1}/" , thisHost , request . RawUrl ) ) ;
86+ response . StatusCode = ( int ) HttpStatusCode . MovedPermanently ; // 301
7487}
7588else if ( ! File . Exists ( path ) )
7689{
77- response . StatusCode = ( int ) HttpStatusCode . NotFound ;
90+ response . StatusCode = ( int ) HttpStatusCode . NotFound ; // 404
7891}
7992else
8093{
@@ -87,10 +100,11 @@ static void Main(string[] args)
87100catch ( Exception e )
88101{
89102Console . Error . WriteLine ( e ) ;
90- response . StatusCode = ( int ) HttpStatusCode . Forbidden ;
103+ response . StatusCode = ( int ) HttpStatusCode . Forbidden ; // 403
91104}
92105}
93- Console . WriteLine ( string . Format ( "{0} - - [{1}]\" {2} {3} HTTP/{4}\" {5} {6}" ,
106+ Console . WriteLine (
107+ string . Format ( "{0} - - [{1}]\" {2} {3} HTTP/{4}\" {5} {6}" ,
94108request . RemoteEndPoint . Address ,
95109DateTime . Now . ToString ( "yyyy-MM-dd HH:mm:ss K" ) ,
96110request . HttpMethod , request . RawUrl , request . ProtocolVersion ,
@@ -118,9 +132,9 @@ static void ParseOptions(string[] args)
118132else
119133{
120134Console . Error . WriteLine (
121- "usage: SimpleHttpServer [-p PORT ] [-b ADDR ] [-r DIR ]\n " +
122- " or SimpleHttpServer [-t ] [-r DIR ]" +
123- " or SimpleHttpServer [-P PREFIX ] [-r DIR ]" ) ;
135+ "usage: SimpleHttpServer [-r DIR ] [-p PORT ] [-b ADDR ]\n " +
136+ " or SimpleHttpServer [-r DIR ] [-t ]" +
137+ " or SimpleHttpServer [-r DIR ] [-P PREFIX ]" ) ;
124138Environment . Exit ( 0 ) ;
125139}
126140}
@@ -137,4 +151,28 @@ static string ContentType(string path)
137151}
138152return "application/octet-stream" ;
139153}
154+
155+ static string CreateIndexPage ( string path , string urlPath )
156+ {
157+ string [ ] files = Directory . GetFileSystemEntries ( path ) ;
158+ string indexPage = string . Format (
159+ "<html><head><meta charset=\" UTF-8\" /></head>\n " +
160+ "<body><h1>List of {0}</h1><ul>\n " ,
161+ WebUtility . HtmlEncode ( urlPath ) ) ;
162+ if ( urlPath != "/" )
163+ {
164+ indexPage += "<li><a href=\" ..\" >..</a></li>\n " ;
165+ }
166+ foreach ( string file in files ) {
167+ string basename = Path . GetFileName ( file ) ;
168+ string link = string . Format (
169+ "<li><a href=\" {0}{2}\" >{1}{2}</a></li>\n " ,
170+ WebUtility . UrlEncode ( basename ) ,
171+ WebUtility . HtmlEncode ( basename ) ,
172+ Directory . Exists ( file ) ? "/" : "" ) ;
173+ indexPage += link ;
174+ }
175+ indexPage += "</ul></body></html>\n " ;
176+ return indexPage ;
177+ }
140178}