ApiServer.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using System.Text;
  6. using System.Threading;
  7. using System.IO;
  8. using System.Reflection;
  9. using System.Linq;
  10. using System.Text.RegularExpressions;
  11. namespace System.Net.ApiService {
  12. public class StateObject {
  13. // Client socket.
  14. public Socket workSocket = null;
  15. // Size of receive buffer.
  16. public const int BufferSize = 2048;
  17. // Receive buffer.
  18. public byte[] buffer = new byte[BufferSize];
  19. // Received data string.
  20. public MemoryStream Content = new MemoryStream();
  21. public StringBuilder RawHeader = new StringBuilder();
  22. public RequestHeader Request;
  23. public ApiServer server;
  24. }
  25. public class ApiServer {
  26. public static ManualResetEvent allDone = new ManualResetEvent(false);
  27. protected ushort _port;
  28. protected HttpMethod _allowedMethods = HttpMethod.GET | HttpMethod.POST;
  29. private List<RouteElements> _routes = new List<RouteElements>();
  30. protected string _serverName = "BlackPro_SimpleApi";
  31. // TODO: wwwDirectory entsprechend einer Hosts.ini Datei anpassen, anhand der Request.Host wird ein entsprechender wwwDirectory / FavIcon / Robots.txt verwendet, der in der Hosts.ini hinterlegt wurde
  32. // Das soll Multiple V-Hosts in zukunft erlauben
  33. protected string? _wwwDirectory = "/www";
  34. protected bool bUseWebDirectory = true;
  35. protected bool bUseCompression = false;
  36. protected bool bAllowEmptyResponse = false;
  37. protected Socket listener;
  38. protected bool bRunning;
  39. protected Thread th;
  40. protected string[] _allowedEncodingTypes = new string[] {
  41. "text/html",
  42. "application/javascript",
  43. "text/javascript",
  44. "application/json",
  45. "text/json",
  46. "text/css",
  47. "text/stylesheet",
  48. "text/xml",
  49. "application/xml"
  50. };
  51. public HttpMethod AllowedMethods {
  52. get => this._allowedMethods;
  53. set => this._allowedMethods = value;
  54. }
  55. public RouteElements[] Routes {
  56. get { return this._routes.ToArray(); }
  57. }
  58. public bool Running {
  59. get { return this.bRunning; }
  60. }
  61. public bool AllowEmptyResponse {
  62. get { return this.bAllowEmptyResponse; }
  63. set { this.bAllowEmptyResponse = value; }
  64. }
  65. public bool Compression {
  66. get {
  67. return this.bUseCompression;
  68. }
  69. set {
  70. this.bUseCompression = value;
  71. }
  72. }
  73. public string ServerName {
  74. get {
  75. return this._serverName;
  76. }
  77. set {
  78. this._serverName = value;
  79. }
  80. }
  81. public bool UseWebDirectory {
  82. get {
  83. return this.bUseWebDirectory;
  84. }
  85. }
  86. public string WebDirectory {
  87. get {
  88. return this._wwwDirectory;
  89. }
  90. set {
  91. this._wwwDirectory = value;
  92. this.bUseWebDirectory = this._wwwDirectory != null && Directory.Exists(this._wwwDirectory) && this._wwwDirectory != "";
  93. }
  94. }
  95. public ushort Port {
  96. get {
  97. return this._port;
  98. }
  99. set {
  100. this._port = value;
  101. if (this.bRunning) {
  102. this.Stop();
  103. this.Start();
  104. }
  105. }
  106. }
  107. public ApiServer() {
  108. }
  109. public ApiServer(ushort port) {
  110. this._port = port;
  111. }
  112. public ApiServer(string www_Directory, ushort port) {
  113. this._port = port;
  114. this._wwwDirectory = www_Directory;
  115. }
  116. public void Stop() {
  117. this.bRunning = false;
  118. System.Diagnostics.Debug.WriteLine("Stop");
  119. try {
  120. allDone.Set();
  121. this.th.Abort();
  122. this.listener.Close();
  123. this.listener.Dispose();
  124. this.listener = null;
  125. } catch {
  126. }
  127. }
  128. public void Start() {
  129. if (this.bRunning == true)
  130. return;
  131. this.bRunning = true;
  132. this.th = new Thread(new ThreadStart(this.StartListen));
  133. //this.th.ThreadState = new object[] { this.listener, this._port, this };
  134. System.Diagnostics.Debug.WriteLine("Start");
  135. this.th.Start();
  136. }
  137. protected void StartListen() {
  138. // Establish the local endpoint for the socket.
  139. // The DNS name of the computer
  140. // running the listener is "host.contoso.com".
  141. IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
  142. //IPAddress ipAddress = ipHostInfo.AddressList[0];
  143. IPAddress ipAddress = new IPAddress(new byte[] { 127, 0, 0, 1 });
  144. IPEndPoint localEndPoint = new IPEndPoint(ipAddress, this._port);
  145. // Create a TCP/IP socket.
  146. System.Diagnostics.Debug.WriteLine("Create listener");
  147. //this.listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  148. this.listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  149. // Bind the socket to the local endpoint and listen for incoming connections.
  150. try {
  151. System.Diagnostics.Debug.WriteLine("Bind listener");
  152. this.listener.Bind(localEndPoint);
  153. System.Diagnostics.Debug.WriteLine("Listen on port: " + this._port);
  154. this.listener.Listen(100);
  155. while (this.bRunning) {
  156. // Set the event to nonsignaled state.
  157. System.Diagnostics.Debug.WriteLine("Reset");
  158. allDone.Reset();
  159. // Start an asynchronous socket to listen for connections.
  160. System.Diagnostics.Debug.WriteLine("Begin Accept");
  161. this.listener.BeginAccept(new AsyncCallback(Async_AcceptCallback), new object[] { this.listener, this });
  162. //Accept(this, this.listener);
  163. // Wait until a connection is made before continuing.
  164. System.Diagnostics.Debug.WriteLine("WaitOne");
  165. allDone.WaitOne();
  166. System.Diagnostics.Debug.WriteLine("Wait done");
  167. }
  168. System.Diagnostics.Debug.WriteLine("Stop Listen");
  169. } catch (Exception e) {
  170. System.Diagnostics.Debug.WriteLine(e);
  171. }
  172. }
  173. protected static void Accept(ApiServer server, Socket listener) {
  174. // Get the socket that handles the client request.
  175. Socket handler = listener.Accept();
  176. System.Diagnostics.Debug.WriteLine("AcceptCallback");
  177. allDone.Set();
  178. // Create the state object.
  179. StateObject state = new StateObject();
  180. state.workSocket = handler;
  181. state.server = server;
  182. System.Diagnostics.Debug.WriteLine("Begin Receive");
  183. handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(Async_ReadRequestCallback), state);
  184. }
  185. protected static void Async_AcceptCallback(IAsyncResult ar) {
  186. // Signal the main thread to continue.
  187. System.Diagnostics.Debug.WriteLine("AcceptCallback");
  188. allDone.Set();
  189. // Get the socket that handles the client request.
  190. Socket listener = (Socket)((object[])ar.AsyncState)[0];
  191. Socket handler = listener.EndAccept(ar);
  192. // Create the state object.
  193. StateObject state = new StateObject();
  194. state.workSocket = handler;
  195. state.server = (ApiServer)((object[])ar.AsyncState)[1];
  196. System.Diagnostics.Debug.WriteLine("Begin Receive");
  197. handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(Async_ReadRequestCallback), state);
  198. }
  199. protected static void Async_ReadRequestCallback(IAsyncResult ar) {
  200. System.Diagnostics.Debug.WriteLine("ReadRequestCallback");
  201. String content = String.Empty;
  202. // Retrieve the state object and the handler socket
  203. // from the asynchronous state object.
  204. StateObject state = (StateObject)ar.AsyncState;
  205. Socket handler = state.workSocket;
  206. // Read data from the client socket.
  207. int bytesRead = handler.EndReceive(ar);
  208. if (bytesRead > 0) {
  209. // There might be more data, so store the data received so far.
  210. string line = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
  211. if (state.RawHeader.Length == 0) {
  212. string[] xline = line.Split("\r\n\r\n", 2);
  213. state.RawHeader.Append(xline[0]);
  214. if (xline.Length > 0) {
  215. for (int i = 20; i < bytesRead; i++)
  216. if (state.buffer[i] == '\r' && state.buffer[i + 1] == '\n' && state.buffer[i + 2] == '\r' && state.buffer[i + 3] == '\n') {
  217. state.Content.Write(state.buffer,i+4,bytesRead-i-4);
  218. break;
  219. }
  220. }
  221. state.Request = new RequestHeader(state.RawHeader.ToString());
  222. } else {
  223. state.Content.Write(state.buffer, 0, bytesRead);
  224. }
  225. Response resp = new Response();
  226. RequestEventArgs req = new RequestEventArgs();
  227. req.Response = resp;
  228. req.Request = state.Request;
  229. req.Socket = handler;
  230. req.SendAnyResponse = true;
  231. // Check if more data is incomming
  232. bool ContinueRead = false;
  233. HttpMethod requestsWithContent = HttpMethod.POST | HttpMethod.PUT | HttpMethod.PATCH;
  234. if ((state.Request.Method | requestsWithContent) == requestsWithContent && state.Request.ContentLength > 0) {
  235. ContinueRead = (state.Request.ContentLength > 0 && state.Request.ContentLength < state.Content.Length) || (state.Request.Boundary.Length > 0 && !line.EndsWith("--" + state.Request.Boundary + "--"));
  236. if (!ContinueRead && state.Request.Boundary.Length > 0) {
  237. // TODO: Resolver boundary here
  238. /*
  239. --boundary\r\n
  240. Content-Disposition: form-data; name="field1"\r\n
  241. \r\n
  242. Hier steht der Content, bis der nächste boundary beginnt\r\n
  243. --boundary\r\n
  244. Content-Disposition: form-data; name="field2"; filename="example.txt"\r\n
  245. \r\n
  246. Hier steht der Zweite Content, bis der finale boundary tag beginnt\r\n
  247. --boundary--
  248. */
  249. }
  250. }
  251. if (ContinueRead) {
  252. handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(Async_ReadRequestCallback), state);
  253. } else {
  254. // Check known files and check allowed HTTP-Method
  255. if ((state.Request.Path == "/ping" || state.Request.Path == "ping") && state.Request.Method == HttpMethod.GET) {
  256. resp.FromString(200, "pong");
  257. } else if (state.Request.Path == "/favicon.ico" && state.Request.Method == HttpMethod.GET) {
  258. resp.FromFile("favicon.ico");
  259. } else if (state.Request.Path == "/robots.txt" && state.Request.Method == HttpMethod.GET) {
  260. resp.FromFile("robots.txt");
  261. } else {
  262. if(state.Request.ContentLength>0 && state.Request.ContentLength<2048) {
  263. state.Request.SetPostData(state.Content.ToString());
  264. }
  265. if ((state.Request.Method | state.server._allowedMethods) != state.server._allowedMethods) {
  266. resp.Error(Response.eErrorCode.MethodNotAllowed);
  267. } else {
  268. state.server.RequestAttr(req);
  269. state.server.OnRequest(req);
  270. }
  271. }
  272. // Generate response header
  273. List<string> response_header = new List<string>();
  274. if (state.server.bAllowEmptyResponse && req.Response.Length == 0) {
  275. SetDefaultResponse(req.Response);
  276. }
  277. response_header.Add("HTTP/1.1 " + req.Response.Code + " " + req.Response.CodeName);
  278. response_header.Add("Server: " + state.server.ServerName);
  279. response_header.Add("Date: " + DateTime.Now.ToString("r"));
  280. bool bUseBRCompression = false;
  281. bool bUseGZCompression = false;
  282. bool bUseDeflateCompression = false;
  283. Span<byte> compressed_content = new Span<byte>();
  284. int bytesWritten;
  285. if (req.Response.Code >= 200 && req.Response.Code < 300 && resp.FilePath == "" && state.server.bUseCompression) {
  286. if (state.server._allowedEncodingTypes.Contains(req.Response.ContentType)) {
  287. if ((state.Request.AcceptEncoding & RequestHeader.eEncoder.br) == state.Request.AcceptEncoding) {
  288. if (System.IO.Compression.BrotliEncoder.TryCompress(resp.Content, compressed_content, out bytesWritten)) {
  289. bUseBRCompression = true;
  290. }
  291. } else if ((state.Request.AcceptEncoding & RequestHeader.eEncoder.gzip) == state.Request.AcceptEncoding) {
  292. using (MemoryStream mem = new MemoryStream()) {
  293. using (System.IO.Compression.GZipStream gzip = new IO.Compression.GZipStream(mem, IO.Compression.CompressionLevel.Optimal)) {
  294. gzip.Write(resp.Content, 0, resp.Content.Length);
  295. }
  296. compressed_content = mem.ToArray();
  297. }
  298. bUseGZCompression = true;
  299. } else if ((state.Request.AcceptEncoding & RequestHeader.eEncoder.deflate) == state.Request.AcceptEncoding) {
  300. using (MemoryStream mem = new MemoryStream()) {
  301. using (System.IO.Compression.DeflateStream defl = new IO.Compression.DeflateStream(mem, IO.Compression.CompressionLevel.Optimal)) {
  302. defl.Write(resp.Content, 0, resp.Content.Length);
  303. }
  304. compressed_content = mem.ToArray();
  305. }
  306. bUseDeflateCompression = true;
  307. }
  308. }
  309. }
  310. if (req.Response.Code >= 300 && req.Response.Code < 400 && req.Response.RedirectLocation != "") {
  311. response_header.Add("Location: " + req.Response.RedirectLocation);
  312. } else if (req.Response.Code >= 500) {
  313. // Nothing to do on 500 errors
  314. } else {
  315. if (bUseBRCompression || bUseGZCompression || bUseDeflateCompression)
  316. response_header.Add("Content-Length: " + compressed_content.Length);
  317. else
  318. response_header.Add("Content-Length: " + req.Response.Length);
  319. if (req.Response.ContentType == "") {
  320. response_header.Add("Content-Type: " + req.Response.ContentType);
  321. }
  322. response_header.Add("Accept-Ranges: bytes");
  323. response_header.Add("Age: 0");
  324. response_header.Add("Accept-Ranges: bytes");
  325. if (resp.CacheControl != null && resp.CacheControl.IsSet) {
  326. response_header.Add("Cache-Control: " + resp.CacheControl);
  327. }
  328. if (bUseBRCompression)
  329. response_header.Add("Content-Encoding: bz");
  330. else if (bUseGZCompression)
  331. response_header.Add("Content-Encoding: gzip");
  332. else if (bUseDeflateCompression)
  333. response_header.Add("Content-Encoding: deflate");
  334. response_header.Add("Connection: " + (resp.Connection == Response.eConnection.KeepAlive ? "keep-alive" : "Close"));
  335. }
  336. string response_header_string = "";
  337. foreach (string s in response_header)
  338. response_header_string += s + "\r\n";
  339. response_header_string += "\r\n";
  340. Send(handler, response_header_string, resp.Content);
  341. }
  342. }
  343. }
  344. protected static void SetDefaultResponse(Response res) {
  345. switch (res.ContentType.ToLower().Trim()) {
  346. case "":
  347. case "text/html":
  348. res.FromString("<html></html>", "text/html");
  349. break;
  350. case "text/stylesheet":
  351. case "text/css":
  352. res.FromString("");
  353. break;
  354. case "text/javascript":
  355. case "application/javascript":
  356. case "text/x-javascript":
  357. case "application/x-javascript":
  358. res.FromString("");
  359. break;
  360. }
  361. }
  362. private static void Send(Socket handler, String data, byte[] Content) {
  363. // Convert the string data to byte data using ASCII encoding.
  364. byte[] byteData = Encoding.ASCII.GetBytes(data);
  365. // Begin sending the data to the remote device.
  366. handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendResponseHeaderCallback), new object[] { handler, Content });
  367. }
  368. private static void SendResponseHeaderCallback(IAsyncResult ar) {
  369. try {
  370. // Retrieve the socket from the state object.
  371. Socket handler = (Socket)((object[])ar.AsyncState)[0];
  372. byte[] Content = (byte[])((object[])ar.AsyncState)[1];
  373. // Complete sending the data to the remote device.
  374. int bytesSent = handler.EndSend(ar);
  375. handler.BeginSend(Content, 0, Content.Length, 0, new AsyncCallback(SendResponseContentCallback), handler);
  376. } catch (Exception e) {
  377. System.Diagnostics.Debug.WriteLine(e);
  378. }
  379. }
  380. private static void SendResponseContentCallback(IAsyncResult ar) {
  381. try {
  382. // Retrieve the socket from the state object.
  383. Socket handler = (Socket)ar.AsyncState;
  384. // Complete sending the data to the remote device.
  385. int bytesSent = handler.EndSend(ar);
  386. //Console.WriteLine("Sent {0} bytes to client.", bytesSent);
  387. handler.Shutdown(SocketShutdown.Both);
  388. handler.Close();
  389. } catch (Exception e) {
  390. System.Diagnostics.Debug.WriteLine(e);
  391. }
  392. }
  393. public void RegisterClass(object[] instances) {
  394. foreach (object o in instances)
  395. this.RegisterClass(o);
  396. }
  397. public void RegisterClass(Type[] t) {
  398. foreach (Type o in t)
  399. this.RegisterClass(o);
  400. }
  401. public void RegisterClass(object instance) {
  402. Type t = instance.GetType();
  403. MethodInfo[] methodInfos = t.GetMethods(BindingFlags.Public | BindingFlags.Static);
  404. Route r = t.GetCustomAttribute<Route>();
  405. string baseRoute = "";
  406. if (r != null) {
  407. baseRoute = r.Path;
  408. }
  409. foreach (MethodInfo mi in methodInfos) {
  410. Route[] ris = mi.GetCustomAttributes<Route>().ToArray();
  411. foreach (Route ri in ris) {
  412. this._routes.Add(new RouteElements(instance, mi, ri, baseRoute));
  413. }
  414. }
  415. }
  416. public void RegisterClass(Type t) {
  417. Route r = t.GetCustomAttribute<Route>();
  418. string baseRoute = "";
  419. if (r != null) {
  420. baseRoute = r.Path;
  421. }
  422. MethodInfo[] methodInfos = t.GetMethods(BindingFlags.Public | BindingFlags.Static);
  423. foreach (MethodInfo mi in methodInfos) {
  424. Route[] ris = mi.GetCustomAttributes<Route>().ToArray();
  425. foreach (Route ri in ris) {
  426. this._routes.Add(new RouteElements(t, mi, ri, baseRoute));
  427. }
  428. }
  429. }
  430. protected void RequestAttr(RequestEventArgs e) {
  431. RequestHeader rh;
  432. foreach (RouteElements re in this._routes) {
  433. rh = e.Request;
  434. bool bIsMethod = (rh.Method | re.Method) == re.Method;
  435. if (rh.Path != null && re.Pattern.IsMatch(rh.Path) && bIsMethod) {
  436. ParameterInfo[] pis = re.Function.GetParameters();
  437. if (pis.Length == 2 && pis[0].ParameterType == typeof(RequestHeader) && pis[1].ParameterType == typeof(Response)) {
  438. re.Function.Invoke(re.Instance, new object[] { e.Request, e.Response });
  439. } else if (pis.Length == 1 && pis[0].ParameterType == typeof(RequestHeader)) {
  440. if (re.Function.ReturnType == typeof(Response)) {
  441. Response r = (Response)re.Function.Invoke(re.Instance, new object[] { rh });
  442. if (r != null) {
  443. e.Response = r;
  444. }
  445. } else if (re.Function.ReturnType == typeof(string)) {
  446. string r = (string)re.Function.Invoke(re.Instance, new object[] { rh });
  447. e.Response.FromString(200, r);
  448. } else if (re.Function.ReturnType == typeof(bool)) {
  449. bool r = (bool)re.Function.Invoke(re.Instance, new object[] { rh });
  450. if (r)
  451. e.Response.FromString(200, "{\"status\":\"ok\",\"code\":200,\"value\":1}", "application/json");
  452. else
  453. e.Response.FromString(200, "{\"status\":\"failed\",\"code\":200,\"value\":0}", "application/json");
  454. } else if (re.Function.ReturnType == typeof(object)) {
  455. object r = (object)re.Function.Invoke(re.Instance, new object[] { rh });
  456. e.Response.FromObject(200, r);
  457. }
  458. } else if (pis.Length == 1 && pis[0].ParameterType == typeof(Response)) {
  459. re.Function.Invoke(re.Instance, new object[] { e.Response });
  460. //RegEx
  461. } else if (pis.Length == 3 && pis[0].ParameterType == typeof(RequestHeader) && pis[1].ParameterType == typeof(Response) && pis[2].ParameterType == typeof(Match)) {
  462. re.Function.Invoke(re.Instance, new object[] { e.Request, e.Response, re.Pattern.Match(rh.Path) });
  463. } else if (pis.Length == 2 && pis[0].ParameterType == typeof(RequestHeader) && pis[1].ParameterType == typeof(Match)) {
  464. if (re.Function.ReturnType == typeof(Response)) {
  465. Response r = (Response)re.Function.Invoke(re.Instance, new object[] { rh, re.Pattern.Match(rh.Path) });
  466. if (r != null) {
  467. e.Response = r;
  468. }
  469. } else if (re.Function.ReturnType == typeof(string)) {
  470. string r = (string)re.Function.Invoke(re.Instance, new object[] { rh, re.Pattern.Match(rh.Path) });
  471. e.Response.FromString(200, r);
  472. } else if (re.Function.ReturnType == typeof(bool)) {
  473. bool r = (bool)re.Function.Invoke(re.Instance, new object[] { rh, re.Pattern.Match(rh.Path) });
  474. if (r)
  475. e.Response.FromString(200, "{\"status\":\"ok\",\"code\":200,\"value\":1}", "application/json");
  476. else
  477. e.Response.FromString(200, "{\"status\":\"failed\",\"code\":200,\"value\":0}", "application/json");
  478. } else if (re.Function.ReturnType == typeof(object)) {
  479. object r = (object)re.Function.Invoke(re.Instance, new object[] { rh, re.Pattern.Match(rh.Path) });
  480. e.Response.FromObject(200, r);
  481. }
  482. } else if (pis.Length == 2 && pis[0].ParameterType == typeof(Response) && pis[1].ParameterType == typeof(Match)) {
  483. re.Function.Invoke(re.Instance, new object[] { e.Response, re.Pattern.Match(rh.Path) });
  484. } else if (pis.Length == 3 && pis[0].ParameterType == typeof(RequestHeader) && pis[1].ParameterType == typeof(Response) && pis[2].ParameterType == typeof(GroupCollection)) {
  485. re.Function.Invoke(re.Instance, new object[] { e.Request, e.Response, re.Pattern.Match(rh.Path).Groups });
  486. } else if (pis.Length == 2 && pis[0].ParameterType == typeof(RequestHeader) && pis[1].ParameterType == typeof(GroupCollection)) {
  487. if (re.Function.ReturnType == typeof(Response)) {
  488. Response r = (Response)re.Function.Invoke(re.Instance, new object[] { rh, re.Pattern.Match(rh.Path).Groups });
  489. if (r != null) {
  490. e.Response = r;
  491. }
  492. } else if (re.Function.ReturnType == typeof(string)) {
  493. string r = (string)re.Function.Invoke(re.Instance, new object[] { rh, re.Pattern.Match(rh.Path).Groups });
  494. e.Response.FromString(200, r);
  495. } else if (re.Function.ReturnType == typeof(bool)) {
  496. bool r = (bool)re.Function.Invoke(re.Instance, new object[] { rh, re.Pattern.Match(rh.Path).Groups });
  497. if (r)
  498. e.Response.FromString(200, "{\"status\":\"ok\",\"code\":200,\"value\":1}", "application/json");
  499. else
  500. e.Response.FromString(200, "{\"status\":\"failed\",\"code\":200,\"value\":0}", "application/json");
  501. } else if (re.Function.ReturnType == typeof(object)) {
  502. object r = (object)re.Function.Invoke(re.Instance, new object[] { rh, re.Pattern.Match(rh.Path).Groups });
  503. e.Response.FromObject(200, r);
  504. }
  505. } else if (pis.Length == 2 && pis[0].ParameterType == typeof(Response) && pis[1].ParameterType == typeof(GroupCollection)) {
  506. re.Function.Invoke(re.Instance, new object[] { e.Response, re.Pattern.Match(rh.Path).Groups });
  507. }
  508. }
  509. }
  510. }
  511. public virtual void OnRequest(RequestEventArgs e) {
  512. EventHandler<RequestEventArgs> handler = Request;
  513. if (handler != null) {
  514. handler(this, e);
  515. }
  516. }
  517. public event EventHandler<RequestEventArgs> Request;
  518. }
  519. }