Web.hx 12 KB

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