OSDN Git Service

ライセンス記述を追加する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / LogServer.cs
1 // Copyright (C) 2014 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
2 //\r
3 // This program is part of KancolleSniffer.\r
4 //\r
5 // KancolleSniffer is free software: you can redistribute it and/or modify\r
6 // it under the terms of the GNU General Public License as published by\r
7 // the Free Software Foundation, either version 3 of the License, or\r
8 // (at your option) any later version.\r
9 //\r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 //\r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 using System;\r
19 using System.IO;\r
20 using System.Linq;\r
21 using System.Net;\r
22 using System.Net.Sockets;\r
23 using System.Text;\r
24 using System.Threading;\r
25 using System.Web;\r
26 using System.Windows.Forms;\r
27 \r
28 namespace KancolleSniffer\r
29 {\r
30     public class LogServer\r
31     {\r
32         private readonly TcpListener _listener;\r
33         private readonly Thread _thread;\r
34         private readonly string _indexDir = Path.GetDirectoryName(Application.ExecutablePath);\r
35         private string _outputDir = Path.GetDirectoryName(Application.ExecutablePath);\r
36 \r
37         public string OutputDir\r
38         {\r
39             set { _outputDir = value; }\r
40         }\r
41 \r
42         public LogServer(int port)\r
43         {\r
44             _listener = new TcpListener(IPAddress.Loopback, port);\r
45             _thread = new Thread(Listen);\r
46         }\r
47 \r
48         public void Start()\r
49         {\r
50             _thread.Start();\r
51         }\r
52 \r
53         private void Listen()\r
54         {\r
55             try\r
56             {\r
57                 _listener.Start();\r
58                 while (true)\r
59                 {\r
60                     var data = new byte[4096];\r
61                     var client = _listener.AcceptSocket();\r
62                     try\r
63                     {\r
64                         if (client.Available == 0)\r
65                         {\r
66                             Thread.Sleep(500);\r
67                             if (client.Available == 0)\r
68                                 continue;\r
69                         }\r
70                         if (client.Receive(data) == 0)\r
71                             continue;\r
72                         var request = Encoding.UTF8.GetString(data).Split('\r')[0].Split(' ');\r
73                         if (request.Length != 3)\r
74                         {\r
75                             SendError(client, "400 Bad Request");\r
76                             continue;\r
77                         }\r
78                         if (!request[0].StartsWith("GET", StringComparison.OrdinalIgnoreCase))\r
79                         {\r
80                             SendError(client, "501 Not Implemented");\r
81                             continue;\r
82                         }\r
83                         var path = HttpUtility.UrlDecode(request[1].Split('?')[0]);\r
84                         if (path == null || !path.StartsWith("/"))\r
85                         {\r
86                             SendError(client, "400 Bad Request");\r
87                             continue;\r
88                         }\r
89 \r
90                         path = path == "/" ? "index.html" : path.Substring(1);\r
91                         var full = Path.Combine(_indexDir, path);\r
92                         var csv = Path.Combine(_outputDir, path);\r
93                         if (path.EndsWith(".html", StringComparison.OrdinalIgnoreCase) && File.Exists(full))\r
94                         {\r
95                             SendFile(client, full, "text/html");\r
96                             continue;\r
97                         }\r
98                         if (path.EndsWith(".csv", StringComparison.OrdinalIgnoreCase) && File.Exists(csv))\r
99                         {\r
100                             SendFile(client, csv, "text/csv; charset=Shift_JIS");\r
101                             continue;\r
102                         }\r
103                         if (path.EndsWith(".json", StringComparison.OrdinalIgnoreCase))\r
104                         {\r
105                             SendJsonData(client, csv);\r
106                             continue;\r
107                         }\r
108                         if (path.EndsWith(".js", StringComparison.OrdinalIgnoreCase) && File.Exists(full))\r
109                         {\r
110                             SendFile(client, full, "application/javascript");\r
111                             continue;\r
112                         }\r
113                         SendError(client, "404 Not Found");\r
114                     }\r
115                     catch (IOException)\r
116                     {\r
117                     }\r
118                     catch (InvalidOperationException)\r
119                     {\r
120                     }\r
121                     finally\r
122                     {\r
123                         client.Close();\r
124                     }\r
125                 }\r
126             }\r
127             catch (SocketException)\r
128             {\r
129             }\r
130             finally\r
131             {\r
132                 _listener.Stop();\r
133             }\r
134         }\r
135 \r
136         private void SendError(Socket client, string error)\r
137         {\r
138             using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII))\r
139             {\r
140                 writer.Write("HTTP/1.1 {0}\r\n", error);\r
141                 writer.Write("Server: KancolleSniffer\r\n");\r
142                 writer.Write("Date: {0:R}\r\n", DateTime.Now);\r
143                 writer.Write("Connection: close\r\n\r\n");\r
144                 writer.Write("<html><head><title>{0}</title></head>\r\n", error);\r
145                 writer.Write("<body><h4>{0}</h4></body></html>\r\n\r\n", error);\r
146                 writer.Flush();\r
147                 client.Send(((MemoryStream)writer.BaseStream).ToArray());\r
148             }\r
149         }\r
150 \r
151         private void SendJsonData(Socket client, string path)\r
152         {\r
153             var header = new StreamWriter(new MemoryStream(), Encoding.ASCII);\r
154             header.Write("HTTP/1.1 200 OK\r\n");\r
155             header.Write("Server: KancolleSniffer\r\n");\r
156             header.Write("Date: {0:R}\r\n", DateTime.Now);\r
157             header.Write("Content-Type: {0}\r\n", "application/json; charset=Shift_JIS");\r
158             header.Write("Connection: close\r\n\r\n");\r
159             header.Flush();\r
160             client.Send(((MemoryStream)header.BaseStream).ToArray());\r
161 \r
162             var csv = path.Replace(".json", ".csv");\r
163             var encoding = Encoding.GetEncoding("Shift_JIS");\r
164             client.Send(encoding.GetBytes("{ \"data\": [\n"));\r
165             if (File.Exists(csv))\r
166             {\r
167                 var delimiter = "";\r
168                 foreach (var line in File.ReadLines(csv, encoding).Skip(1))\r
169                 {\r
170                     client.Send(encoding.GetBytes(delimiter + "[\"" + string.Join("\",\"", line.Split(',')) + "\"]"));\r
171                     delimiter = ",\n";\r
172                 }\r
173             }\r
174             client.Send(encoding.GetBytes("]}\n"));\r
175         }\r
176 \r
177         private void SendFile(Socket client, string path, string mime)\r
178         {\r
179             using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII))\r
180             {\r
181                 writer.Write("HTTP/1.1 200 OK\r\n");\r
182                 writer.Write("Server: KancolleSniffer\r\n");\r
183                 writer.Write("Date: {0:R}\r\n", DateTime.Now);\r
184                 writer.Write("Content-Length: {0}\r\n", new FileInfo(path).Length);\r
185                 writer.Write("Content-Type: {0}\r\n", mime);\r
186                 writer.Write("Connection: close\r\n\r\n");\r
187                 writer.Flush();\r
188                 client.SendFile(path, ((MemoryStream)writer.BaseStream).ToArray(), null,\r
189                     TransmitFileOptions.UseDefaultWorkerThread);\r
190             }\r
191         }\r
192 \r
193         public void Stop()\r
194         {\r
195             _listener.Stop();\r
196             _thread.Join();\r
197         }\r
198     }\r
199 }