How do you read and write http headers in ActionScript? - actionscript-3

Is it even possible to both read and write http headers in actionscript?

Hmm... ok setting them doesn't seem to be a problem.
Pretty straight forward, you just add and array of URLRequestHeader objects to the URLRequest object.
var req:URLRequest = new URLRequest();
var someheader:URLRequestHeader = new URLRequestHeader( "Connection", "OK" );
req.requestHeaders = [someheader];
However, you can't read them in the regular FlashPlayer. This can be done in AIR and Flash Lite on using the requestHeader property on the HTTPStatusEvent.
var loader:URLLoader = new URLLoader();
loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onStatus);
private function onStatus( e:HTTPStatusEvent ) : void
{
var headers:Array = e.requestHeaders; // only available in FlashLite and AIR
}
This is kinda weird.

Related

getting POST using URLRequest + if statement syntax issue

I'm trying to get the reply from the address specified in var url:String, which is either 0 or 1. If the reply is 1 then it must set currentState = CallFailed (as seen below). The client compiles without error (using Adobe Flash Builder 4.6) and seems to successfully reach var url:String, but doesn't seem to be getting the response\and or my if statement is incorrect.
Actionscript:
// check to see if block.php replies 0 or 1
var url:String = "https://domain.com/block.php?postid=" + calleeInput.text + "";
var request:URLRequest = new URLRequest(url);
var variables:URLVariables = new URLVariables();
request.data = variables;
request.method = URLRequestMethod.POST;
navigateToURL(request);
if (request.data == 1)
{
// if reply is 1 then cancel the call
currentState = CallFailed;
return;
}
PHP:
PHP will echo 0 or 1 when block.php is loaded. It's not encoded in any format such as JSON\AJAX.
It seems you want data from the server. Perhaps the URLLoader class would be better?
var url:String = "https://domain.com/block.php?postid=" + calleeInput.text + "";
var request:URLRequest = new URLRequest(url);
var variables:URLVariables = new URLVariables();
request.data = variables;
request.method = URLRequestMethod.POST;
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.addEventListener( Event.COMPLETE,
function( e:Event ) : void
{
// your response data will be here
// you'll have to verify the format
trace( e.target.data );
}
)
loader.load( request );
Put a breakpoint at the trace statement and check out the contents of e.target.data, and go from there
The purpose of navigateToURL() is to open the webbrowser, as stated in its documentation:
Opens or replaces a window in the application that contains the Flash Player container (usually a browser). In Adobe AIR, the function opens a URL in the default system web browser
In order to perform an request (without opening a browser, just the HTTP communication) you should use URLLoader.
The URLLoader class downloads data from a URL as text, binary data, or URL-encoded variables.
On a related note: your logic is not valid. The call to a server is asynchronous. You have to wait for the response to be returned before reasoning about the result.
The URLLoader class dispatches a number of Events that help you decide when the result of a request is returned or if there's a problem with it.

AS3 won't send POST data to browser - wrong URLRequestHeader content type?

I have the following code in my AS3 Flash code that takes a screenshot within the swf using JPGEncoder and sends it to the url where i write it to a file in PHP.
I did run into the Google Chrome Pepperflash issue recently where the function just stops and the page fails to redirect. Nothing gets sent to save.php. By changing
var header:URLRequestHeader = new URLRequestHeader ("Content-type", "application/octet-stream");
to
var header:URLRequestHeader = new URLRequestHeader ("Content-type", "text/plain");
That seemed to do the trick. As of today though this works in internet Explorer but no longer in Chrome, Safari, Firefox. I saw that Adobe put out an update/patch to flash and flash player yesterday - could that have anything to do with it?
If i remove the following:
var header:URLRequestHeader = new URLRequestHeader ("Content-type", "text/plain");
jpgURLRequest.requestHeaders.push(header);
Then the page successfully redirects but $GLOBALS['HTTP_RAW_POST_DATA'] is then empty so no image file can be created.
Is there an alternative header i can put that will solve this?
My code is:
AS3:
function createJPG(m:MovieClip, q:Number, fileName:String) {
var jpgSource:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
jpgSource.draw(stage);
var jpgScreenshot: BitmapData = new BitmapData(362, 310);
jpgScreenshot.copyPixels(jpgSource, new Rectangle(288, 89, 362, 310), new Point(0, 0));
var jpgEncoder:JPGEncoder = new JPGEncoder(q);
var jpgStream:ByteArray = jpgEncoder.encode(jpgScreenshot);
var header:URLRequestHeader = new URLRequestHeader ("Content-type", "text/plain");
var jpgURLRequest:URLRequest = new URLRequest ("http://www.url.com/save.php");
jpgURLRequest.requestHeaders.push(header);
jpgURLRequest.method = URLRequestMethod.POST;
jpgURLRequest.data = jpgStream;
var jpgURLLoader:URLLoader = new URLLoader();
navigateToURL(jpgURLRequest, "_self");
}
save.php
$imagefile=''.$imageURL.'';
$fp = fopen($imagefile, 'wb');
fwrite($fp, $GLOBALS['HTTP_RAW_POST_DATA']);
fclose($fp);
header('Location: https://www.url.com/your-image.php');
Managed to get this working now with the following code. Liam was correct on the Flash Player issue. Working now by separating saving the image and navigating to the url into 2 differents function:
function createJPG(m:MovieClip, q:Number, fileName:String) {
var jpgSource:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
jpgSource.draw(stage);
var jpgScreenshot: BitmapData = new BitmapData(362, 310);
jpgScreenshot.copyPixels(jpgSource, new Rectangle(288, 89, 362, 310), new Point(0, 0));
var jpgEncoder:JPGEncoder = new JPGEncoder(q);
var jpgStream:ByteArray = jpgEncoder.encode(jpgScreenshot);
var urlLoader:URLLoader = new URLLoader();
var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var saveJPG:URLRequest = new URLRequest('http://www.url.com/save_image.php?name=filename';
saveJPG.requestHeaders.push(header);
saveJPG.method = URLRequestMethod.POST;
saveJPG.data = jpgStream;
urlLoader.addEventListener(Event.COMPLETE, goToCheckout);
urlLoader.load(saveJPG);
}
function goToCheckout(e:Event):void{
var url:String = 'http://www.url.com/show_image.php';
var request:URLRequest = new URLRequest(url);
try {
navigateToURL(request, '_self');
} catch (e:Error) {
trace("Error occurred!:");
}
}
save_image.php:
if(isset($GLOBALS["HTTP_RAW_POST_DATA"])){
$jpg = $GLOBALS["HTTP_RAW_POST_DATA"];
$path = "";
$id = $_GET["name"];
$file = $id;
file_put_contents($path.$file, $jpg);
echo "complete";
} else{
// error
}
Flash Player version 13.0.0.214 introduces some key security fixes. Unfortunately it also breaks navigateToUrl() by forbidding the changing of any headers in the request given to navigateToUrl(). This breaks POST requests that need to pass in security/session token headers, or to even change the Content-Type, e.g. to text/xml, etc. as you have done in your example.
Right now, as much as it sucks, our best known workaround is to downgrade clients to 13.0.0.206
Adobe proposes using external interface call as described here: https://forums.adobe.com/message/6396080
it uses JavaScript to replace the POST method
The solution proposed by odd_duck seems simpler though - would be great to see the php code as well.

AS3 send flashvar to self on navigateToURL

This is how i'm handling html flash vars:
var flashVars:Object = new Object();
flashVars = this.loaderInfo.parameters;
for (var item:String in flashVars)
{
switch (item)
{
case "phoneNumber" :
phoneNum = String(flashVars[item]);
break;
}
}
A little verbose for only one var, but i like to be flexible to change later on in the project..
anyways, it was more efficient to compose a quick reset function that simply reloads the swf than it would be to compose a matrix of properties for objects that i'm manipulating within the swf; thus, I'm using the following code:
function reset(){
var url = stage.loaderInfo.url;
var request = new URLRequest(url);
navigateToURL(request,"_level0");
}
What I need to do is pass the flashvars from the flashVars object to the request var and i think having a fever is making me over think this... anyone done this before?
You can just pass the flashvars data object to the data property of your URLRequest:
var url = stage.loaderInfo.url;
var request = new URLRequest(url);
request.data = stage.loaderInfo.parameters
navigateToURL(request,"_level0");

loading images and video in AIR without HTTP

I'm curious what the correct methodology is for loading image and video data directly from the file system, without employing HTTP.
I'm writing an AIR slideshow application, and it works great but currently relies on a local MAMP server to hand the app all the media via the standard, tried and true, FLASH media loading methodologies.
I know that since FLASH was developed as a web plugin it handles this way of receiving data best, but I'd really like to extricate this rather onerous and unnecessary bit and have the app as a stand-alone player, however, I'm unclear what the "correct" way is to load the media.
I have the File objects ready and I've gotten as far as having the user select the local directory from which to pull the media and I'm getting a list of the files (based on their extensions) from the list... but now what?
You first have to put the content of your file in a ByteArray (code from FileStream documentation)
var bytes:ByteArray = new ByteArray();
var myFileStream:FileStream = new FileStream();
var myFile:File = File.documentsDirectory.resolvePath("test.jpg");
myFileStream.addEventListener(ProgressEvent.PROGRESS, progressHandler);
myFileStream.openAsync(myFile, FileMode.READ);
function progressHandler(event:ProgressEvent):void
{
if (myFileStream.bytesAvailable)
{
myFileStream.readBytes(bytes, myFileStream.position, myFileStream.bytesAvailable);
}
else
{
myFileStream.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
loadImage();
}
}
Then you may load these bytes in a Loader to display the image (see method Loader.loadBytes)
function loadImage():void
{
var loader:Loader = new Loader();
loader.loadBytes(bytes);
addChild(loader);
}
Cheers
With this code the Loader fires the Event.COMPLTE event and you will be able to manipulate the Bitmap from it:
var bytes:ByteArray = new ByteArray();
var myFileStream:FileStream = new FileStream();
var myFile:File = File.documentsDirectory.resolvePath(YOUR_PATH);
myFileStream.addEventListener(Event.COMPLETE, fileCompleteHandler)
myFileStream.openAsync(myFile, FileMode.READ);
function fileCompleteHandler(event:Event):void
{
myFileStream.readBytes(bytes);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
loader.loadBytes(bytes);
function imageLoaded(e:Event):void
{
addChild(Bitmap(loader.content));
myFileStream.removeEventListener(Event.COMPLETE, fileCompleteHandler);
myFileStream.close();
}
}
PS: Thanks Kodiak, I made my code based on yours.

AS3 ByteArray " The supplied index is out of bounds" Error

I'm working on an application and I need to save an AS3 object to a db.
Here's what I'm doing:
private function getComplete(e:Event)
{
var getVars:URLVariables = new URLVariables(unescape(e.target.data));
var _saveData_obj = readObjectFromStringBytes( getVars.saveData);
// do something with the save data....
}
public function SaveGame() {
var _save_data:Object = _puzzle.dataForSaving;
var _serialized_string = escape(serializeToString(_save_data));
var _round_time = Math.round( _elapsed_time);
var _token = MD5.hash( _id +
_difficulty +
"mysomewhatsecretstringhere" +
_round_time );
var request:URLRequest =
new URLRequest( _home + 'savegame.php' );
request.method = URLRequestMethod.POST;
var variables:URLVariables = new URLVariables();
variables.saveData = _serialized_string;
variables.time = _round_time;
variables.id = _id;
variables.dif = _difficulty;
variables.token = _token;
request.data = variables;
var loader:URLLoader = new URLLoader (request);
loader.addEventListener(Event.COMPLETE, postComplete);
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.load(request);
}
public function LoadGame() {
var request:URLRequest =
new URLRequest( _home + 'loadgame.php?id='+_id+"&dif="+_difficulty);
request.method = URLRequestMethod.GET;
var loader:URLLoader = new URLLoader (request);
loader.addEventListener(Event.COMPLETE, getComplete);
loader.addEventListener(IOErrorEvent.IO_ERROR, netError);
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.load(request);
}
public static function serializeToString(value:Object):String{
if(value==null){
throw new Error("null isn't a legal serialization candidate");
}
var bytes:ByteArray = new ByteArray();
bytes.writeObject(value);
bytes.position = 0;
trace ("Saved: "+bytes.length);
var be:String = Base64.encodeByteArray(bytes);
return be;
}
public static function readObjectFromStringBytes(value:String):Object {
var result:ByteArray=Base64.decodeToByteArray( value) as ByteArray;
result.position = 0;
var the_obj:Object = result.readObject();
return the_obj
}
The problem is that I keep getting a "The supplied index is out of bounds" error when I try to read the object from the Base64 string.... I checked if the saved string and the loaded string are the same. Tried to save the Base64 string to a shared object and retrieve it - that works fine ... the only problem is when I save and load to/from the server.
Can you guys help me? What am I doing wrong?
Thanks.
try using ba.writeMultiByte(string, 'utf-8') and ba.readMultiByte(ba.bytesAvailable, 'utf-8') without converting to object
Ok, so it looks like we've come to a series of steps you can take to debug what's going on.
(In save game) make sure that unescape( variables ).saveData == _puzzle.dataForSaving. If this does not work, then your issue is with either escape or unescape. I have to admit
I am suspicious here, you should never need to escape data for a POST once it has been Base64 encoded (as3crypto's Base 64 encoding will return only one of these characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=. Those are all legit in a POST) and your URLLoader should take care of making it a legit request, so I have difficulty seeing the need.
It is more consistent (and more expected) to have escape and unescape both accept strings as parameters and return strings.
Instead of storing to the database and then retrieving, store to $_SESSION (or, if possible, just echo the value back). This will eliminate PHP as a possible culprit.
In PHP, make sure that $_POST['saveData'] == /* whatever you echo */. If it isn't, then you have a DB encoding issue. You need to make sure that whatever encoding is used in MySQL is the same as the one used in AS.
As an aside, when working with AS, you'll often find it easier to use $_REQUEST instead of $_POST or $_GET. Since the requests are more or less abstracted, the URLRequests of AS don't really need to worry about being RESTful, and it is a heck of a lot easier to work with than exclusively using POSTs.