/bin/std/neko/Web.hx

http://github.com/Yoomee/clippy · Haxe · 388 lines · 250 code · 29 blank · 109 comment · 52 complexity · 5c86783c4253b03a4737c3cb71a13b33 MD5 · raw file

  1. /*
  2. * Copyright (c) 2005, The haXe Project Contributors
  3. * All rights reserved.
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. *
  7. * - Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * - Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
  17. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  19. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  20. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  23. * DAMAGE.
  24. */
  25. package neko;
  26. /**
  27. This class is used for accessing the local Web server and the current
  28. client request and informations.
  29. **/
  30. class Web {
  31. /**
  32. Returns the GET and POST parameters.
  33. **/
  34. public static function getParams() {
  35. var p = _get_params();
  36. var h = new Hash<String>();
  37. var k = "";
  38. while( p != null ) {
  39. untyped k.__s = p[0];
  40. h.set(k,new String(p[1]));
  41. p = untyped p[2];
  42. }
  43. return h;
  44. }
  45. /**
  46. Returns an Array of Strings built using GET / POST values.
  47. If you have in your URL the parameters [a[]=foo;a[]=hello;a[5]=bar;a[3]=baz] then
  48. [neko.Web.getParamValues("a")] will return [["foo","hello",null,"baz",null,"bar"]]
  49. **/
  50. public static function getParamValues( param : String ) : Array<String> {
  51. var reg = new EReg("^"+param+"(\\[|%5B)([0-9]*?)(\\]|%5D)=(.*?)$", "");
  52. var res = new Array<String>();
  53. var explore = function(data:String){
  54. if (data == null || data.length == 0)
  55. return;
  56. for (part in data.split("&")){
  57. if (reg.match(part)){
  58. var idx = reg.matched(2);
  59. var val = StringTools.urlDecode(reg.matched(4));
  60. if (idx == "")
  61. res.push(val);
  62. else
  63. res[Std.parseInt(idx)] = val;
  64. }
  65. }
  66. }
  67. explore(StringTools.replace(getParamsString(), ";", "&"));
  68. explore(getPostData());
  69. if (res.length == 0)
  70. return null;
  71. return res;
  72. }
  73. /**
  74. Returns the local server host name
  75. **/
  76. public static function getHostName() {
  77. return new String(_get_host_name());
  78. }
  79. /**
  80. Surprisingly returns the client IP address.
  81. **/
  82. public static function getClientIP() {
  83. return new String(_get_client_ip());
  84. }
  85. /**
  86. Returns the original request URL (before any server internal redirections)
  87. **/
  88. public static function getURI() {
  89. return new String(_get_uri());
  90. }
  91. /**
  92. Tell the client to redirect to the given url ("Location" header)
  93. **/
  94. public static function redirect( url : String ) {
  95. _cgi_redirect(untyped url.__s);
  96. }
  97. /**
  98. Set an output header value. If some data have been printed, the headers have
  99. already been sent so this will raise an exception.
  100. **/
  101. public static function setHeader( h : String, v : String ) {
  102. _cgi_set_header(untyped h.__s,untyped v.__s);
  103. }
  104. /**
  105. Set the HTTP return code. Same remark as setHeader.
  106. **/
  107. public static function setReturnCode( r : Int ) {
  108. _set_return_code(r);
  109. }
  110. /**
  111. Retrieve a client header value sent with the request.
  112. **/
  113. public static function getClientHeader( k : String ) {
  114. var v = _get_client_header(untyped k.__s);
  115. if( v == null )
  116. return null;
  117. return new String(v);
  118. }
  119. /**
  120. Retrieve all the client headers.
  121. **/
  122. public static function getClientHeaders() {
  123. var v = _get_client_headers();
  124. var a = new List();
  125. while( v != null ) {
  126. a.add({ header : new String(v[0]), value : new String(v[1]) });
  127. v = cast v[2];
  128. }
  129. return a;
  130. }
  131. /**
  132. Returns all the GET parameters String
  133. **/
  134. public static function getParamsString() {
  135. return new String(_get_params_string());
  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() {
  156. var p = _get_cookies();
  157. var h = new Hash<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 ) {
  170. var buf = new StringBuf();
  171. buf.add(value);
  172. if( expire != null ) addPair(buf, "expires=", DateTools.format(expire, "%a, %d-%b-%Y %H:%M:%S GMT"));
  173. addPair(buf, "domain=", domain);
  174. addPair(buf, "path=", path);
  175. if( secure ) addPair(buf, "secure", "");
  176. var v = buf.toString();
  177. _set_cookie(untyped key.__s, untyped v.__s);
  178. }
  179. static function addPair( buf : StringBuf, name, value ) {
  180. if( value == null ) return;
  181. buf.add("; ");
  182. buf.add(name);
  183. buf.add(value);
  184. }
  185. /**
  186. Returns an object with the authorization sent by the client (Basic scheme only).
  187. **/
  188. public static function getAuthorization() : { user : String, pass : String } {
  189. var h = getClientHeader("Authorization");
  190. var reg = ~/^Basic ([^=]+)=*$/;
  191. if( h != null && reg.match(h) ){
  192. var val = reg.matched(1);
  193. untyped val = new String(_base_decode(val.__s,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".__s));
  194. var a = val.split(":");
  195. if( a.length != 2 ){
  196. throw "Unable to decode authorization.";
  197. }
  198. return {user: a[0],pass: a[1]};
  199. }
  200. return null;
  201. }
  202. /**
  203. Get the current script directory in the local filesystem.
  204. **/
  205. public static function getCwd() {
  206. return new String(_get_cwd());
  207. }
  208. /**
  209. Set the main entry point function used to handle requests.
  210. Setting it back to null will disable code caching.
  211. **/
  212. public static function cacheModule( f : Void -> Void ) {
  213. _set_main(f);
  214. }
  215. /**
  216. Get the multipart parameters as an hashtable. The data
  217. cannot exceed the maximum size specified.
  218. **/
  219. public static function getMultipart( maxSize : Int ) : Hash<String> {
  220. var h = new Hash();
  221. var buf : haxe.io.BytesBuffer = null;
  222. var curname = null;
  223. parseMultipart(function(p,_) {
  224. if( curname != null )
  225. h.set(curname,neko.Lib.stringReference(buf.getBytes()));
  226. curname = p;
  227. buf = new haxe.io.BytesBuffer();
  228. maxSize -= p.length;
  229. if( maxSize < 0 )
  230. throw "Maximum size reached";
  231. },function(str,pos,len) {
  232. maxSize -= len;
  233. if( maxSize < 0 )
  234. throw "Maximum size reached";
  235. buf.addBytes(str,pos,len);
  236. });
  237. if( curname != null )
  238. h.set(curname,neko.Lib.stringReference(buf.getBytes()));
  239. return h;
  240. }
  241. /**
  242. Parse the multipart data. Call [onPart] when a new part is found
  243. with the part name and the filename if present
  244. and [onData] when some part data is readed. You can this way
  245. directly save the data on hard drive in the case of a file upload.
  246. **/
  247. public static function parseMultipart( onPart : String -> String -> Void, onData : haxe.io.Bytes -> Int -> Int -> Void ) : Void {
  248. _parse_multipart(
  249. function(p,f) { onPart(new String(p),if( f == null ) null else new String(f)); },
  250. function(buf,pos,len) { onData(untyped new haxe.io.Bytes(__dollar__ssize(buf),buf),pos,len); }
  251. );
  252. }
  253. /**
  254. Flush the data sent to the client. By default on Apache, outgoing data is buffered so
  255. this can be useful for displaying some long operation progress.
  256. **/
  257. public static function flush() : Void {
  258. _flush();
  259. }
  260. /**
  261. Get the HTTP method used by the client. This api requires Neko 1.7.1+
  262. **/
  263. public static function getMethod() : String {
  264. return new String(_get_http_method());
  265. }
  266. /**
  267. Write a message into the web server log file. This api requires Neko 1.7.1+
  268. **/
  269. public static function logMessage( msg : String ) {
  270. _log_message(untyped msg.__s);
  271. }
  272. public static var isModNeko(default,null) : Bool;
  273. public static var isTora(default,null) : Bool;
  274. static var _set_main : Dynamic;
  275. static var _get_host_name : Dynamic;
  276. static var _get_client_ip : Dynamic;
  277. static var _get_uri : Dynamic;
  278. static var _cgi_redirect : Dynamic;
  279. static var _cgi_set_header : Dynamic;
  280. static var _set_return_code : Dynamic;
  281. static var _get_client_header : Dynamic;
  282. static var _get_params_string : Dynamic;
  283. static var _get_post_data : Dynamic;
  284. static var _get_params : Dynamic;
  285. static var _get_cookies : Dynamic;
  286. static var _set_cookie : Dynamic;
  287. static var _get_cwd : Dynamic;
  288. static var _parse_multipart : Dynamic;
  289. static var _flush : Dynamic;
  290. static var _get_client_headers : Dynamic;
  291. static var _get_http_method : Dynamic;
  292. static var _base_decode = Lib.load("std","base_decode",2);
  293. static var _log_message : Dynamic;
  294. static function __init__() {
  295. var get_env = Lib.load("std","get_env",1);
  296. var ver = untyped get_env("MOD_NEKO".__s);
  297. untyped isModNeko = (ver != null);
  298. if( isModNeko ) {
  299. var lib = "mod_neko"+if( ver == untyped "1".__s ) "" else ver;
  300. _set_main = Lib.load(lib,"cgi_set_main",1);
  301. _get_host_name = Lib.load(lib,"get_host_name",0);
  302. _get_client_ip = Lib.load(lib,"get_client_ip",0);
  303. _get_uri = Lib.load(lib,"get_uri",0);
  304. _cgi_redirect = Lib.load(lib,"redirect",1);
  305. _cgi_set_header = Lib.load(lib,"set_header",2);
  306. _set_return_code = Lib.load(lib,"set_return_code",1);
  307. _get_client_header = Lib.load(lib,"get_client_header",1);
  308. _get_params_string = Lib.load(lib,"get_params_string",0);
  309. _get_post_data = Lib.load(lib,"get_post_data",0);
  310. _get_params = Lib.load(lib,"get_params",0);
  311. _get_cookies = Lib.load(lib,"get_cookies",0);
  312. _set_cookie = Lib.load(lib,"set_cookie",2);
  313. _get_cwd = Lib.load(lib,"cgi_get_cwd",0);
  314. _get_http_method = Lib.loadLazy(lib,"get_http_method",0);
  315. _parse_multipart = Lib.loadLazy(lib,"parse_multipart_data",2);
  316. _flush = Lib.loadLazy(lib,"cgi_flush",0);
  317. _get_client_headers = Lib.loadLazy(lib,"get_client_headers",0);
  318. _log_message = Lib.loadLazy(lib,"log_message",1);
  319. isTora = try Lib.load(lib,"tora_infos",0) != null catch( e : Dynamic) false;
  320. } else {
  321. var a0 = untyped __dollar__loader.args[0];
  322. if( a0 != null ) a0 = new String(a0);
  323. _set_main = function(f) { };
  324. _get_host_name = function() { return untyped "localhost".__s; };
  325. _get_client_ip = function() { return untyped "127.0.0.1".__s; };
  326. _get_uri = function() {
  327. return untyped (if( a0 == null ) "/" else a0).__s;
  328. };
  329. _cgi_redirect = function(v) { Lib.print("Location: "+v+"\n"); };
  330. _cgi_set_header = function(h,v) { };
  331. _set_return_code = function(i) { };
  332. _get_client_header = function(h) { return null; };
  333. _get_client_headers = function() { return null; };
  334. _get_params_string = function() {
  335. return untyped (if( a0 == null ) "" else a0).__s;
  336. };
  337. _get_post_data = function() { return null; };
  338. _get_params = function() {
  339. var l = null;
  340. if( a0 == null )
  341. return null;
  342. for( p in a0.split(";") ) {
  343. var k = p.split("=");
  344. if( k.length == 2 )
  345. l = untyped [k[0].__s,k[1].__s,l];
  346. }
  347. return l;
  348. };
  349. _get_cookies = function() { return null; }
  350. _set_cookie = function(k,v) { };
  351. _get_cwd = Lib.load("std","get_cwd",0);
  352. _get_http_method = function() return untyped "GET".__s;
  353. _parse_multipart = function(a,b) { throw "Not supported"; };
  354. _flush = function() { };
  355. _log_message = function(s) { };
  356. isTora = false;
  357. }
  358. }
  359. }