Web.hx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*
  2. * Copyright (C)2005-2019 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package neko;
  23. import haxe.ds.List;
  24. /**
  25. This class is used for accessing the local Web server and the current
  26. client request and information.
  27. **/
  28. @:deprecated('neko.Web is deprecated and will be removed from standard library in Haxe 4.2')
  29. class Web {
  30. /**
  31. Returns the GET and POST parameters.
  32. **/
  33. public static function getParams() {
  34. var p = _get_params();
  35. var h = new haxe.ds.StringMap<String>();
  36. var k = "";
  37. while (p != null) {
  38. untyped k.__s = p[0];
  39. h.set(k, new String(p[1]));
  40. p = untyped p[2];
  41. }
  42. return h;
  43. }
  44. /**
  45. Returns an Array of Strings built using GET / POST values.
  46. If the URL contains the parameters `[a[]=foo;a[]=hello;a[5]=bar;a[3]=baz]` then
  47. `neko.Web.getParamValues("a")` will return `["foo","hello",null,"baz",null,"bar"]`
  48. **/
  49. public static function getParamValues(param:String):Array<String> {
  50. var reg = new EReg("^" + param + "(\\[|%5B)([0-9]*?)(\\]|%5D)=(.*?)$", "");
  51. var res = new Array<String>();
  52. var explore = function(data:String) {
  53. if (data == null || data.length == 0)
  54. return;
  55. for (part in data.split("&")) {
  56. if (reg.match(part)) {
  57. var idx = reg.matched(2);
  58. var val = StringTools.urlDecode(reg.matched(4));
  59. if (idx == "")
  60. res.push(val);
  61. else
  62. res[Std.parseInt(idx)] = val;
  63. }
  64. }
  65. }
  66. explore(StringTools.replace(getParamsString(), ";", "&"));
  67. explore(getPostData());
  68. if (res.length == 0)
  69. return null;
  70. return res;
  71. }
  72. /**
  73. Returns the local server host name.
  74. **/
  75. public static function getHostName() {
  76. return new String(_get_host_name());
  77. }
  78. /**
  79. Surprisingly returns the client IP address.
  80. **/
  81. public static function getClientIP() {
  82. return new String(_get_client_ip());
  83. }
  84. /**
  85. Returns the original request URL (before any server internal redirections)
  86. **/
  87. public static function getURI() {
  88. return new String(_get_uri());
  89. }
  90. /**
  91. Tell the client to redirect to the given url ("Location" header)
  92. **/
  93. public static function redirect(url:String) {
  94. _cgi_redirect(untyped url.__s);
  95. }
  96. /**
  97. Set an output header value. If some data have been printed, the headers have
  98. already been sent so this will raise an exception.
  99. **/
  100. public static function setHeader(h:String, v:String) {
  101. _cgi_set_header(untyped h.__s, untyped v.__s);
  102. }
  103. /**
  104. Set the HTTP return code. Same remark as setHeader.
  105. **/
  106. public static function setReturnCode(r:Int) {
  107. _set_return_code(r);
  108. }
  109. /**
  110. Retrieve a client header value sent with the request.
  111. **/
  112. public static function getClientHeader(k:String) {
  113. var v = _get_client_header(untyped k.__s);
  114. if (v == null)
  115. return null;
  116. return new String(v);
  117. }
  118. /**
  119. Retrieve all the client headers.
  120. **/
  121. public static function getClientHeaders() {
  122. var v = _get_client_headers();
  123. var a = new List();
  124. while (v != null) {
  125. a.add({header: new String(v[0]), value: new String(v[1])});
  126. v = cast v[2];
  127. }
  128. return a;
  129. }
  130. /**
  131. Returns all the GET parameters String.
  132. **/
  133. public static function getParamsString() {
  134. var p = _get_params_string();
  135. return if (p == null) "" else new String(p);
  136. }
  137. /**
  138. Returns all the POST data. POST Data is always parsed as
  139. being `application/x-www-form-urlencoded` and is stored into
  140. the getParams hashtable. POST Data is maximimized to 256K
  141. unless the content type is `multipart/form-data`. In that
  142. case, you will have to use `getMultipart` or `parseMultipart`
  143. methods.
  144. **/
  145. public static function getPostData() {
  146. var v = _get_post_data();
  147. if (v == null)
  148. return null;
  149. return new String(v);
  150. }
  151. /**
  152. Returns an hashtable of all Cookies sent by the client.
  153. Modifying the hashtable will not modify the cookie, use `setCookie` instead.
  154. **/
  155. public static function getCookies():Map<String, String> {
  156. var p = _get_cookies();
  157. var h = new haxe.ds.StringMap<String>();
  158. var k = "";
  159. while (p != null) {
  160. untyped k.__s = p[0];
  161. h.set(k, new String(p[1]));
  162. p = untyped p[2];
  163. }
  164. return h;
  165. }
  166. /**
  167. Set a Cookie value in the HTTP headers. Same remark as `setHeader`.
  168. **/
  169. public static function setCookie(key:String, value:String, ?expire:Date, ?domain:String, ?path:String, ?secure:Bool, ?httpOnly:Bool) {
  170. var buf = new StringBuf();
  171. buf.add(value);
  172. if (expire != null)
  173. addPair(buf, "expires=", DateTools.format(expire, "%a, %d-%b-%Y %H:%M:%S GMT"));
  174. addPair(buf, "domain=", domain);
  175. addPair(buf, "path=", path);
  176. if (secure)
  177. addPair(buf, "secure", "");
  178. if (httpOnly)
  179. addPair(buf, "HttpOnly", "");
  180. var v = buf.toString();
  181. _set_cookie(untyped key.__s, untyped v.__s);
  182. }
  183. static function addPair(buf:StringBuf, name:String, value:String) {
  184. if (value == null)
  185. return;
  186. buf.add("; ");
  187. buf.add(name);
  188. buf.add(value);
  189. }
  190. /**
  191. Returns an object with the authorization sent by the client (Basic scheme only).
  192. **/
  193. public static function getAuthorization():{user:String, pass:String} {
  194. var h = getClientHeader("Authorization");
  195. var reg = ~/^Basic ([^=]+)=*$/;
  196. if (h != null && reg.match(h)) {
  197. var val = reg.matched(1);
  198. untyped val = new String(_base_decode(val.__s, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".__s));
  199. var a = val.split(":");
  200. if (a.length != 2) {
  201. throw "Unable to decode authorization.";
  202. }
  203. return {user: a[0], pass: a[1]};
  204. }
  205. return null;
  206. }
  207. /**
  208. Get the current script directory in the local filesystem.
  209. **/
  210. public static function getCwd() {
  211. return new String(_get_cwd());
  212. }
  213. /**
  214. Set the main entry point function used to handle requests.
  215. Setting it back to null will disable code caching.
  216. **/
  217. public static function cacheModule(f:Void->Void) {
  218. _set_main(f);
  219. }
  220. /**
  221. Get the multipart parameters as an hashtable. The data
  222. cannot exceed the maximum size specified.
  223. **/
  224. public static function getMultipart(maxSize:Int):Map<String, String> {
  225. var h = new haxe.ds.StringMap();
  226. var buf:haxe.io.BytesBuffer = null;
  227. var curname = null;
  228. parseMultipart(function(p, _) {
  229. if (curname != null)
  230. h.set(curname, neko.Lib.stringReference(buf.getBytes()));
  231. curname = p;
  232. buf = new haxe.io.BytesBuffer();
  233. maxSize -= p.length;
  234. if (maxSize < 0)
  235. throw "Maximum size reached";
  236. }, function(str, pos, len) {
  237. maxSize -= len;
  238. if (maxSize < 0)
  239. throw "Maximum size reached";
  240. buf.addBytes(str, pos, len);
  241. });
  242. if (curname != null)
  243. h.set(curname, neko.Lib.stringReference(buf.getBytes()));
  244. return h;
  245. }
  246. /**
  247. Parse the multipart data. Call `onPart` when a new part is found
  248. with the part name and the filename if present
  249. and `onData` when some part data is read. You can this way
  250. directly save the data on hard drive in the case of a file upload.
  251. **/
  252. public static function parseMultipart(onPart:String->String->Void, onData:haxe.io.Bytes->Int->Int->Void):Void {
  253. _parse_multipart(function(p, f) {
  254. onPart(new String(p), if (f == null) null else new String(f));
  255. }, function(buf, pos, len) {
  256. onData(untyped new haxe.io.Bytes(__dollar__ssize(buf), buf), pos, len);
  257. });
  258. }
  259. /**
  260. Flush the data sent to the client. By default on Apache, outgoing data is buffered so
  261. this can be useful for displaying some long operation progress.
  262. **/
  263. public static function flush():Void {
  264. _flush();
  265. }
  266. /**
  267. Get the HTTP method used by the client. This API requires Neko 1.7.1+.
  268. **/
  269. public static function getMethod():String {
  270. return new String(_get_http_method());
  271. }
  272. /**
  273. Write a message into the web server log file. This API requires Neko 1.7.1+.
  274. **/
  275. public static function logMessage(msg:String) {
  276. _log_message(untyped msg.__s);
  277. }
  278. public static var isModNeko(default, null):Bool;
  279. public static var isTora(default, null):Bool;
  280. static var _set_main:Dynamic;
  281. static var _get_host_name:Dynamic;
  282. static var _get_client_ip:Dynamic;
  283. static var _get_uri:Dynamic;
  284. static var _cgi_redirect:Dynamic;
  285. static var _cgi_set_header:Dynamic;
  286. static var _set_return_code:Dynamic;
  287. static var _get_client_header:Dynamic;
  288. static var _get_params_string:Dynamic;
  289. static var _get_post_data:Dynamic;
  290. static var _get_params:Dynamic;
  291. static var _get_cookies:Dynamic;
  292. static var _set_cookie:Dynamic;
  293. static var _get_cwd:Dynamic;
  294. static var _parse_multipart:Dynamic;
  295. static var _flush:Dynamic;
  296. static var _get_client_headers:Dynamic;
  297. static var _get_http_method:Dynamic;
  298. static var _base_decode = Lib.load("std", "base_decode", 2);
  299. static var _log_message:Dynamic;
  300. static function __init__() {
  301. var get_env = Lib.load("std", "get_env", 1);
  302. var ver = untyped get_env("MOD_NEKO".__s);
  303. untyped isModNeko = (ver != null);
  304. if (isModNeko) {
  305. var lib = "mod_neko" + if (ver == untyped "1".__s) "" else ver;
  306. _set_main = Lib.load(lib, "cgi_set_main", 1);
  307. _get_host_name = Lib.load(lib, "get_host_name", 0);
  308. _get_client_ip = Lib.load(lib, "get_client_ip", 0);
  309. _get_uri = Lib.load(lib, "get_uri", 0);
  310. _cgi_redirect = Lib.load(lib, "redirect", 1);
  311. _cgi_set_header = Lib.load(lib, "set_header", 2);
  312. _set_return_code = Lib.load(lib, "set_return_code", 1);
  313. _get_client_header = Lib.load(lib, "get_client_header", 1);
  314. _get_params_string = Lib.load(lib, "get_params_string", 0);
  315. _get_post_data = Lib.load(lib, "get_post_data", 0);
  316. _get_params = Lib.load(lib, "get_params", 0);
  317. _get_cookies = Lib.load(lib, "get_cookies", 0);
  318. _set_cookie = Lib.load(lib, "set_cookie", 2);
  319. _get_cwd = Lib.load(lib, "cgi_get_cwd", 0);
  320. _get_http_method = Lib.loadLazy(lib, "get_http_method", 0);
  321. _parse_multipart = Lib.loadLazy(lib, "parse_multipart_data", 2);
  322. _flush = Lib.loadLazy(lib, "cgi_flush", 0);
  323. _get_client_headers = Lib.loadLazy(lib, "get_client_headers", 0);
  324. _log_message = Lib.loadLazy(lib, "log_message", 1);
  325. isTora = try Lib.load(lib, "tora_infos", 0) != null catch (e:Dynamic) false;
  326. } else {
  327. var a0 = untyped __dollar__loader.args[0];
  328. if (a0 != null)
  329. a0 = new String(a0);
  330. _set_main = function(f) {};
  331. _get_host_name = function() {
  332. return untyped "localhost".__s;
  333. };
  334. _get_client_ip = function() {
  335. return untyped "127.0.0.1".__s;
  336. };
  337. _get_uri = function() {
  338. return untyped (if (a0 == null) "/" else a0).__s;
  339. };
  340. _cgi_redirect = function(v) {
  341. Lib.print("Location: " + v + "\n");
  342. };
  343. _cgi_set_header = function(h, v) {};
  344. _set_return_code = function(i) {};
  345. _get_client_header = function(h) {
  346. return null;
  347. };
  348. _get_client_headers = function() {
  349. return null;
  350. };
  351. _get_params_string = function() {
  352. return untyped (if (a0 == null) "" else a0).__s;
  353. };
  354. _get_post_data = function() {
  355. return null;
  356. };
  357. _get_params = function() {
  358. var l = null;
  359. if (a0 == null)
  360. return null;
  361. for (p in a0.split(";")) {
  362. var k = p.split("=");
  363. if (k.length == 2)
  364. l = untyped [k[0].__s, k[1].__s, l];
  365. }
  366. return l;
  367. };
  368. _get_cookies = function() {
  369. return null;
  370. }
  371. _set_cookie = function(k, v) {};
  372. _get_cwd = Lib.load("std", "get_cwd", 0);
  373. _get_http_method = function() return untyped "GET".__s;
  374. _parse_multipart = function(a, b) {
  375. throw "Not supported";
  376. };
  377. _flush = function() {};
  378. _log_message = function(s) {};
  379. isTora = false;
  380. }
  381. }
  382. }