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
16 using System.Collections.Generic;
\r
17 using System.Globalization;
\r
20 using System.Net.Sockets;
\r
23 namespace KancolleSniffer
\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 void Process(Socket client, string requestLine)
\r
37 var from = DateTime.MinValue;
\r
38 var to = DateTime.MaxValue;
\r
39 var timestamp = false;
\r
41 var request = requestLine.Split(' ');
\r
42 if (request.Length != 3)
\r
44 SendError(client, "400 Bad Request");
\r
47 if (!request[0].StartsWith("GET", StringComparison.OrdinalIgnoreCase))
\r
49 SendError(client, "501 Not Implemented");
\r
52 var tmp = request[1].Split('?');
\r
53 var path = HttpUtility.UrlDecode(tmp[0]);
\r
54 if (path == null || !path.StartsWith("/"))
\r
56 SendError(client, "400 Bad Request");
\r
59 if (tmp.Length == 2)
\r
61 var query = HttpUtility.ParseQueryString(tmp[1]);
\r
62 if (query["from"] != null)
\r
65 double.TryParse(query["from"], out tick);
\r
66 from = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000);
\r
68 if (query["to"] != null)
\r
71 double.TryParse(query["to"], out 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("proxy.pac"))
\r
103 SendProxyPac(client, HttpProxy.LocalPort);
\r
106 SendError(client, "404 Not Found");
\r
109 private static void SendError(Socket client, string error)
\r
111 using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII))
\r
113 writer.Write("HTTP/1.1 {0}\r\n", error);
\r
114 writer.Write("Server: KancolleSniffer\r\n");
\r
115 writer.Write("Date: {0:R}\r\n", DateTime.Now);
\r
116 writer.Write("Connection: close\r\n\r\n");
\r
117 writer.Write("<html><head><title>{0}</title></head>\r\n", error);
\r
118 writer.Write("<body><h4>{0}</h4></body></html>\r\n\r\n", error);
\r
120 client.Send(((MemoryStream)writer.BaseStream).ToArray());
\r
124 private static void SendJsonData(Socket client, string path, DateTime from, DateTime to, bool number)
\r
126 using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))
\r
128 header.Write("HTTP/1.1 200 OK\r\n");
\r
129 header.Write("Server: KancolleSniffer\r\n");
\r
130 header.Write("Date: {0:R}\r\n", DateTime.Now);
\r
131 header.Write("Content-Type: {0}\r\n", "application/json; charset=Shift_JIS");
\r
132 header.Write("Connection: close\r\n\r\n");
\r
134 client.Send(((MemoryStream)header.BaseStream).ToArray());
\r
136 var csv = path.Replace(".json", ".csv");
\r
137 var encoding = Encoding.GetEncoding("Shift_JIS");
\r
138 client.Send(encoding.GetBytes("{ \"data\": [\n"));
\r
141 if (File.Exists(csv))
\r
143 var delimiter = "";
\r
144 var material = path.EndsWith("資材ログ.json"); // 末尾の空データを削除する必要がある
\r
145 var battle = path.EndsWith("海戦・ドロップ報告書.json"); // データを40個にそろえる必要がある
\r
146 foreach (var line in File.ReadLines(csv, encoding).Skip(1))
\r
148 var data = line.Split(',');
\r
150 if (!DateTime.TryParseExact(data[0], Logger.DateTimeFormat, CultureInfo.InvariantCulture,
\r
151 DateTimeStyles.AssumeLocal, out date) &&
\r
152 DateTime.TryParse(data[0], CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out date))
\r
154 data[0] = date.ToString(Logger.DateTimeFormat);
\r
156 if (date < from || to < date)
\r
158 IEnumerable<string> entries = data;
\r
160 entries = data.Take(9);
\r
162 entries = data.Concat(Enumerable.Repeat("", 3)).Take(38);
\r
165 var stamp = ((date.ToUniversalTime().Ticks -
\r
166 new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks) /
\r
167 TimeSpan.TicksPerMillisecond).ToString();
\r
168 client.Send(encoding.GetBytes(delimiter + "[" + stamp + "," +
\r
169 string.Join(",", entries.Skip(1)) + "]"));
\r
173 client.Send(encoding.GetBytes(delimiter + "[\"" +
\r
174 string.Join("\",\"", entries) + "\"]"));
\r
182 client.Send(encoding.GetBytes("]}\n"));
\r
186 private static void SendFile(Socket client, string path, string mime)
\r
188 using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))
\r
190 header.Write("HTTP/1.1 200 OK\r\n");
\r
191 header.Write("Server: KancolleSniffer\r\n");
\r
192 header.Write("Date: {0:R}\r\n", DateTime.Now);
\r
193 header.Write("Content-Length: {0}\r\n", new FileInfo(path).Length);
\r
194 header.Write("Content-Type: {0}\r\n", mime);
\r
195 header.Write("Connection: close\r\n\r\n");
\r
197 client.SendFile(path, ((MemoryStream)header.BaseStream).ToArray(), null,
\r
198 TransmitFileOptions.UseDefaultWorkerThread);
\r
202 private static void SendProxyPac(Socket client, int port)
\r
204 using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))
\r
206 header.Write("HTTP/1.1 200 OK\r\n");
\r
207 header.Write("Server: KancolleSniffer\r\n");
\r
208 header.Write("Date: {0:R}\r\n", DateTime.Now);
\r
209 header.Write("Content-Type: application/x-ns-proxy-autoconfig\r\n");
\r
210 header.Write("Connection: close\r\n\r\n");
\r
212 client.Send(((MemoryStream)header.BaseStream).ToArray());
\r
215 function FindProxyForURL(url, host) {
\r
216 if(isInNet(host, ""203.104.209.71"", ""255.255.255.255"") ||
\r
217 isInNet(host, ""125.6.184.15"", ""255.255.255.255"") ||
\r
218 isInNet(host, ""125.6.184.16"", ""255.255.255.255"") ||
\r
219 isInNet(host, ""125.6.187.205"", ""255.255.255.255"") ||
\r
220 isInNet(host, ""125.6.187.229"", ""255.255.255.255"") ||
\r
221 isInNet(host, ""125.6.187.253"", ""255.255.255.255"") ||
\r
222 isInNet(host, ""125.6.188.25"", ""255.255.255.255"") ||
\r
223 isInNet(host, ""203.104.248.135"", ""255.255.255.255"") ||
\r
224 isInNet(host, ""125.6.189.7"", ""255.255.255.255"") ||
\r
225 isInNet(host, ""125.6.189.39"", ""255.255.255.255"") ||
\r
226 isInNet(host, ""125.6.189.71"", ""255.255.255.255"") ||
\r
227 isInNet(host, ""125.6.189.103"", ""255.255.255.255"") ||
\r
228 isInNet(host, ""125.6.189.135"", ""255.255.255.255"") ||
\r
229 isInNet(host, ""125.6.189.167"", ""255.255.255.255"") ||
\r
230 isInNet(host, ""125.6.189.215"", ""255.255.255.255"") ||
\r
231 isInNet(host, ""125.6.189.247"", ""255.255.255.255"") ||
\r
232 isInNet(host, ""203.104.209.23"", ""255.255.255.255"") ||
\r
233 isInNet(host, ""203.104.209.39"", ""255.255.255.255"") ||
\r
234 isInNet(host, ""203.104.209.55"", ""255.255.255.255"") ||
\r
235 isInNet(host, ""203.104.209.102"", ""255.255.255.255"") ||
\r
236 isInNet(host, ""203.104.209.87"", ""255.255.255.255"")) {
\r
237 return ""PROXY 127.0.0.1:8080"";
\r
242 }".Replace("8080", port.ToString());
\r
243 client.Send(Encoding.ASCII.GetBytes(pacFile));
\r