/** * Usage: * * 1. Create subclass of AbstractGateway as your Gateway. * * class MyGateway extends AbstractGateway * * 2. Override execute method. * * override protected function execute(request:IWebRequest):IWebResponse * * 3. Process the request. * (See also: IWebRequest) * * 4. Create and return instance of IWebResponse. * (See also: IWebResponse, TextResponse, HTMLResponse, ByteArrayResponse) * * See also: * * guestbook.as * amf.as * amf/org/libspark/web/AMFGateway.as * swfassist/org/libspark/web/SWFResponse.as */ package org.libspark.web { import flash.utils.Dictionary; import flash.utils.ByteArray; import avmplus.System; public function htmlescape(value:String):String { return value.replace(/&/g, '&').replace(//g, '>'); } /** * Interface of web request */ public interface IWebRequest { /** * Request method */ function get requestMethod():String; /** * Request content type */ function get contentType():String; /** * Raw query string (not parsed, ex: name=foo&message=bar) */ function get queryString():String; /** * Raw post data (not parsed) */ function get postData():ByteArray; /** * Alias of createParsedQueryString */ function createGetArgs():Object; /** * Alias of createParsedPostData */ function createPostArgs():Object; /** * Returns parsed query string */ function createParsedQueryString():Object; /** * Returns parsed post data */ function createParsedPostData():Object; } internal class WebRequestImpl implements IWebRequest { public function WebRequestImpl(method:String, type:String, queryString:String, postData:ByteArray) { _requestMethod = method; _contentType = type; _queryString = queryString; _postData = postData; } private var _requestMethod:String; private var _contentType:String; private var _queryString:String; private var _postData:ByteArray; public function get requestMethod():String { return _requestMethod; } public function get contentType():String { return _contentType; } public function get queryString():String { return _queryString; } public function get postData():ByteArray { return _postData; } public function createGetArgs():Object { return createParsedQueryString(); } public function createPostArgs():Object { return createParsedPostData(); } public function createParsedQueryString():Object { if (_queryString != null && _queryString.length > 0) { return createArgs(_queryString); } return createArgs(''); } public function createParsedPostData():Object { if (_postData != null && _postData.length > 0) { var pos:uint = _postData.position; _postData.position = 0; var v:String = _postData.readUTFBytes(_postData.length); _postData.position = pos; return createArgs(v); } return createArgs(''); } private function createArgs(value:String):Object { var arg:Dictionary = new Dictionary(); if (value.length > 0) { var kvList:Array = value.split('&'); for each (var kv:String in kvList) { var kva:Array = kv.split('='); if (kva.length == 2) { arg[kva[0]] = unescape(String(kva[1]).replace(/\+/g, ' ')); } } } return arg; } } /** * Interface of web response */ public interface IWebResponse { /** * Display content to standard output. */ function display():void; } /** * Content-type: text/plain; */ public class TextResponse implements IWebResponse { public function TextResponse(contents:String = '') { this.contents = contents; } private var _contents:String; public function get contents():String { return _contents; } public function set contents(value:String):void { _contents = value; } public function display():void { trace('Content-type: text/plain'); trace(''); trace(contents); } } /** * Content-type: text/html; */ public class HTMLResponse implements IWebResponse { /** * @param contents HTML String or XML (if XML is passed, we'll call toXMLString()) */ public function HTMLResponse(contents:Object = null) { this.contents = contents; } private var _contents:Object; public function get contents():Object { return _contents; } public function set contents(value:Object):void { _contents = value; } public function display():void { trace('Content-type: text/html'); trace(''); if (contents != null) { if (contents is XML) { trace((contents as XML).toXMLString()); } else { trace(String(contents)); } } } } /** * Custom content-type */ public class ByteArrayResponse implements IWebResponse { /** * Display given raw bytes as given content type */ public function ByteArrayResponse(bytes:ByteArray = null, type:String = 'application/octet-stream') { this.byteArray = bytes; this.contentType = type; } private var _byteArray:ByteArray; private var _contentType:String; public function get byteArray():ByteArray { return _byteArray; } public function set byteArray(value:ByteArray):void { _byteArray = value; } public function get contentType():String { return _contentType; } public function set contentType(value:String):void { _contentType = value; } public function display():void { trace('Content-type: ' + contentType); trace(''); if (byteArray != null) { byteArray.writeStdout(); } } } public class AbstractWebGateway { private static const REQUEST_METHOD:String = 'REQUEST_METHOD'; private static const CONTENT_TYPE:String = 'CONTENT_TYPE'; private static const CONTENT_LENGTH:String = 'CONTENT_LENGTH'; private static const QUERY_STRING:String = 'QUERY_STRING'; public function AbstractWebGateway() { } public function enter():void { var method:String = System.getEnv(REQUEST_METHOD); var type:String = System.getEnv(CONTENT_TYPE); var cLength:int = int(System.getEnv(CONTENT_LENGTH)); var queryString:String = System.getEnv(QUERY_STRING); var postData:ByteArray = null; if (cLength > 0) { postData = ByteArray.readStdin(cLength); } else { postData = new ByteArray(); } var request:IWebRequest = new WebRequestImpl(method, type, queryString, postData); var response:IWebResponse = execute(request); if (response != null) { response.display(); } else { new TextResponse().display(); } } protected function execute(request:IWebRequest):IWebResponse { return null; } } }