0
|
1 ???using System; |
|
2 using System.Collections.Generic; |
|
3 using System.IO; |
|
4 using System.Text; |
|
5 using System.Threading; |
|
6 |
|
7 namespace UCIS.Net.HTTP { |
|
8 public class HTTPServer : TCPServer.IModule { |
|
9 public Dictionary<string, HTTPContent> Content = new Dictionary<string, HTTPContent>(StringComparer.InvariantCultureIgnoreCase); |
|
10 public HTTPContent DefaultContent = null; |
|
11 |
|
12 public bool Accept(TCPStream Stream) { |
|
13 StreamReader StreamReader = new StreamReader(Stream, Encoding.ASCII); |
|
14 String Line = StreamReader.ReadLine(); |
|
15 String[] Request = Line.Split(' '); |
|
16 |
|
17 //Console.WriteLine("HTTP.Server.Accept Request: " + Line); |
|
18 |
|
19 if (Request == null || Request.Length < 2 || Request[0] != "GET" || Request[1][0] != '/') { |
|
20 //Console.WriteLine("HTTP.Server.Start Bad request"); |
|
21 SendError(Stream, 400); |
|
22 return true; |
|
23 } |
|
24 |
|
25 Request = Request[1].Split(new Char[] { '?' }, 2); |
|
26 HTTPContent content; |
|
27 if (Content.TryGetValue(Request[0], out content)) { |
|
28 } else if (DefaultContent != null) { |
|
29 content = DefaultContent; |
|
30 } else { |
|
31 SendError(Stream, 404); |
|
32 return true; |
|
33 } |
|
34 HTTPContext Context = new HTTPContext(); |
|
35 Context.Stream = Stream; |
|
36 Context.Request = new HTTPRequest(); |
|
37 Context.Request.Method = Method.GET; |
|
38 Context.Request.Path = Request[0]; |
|
39 if (Request.Length == 2) { |
|
40 Context.Request.Query = Request[1]; |
|
41 } else { |
|
42 Context.Request.Query = null; |
|
43 } |
|
44 HTTPContent.Result ServeResult = content.Serve(Context); |
|
45 |
|
46 if (ServeResult == HTTPContent.Result.OK_KEEPALIVE) { |
|
47 return false; |
|
48 } else if (!(ServeResult == HTTPContent.Result.OK_CLOSE)) { |
|
49 SendError(Stream, (int)ServeResult); |
|
50 } |
|
51 return true; |
|
52 } |
|
53 |
|
54 public static void SendError(Stream Stream, int ErrorCode) { |
|
55 string ErrorText = null; |
|
56 switch (ErrorCode) { |
|
57 case 400: |
|
58 ErrorText = "The request could not be understood by the server due to malformed syntax."; |
|
59 break; |
|
60 case 404: |
|
61 ErrorText = "The requested file can not be found."; |
|
62 break; |
|
63 default: |
|
64 ErrorText = "Unknown error code: " + ErrorCode.ToString() + "."; |
|
65 break; |
|
66 } |
|
67 SendHeader(Stream, ErrorCode, "text/plain", ErrorText.Length); |
|
68 WriteLine(Stream, ErrorText); |
|
69 Thread.Sleep(100); |
|
70 return; |
|
71 } |
|
72 |
|
73 public static void SendHeader(Stream Stream, int ResultCode, string ContentType) { |
|
74 SendHeader(Stream, ResultCode, ContentType, -1); |
|
75 } |
|
76 public static void SendHeader(Stream Stream, int ResultCode, string ContentType, int ContentLength) { |
|
77 //ResultCode = 200, ContentType = null, ContentLength = -1 |
|
78 string ResultString; |
|
79 switch (ResultCode) { |
|
80 case 200: ResultString = "OK"; break; |
|
81 case 400: ResultString = "Bad Request"; break; |
|
82 case 404: ResultString = "Not found"; break; |
|
83 default: ResultString = "Unknown"; break; |
|
84 } |
|
85 WriteLine(Stream, "HTTP/1.1 " + ResultCode.ToString() + " " + ResultString); |
|
86 WriteLine(Stream, "Expires: Mon, 26 Jul 1990 05:00:00 GMT"); |
|
87 WriteLine(Stream, "Cache-Control: no-store, no-cache, must-revalidate"); |
|
88 WriteLine(Stream, "Cache-Control: post-check=0, pre-check=0"); |
|
89 WriteLine(Stream, "Pragma: no-cache"); |
|
90 WriteLine(Stream, "Server: UCIS Simple Webserver"); |
|
91 WriteLine(Stream, "Connection: Close"); |
|
92 if ((ContentType != null)) WriteLine(Stream, "Content-Type: " + ContentType); |
|
93 if (ContentLength != -1) WriteLine(Stream, "Content-Length: " + ContentLength.ToString()); |
|
94 WriteLine(Stream, ""); |
|
95 } |
|
96 |
|
97 public static void WriteLine(Stream Stream, string Line) { |
|
98 byte[] Buffer = null; |
|
99 Buffer = Encoding.ASCII.GetBytes(Line); |
|
100 Stream.Write(Buffer, 0, Buffer.Length); |
|
101 Stream.WriteByte(13); |
|
102 Stream.WriteByte(10); |
|
103 } |
|
104 } |
|
105 |
|
106 public abstract class HTTPContent { |
|
107 public abstract Result Serve(HTTPContext Context); |
|
108 public enum Result : int { |
|
109 OK_CLOSE = -2, |
|
110 OK_KEEPALIVE = -1, |
|
111 ERR_NOTFOUND = 404 |
|
112 } |
|
113 } |
|
114 |
|
115 public class HTTPFileContent : HTTPContent { |
|
116 public string Filename { get; private set; } |
|
117 public string ContentType { get; private set; } |
|
118 |
|
119 public HTTPFileContent(string Filename) : this(Filename, "application/octet-stream") { } |
|
120 public HTTPFileContent(string Filename, string ContentType) { |
|
121 this.Filename = Filename; |
|
122 this.ContentType = ContentType; |
|
123 } |
|
124 |
|
125 public override Result Serve(HTTPContext Context) { |
|
126 if (!File.Exists(Filename)) return Result.ERR_NOTFOUND; |
|
127 |
|
128 using (FileStream FileStream = File.OpenRead(Filename)) { |
|
129 HTTPServer.SendHeader(Context.Stream, 200, ContentType, (int)FileStream.Length); |
|
130 byte[] Buffer = new byte[1025]; |
|
131 while (FileStream.CanRead) { |
|
132 int Length = FileStream.Read(Buffer, 0, Buffer.Length); |
|
133 if (Length <= 0) break; |
|
134 Context.Stream.Write(Buffer, 0, Length); |
|
135 } |
|
136 } |
|
137 return Result.OK_CLOSE; |
|
138 } |
|
139 } |
|
140 |
|
141 public class HTTPContext { |
|
142 public HTTPRequest Request { get; internal set; } |
|
143 public TCPStream Stream { get; internal set; } |
|
144 } |
|
145 |
|
146 public enum Method { |
|
147 GET = 0, |
|
148 HEAD = 1, |
|
149 POST = 2, |
|
150 PUT = 3 |
|
151 } |
|
152 |
|
153 public class HTTPRequest { |
|
154 public HTTP.Method Method { get; internal set; } |
|
155 public string Path { get; internal set; } |
|
156 public string Query { get; internal set; } |
|
157 } |
|
158 } |