1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>
\r
3 // Licensed under the Apache License, Version 2.0 (the "License");
\r
4 // you may not use this file except in compliance with the License.
\r
5 // You may obtain a copy of the License at
\r
7 // http://www.apache.org/licenses/LICENSE-2.0
\r
9 // Unless required by applicable law or agreed to in writing, software
\r
10 // distributed under the License is distributed on an "AS IS" BASIS,
\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
12 // See the License for the specific language governing permissions and
\r
13 // limitations under the License.
\r
18 using System.Net.Sockets;
\r
20 using KancolleSniffer.Log;
\r
21 using KancolleSniffer.Util;
\r
23 namespace KancolleSniffer.Net
\r
25 public class LogServer
\r
27 private static readonly string IndexDir = AppDomain.CurrentDomain.BaseDirectory;
\r
28 private static string _outputDir = AppDomain.CurrentDomain.BaseDirectory;
\r
30 public static string OutputDir
\r
32 set => _outputDir = value;
\r
35 public static LogProcessor LogProcessor { private get; set; }
\r
37 public static void Process(Socket client, string requestLine)
\r
39 var from = DateTime.MinValue;
\r
40 var to = DateTime.MaxValue;
\r
41 var timestamp = false;
\r
43 var request = requestLine.Split(' ');
\r
44 if (request.Length != 3)
\r
46 SendError(client, "400 Bad Request");
\r
49 if (!request[0].StartsWith("GET", StringComparison.OrdinalIgnoreCase))
\r
51 SendError(client, "501 Not Implemented");
\r
54 var tmp = request[1].Split('?');
\r
55 var path = HttpUtility.UrlDecode(tmp[0]);
\r
56 if (path == null || !path.StartsWith("/"))
\r
58 SendError(client, "400 Bad Request");
\r
61 if (tmp.Length == 2)
\r
63 var query = HttpUtility.ParseQueryString(tmp[1]);
\r
64 if (query["from"] != null)
\r
66 double.TryParse(query["from"], out var tick);
\r
67 from = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000);
\r
69 if (query["to"] != null)
\r
71 double.TryParse(query["to"], out var tick);
\r
72 to = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000);
\r
74 if (query["number"] != null)
\r
75 timestamp = query["number"] == "true";
\r
78 path = path == "/" ? "index.html" : path.Substring(1);
\r
79 var full = Path.Combine(IndexDir, path);
\r
80 var csv = Path.Combine(_outputDir, path);
\r
81 if (path.EndsWith(".html", StringComparison.OrdinalIgnoreCase) && File.Exists(full))
\r
83 SendFile(client, full, "text/html");
\r
86 if (path.EndsWith(".csv", StringComparison.OrdinalIgnoreCase) && File.Exists(csv))
\r
88 SendFile(client, csv, "text/csv; charset=Shift_JIS");
\r
91 if (path.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
\r
93 SendJsonData(client, csv, from, to, timestamp);
\r
96 if (path.EndsWith(".js", StringComparison.OrdinalIgnoreCase) && File.Exists(full))
\r
98 SendFile(client, full, "application/javascript");
\r
101 if (path.EndsWith(".pac"))
\r
103 SendProxyPac(client, HttpProxy.LocalPort);
\r
106 if (File.Exists(full))
\r
108 SendFile(client, full, "text/plain");
\r
111 SendError(client, "404 Not Found");
\r
114 private static void SendError(Socket client, string error)
\r
116 using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII))
\r
118 writer.Write("HTTP/1.1 {0}\r\n", error);
\r
119 writer.Write("Server: KancolleSniffer\r\n");
\r
120 writer.Write("Date: {0:R}\r\n", DateTime.Now);
\r
121 writer.Write("Connection: close\r\n\r\n");
\r
122 writer.Write("<html><head><title>{0}</title></head>\r\n", error);
\r
123 writer.Write("<body><h4>{0}</h4></body></html>\r\n\r\n", error);
\r
125 client.Send(((MemoryStream)writer.BaseStream).ToArray());
\r
129 private static void SendJsonData(Socket client, string path, DateTime from, DateTime to, bool number)
\r
131 using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))
\r
133 header.Write("HTTP/1.1 200 OK\r\n");
\r
134 header.Write("Server: KancolleSniffer\r\n");
\r
135 header.Write("Date: {0:R}\r\n", DateTime.Now);
\r
136 header.Write("Content-Type: {0}\r\n", "application/json; charset=Shift_JIS");
\r
137 header.Write("Connection: close\r\n\r\n");
\r
139 client.Send(((MemoryStream)header.BaseStream).ToArray());
\r
141 var csv = path.Replace(".json", ".csv");
\r
142 if (!File.Exists(csv))
\r
144 var encoding = Encoding.GetEncoding("Shift_JIS");
\r
145 client.Send(encoding.GetBytes("{ \"data\": [\n"));
\r
148 foreach (var record in LogProcessor.Process(File.ReadLines(csv, encoding).Skip(1), csv, from, to, number))
\r
149 client.Send(encoding.GetBytes(record));
\r
153 client.Send(encoding.GetBytes("]}\n"));
\r
157 private static void SendFile(Socket client, string path, string mime)
\r
159 using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))
\r
161 header.Write("HTTP/1.1 200 OK\r\n");
\r
162 header.Write("Server: KancolleSniffer\r\n");
\r
163 header.Write("Date: {0:R}\r\n", DateTime.Now);
\r
164 header.Write("Content-Length: {0}\r\n", new FileInfo(path).Length);
\r
165 header.Write("Content-Type: {0}\r\n", mime);
\r
166 header.Write("Connection: close\r\n\r\n");
\r
168 client.SendFile(path, ((MemoryStream)header.BaseStream).ToArray(), null,
\r
169 TransmitFileOptions.UseDefaultWorkerThread);
\r
173 private static void SendProxyPac(Socket client, int port)
\r
175 using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))
\r
177 header.Write("HTTP/1.1 200 OK\r\n");
\r
178 header.Write("Server: KancolleSniffer\r\n");
\r
179 header.Write("Date: {0:R}\r\n", DateTime.Now);
\r
180 header.Write("Content-Type: application/x-ns-proxy-autoconfig\r\n");
\r
181 header.Write("Connection: close\r\n\r\n");
\r
183 client.Send(((MemoryStream)header.BaseStream).ToArray());
\r
188 pacFile = File.ReadAllText("proxy.pac").Replace("8080", port.ToString());
\r
194 client.Send(Encoding.ASCII.GetBytes(pacFile));
\r