Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 7476d8a9f4e30ca74ff7294112b910370920f1b7 @dv committed Oct 18, 2009
Showing with 559 additions and 0 deletions.
  1. +184 −0 HTTPForm.as
  2. +118 −0 MimeFile.as
  3. +50 −0 MimePart.as
  4. +140 −0 MimeString.as
  5. +23 −0 license
  6. +44 −0 readme
184 HTTPForm.as
@@ -0,0 +1,184 @@
+/* HTTPForm Class
+ *
+ * Class HTTPForm fakes a form-submission via POST. Includes support for all INPUT-type arguments.
+ *
+ * (C) David Verhasselt 2006
+ * Licensed under the MIT license
+ */
+
+package crowdway.http
+{
+ import crowdway.http.MimeFile;
+ import crowdway.http.MimePart;
+ import crowdway.http.MimeString;
+
+ import flash.utils.ByteArray;
+ import flash.events.*;
+ import mx.utils.StringUtil;
+
+ import flash.net.*;
+
+
+ /**
+ * Class that implements a method to fake html-form uploads using POST-method. Supports all possible fields and file-uploads.
+ *
+ * @see MimePart
+ * @see MimeFile
+ * @see MimeString
+ */
+ public class HTTPForm implements IEventDispatcher
+ {
+ private const crlf:String = "\r\n";
+
+ // Variables for net-connection
+ private var request:URLRequest;
+ private var loader:URLLoader;
+
+ // Variables for content
+ private var fields:Array;
+
+
+ /**
+ * Generates a random boundary of "length" characters.
+ *
+ * Boundary can exist out of upper-case and lower-case alphanumericals.
+ *
+ * @param length The length of the boundary to be generated
+ * @return The randomly generated boundary
+ */
+ private function generateBoundary(length:Number):String
+ {
+ var boundary:String = new String();
+ var map:Array = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
+ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
+ "0","1","2","3","4","5","6","7","8","9"];
+
+ for (var i:int = length; i > 0; i--)
+ {
+ boundary += map[Math.floor(Math.random()*map.length)];
+ }
+
+ return boundary;
+ }
+
+ /**
+ * Generates the body to be sent to the server
+ *
+ * @param boundary The boundary to be used to split the message-parts
+ * @return All the messages from fields compiled in 1 ByteArray
+ */
+ private function compileBody(boundary:String):ByteArray
+ {
+ var body:ByteArray = new ByteArray();
+
+ body.writeUTFBytes("--" + boundary + crlf);
+
+ for each (var field:MimePart in this.fields)
+ {
+
+ // Add the head of the part
+ body.writeUTFBytes("content-disposition: form-data; name=\"" + field.getName() + "\";");
+
+ if (field.getFilename() != null)
+ {
+ body.writeUTFBytes(" filename=\"" + field.getFilename() + "\";");
+ }
+
+ body.writeUTFBytes(crlf);
+
+ if (field.getHead() != null)
+ {
+ body.writeUTFBytes(field.getHead() + crlf);
+ }
+
+ body.writeUTFBytes(crlf);
+
+ // Add the body and end of the part
+ body.writeBytes(field.getBody());
+ body.writeUTFBytes(crlf + "--" + boundary + crlf);
+ }
+
+ return body;
+ }
+
+
+
+ /**
+ * Creates a new HTTPForm object with "url" being the URL of the destination
+ *
+ * @url The url of the destination
+ */
+ public function HTTPForm(url:String)
+ {
+ this.request = new URLRequest(url);
+ this.loader = new URLLoader();
+
+ this.fields = new Array();
+
+ // Events
+ this.loader.addEventListener(flash.events.Event.COMPLETE, checkComplete);
+ this.loader.addEventListener(flash.events.HTTPStatusEvent.HTTP_STATUS, function():void { trace("Processer - URLLoader.httpStatus"); });
+ this.loader.addEventListener(flash.events.ProgressEvent.PROGRESS, function():void { trace("Processor - URLLoader.progress"); });
+ this.loader.addEventListener(flash.events.IOErrorEvent.IO_ERROR, function(event:Event):void { trace("Procesosr - URLLoader.ioError"); trace(event);});
+ this.loader.addEventListener(flash.events.SecurityErrorEvent.SECURITY_ERROR, function():void { trace("Processor ( URLLoader.securityError"); });
+ }
+
+ private function checkComplete(event:Event):void
+ {
+ trace("Complete");
+ var loader2:URLLoader = URLLoader(event.target);
+ trace("Length: " + loader2.bytesTotal);
+ trace("Data: " + loader2.data);
+ }
+
+ /**
+ * Adds a message-part (an input-field or file) to be sent to the destination to this HTTPForm
+ *
+ * @param field The field to be added
+ */
+ public function addField(field:MimePart):void
+ {
+ this.fields.push(field);
+ }
+
+ /**
+ * Compiles all the fields together, and sends this HTTPForm to the destination specified on creation
+ */
+ public function send():void
+ {
+ var boundary:String = generateBoundary(10);
+
+ this.request.method = URLRequestMethod.POST;
+ this.request.contentType = "multipart/form-data; boundary=\"" + boundary + "\"";
+ this.request.data = this.compileBody(boundary);
+ this.loader.load(request);
+ }
+
+
+ // IEventDispatcher Implementation
+ public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
+ {
+ this.loader.addEventListener(type, listener, useCapture, priority, useWeakReference);
+ }
+
+ public function dispatchEvent(event:Event):Boolean
+ {
+ return this.loader.dispatchEvent(event);
+ }
+
+ public function hasEventListener(type:String):Boolean
+ {
+ return this.loader.hasEventListener(type);
+ }
+
+ public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
+ {
+ return this.loader.removeEventListener(type, listener, useCapture);
+ }
+
+ public function willTrigger(type:String):Boolean
+ {
+ return this.loader.willTrigger(type);
+ }
+ }
+}
118 MimeFile.as
@@ -0,0 +1,118 @@
+/**
+ * MimeFile Class
+ *
+ * (C) David Verhasselt 2007
+ * Licensed under the MIT license
+ */
+package crowdway.http
+{
+ import crowdway.http.MimePart;
+
+ import flash.utils.ByteArray;
+ import flash.events.*;
+ import mx.utils.StringUtil;
+
+ import flash.net.*;
+
+
+ /**
+ * Implements the "file" input-field
+ *
+ * @see MimePart
+ * @see MimeString
+ * @see HTTPForm
+ */
+ public class MimeFile implements MimePart
+ {
+ private static const crlf:String = "\r\n";
+
+ // Content parameters
+ private var name:String;
+ private var fileName:String;
+ private var contentType:String;
+ private var charset:String;
+ private var content:ByteArray;
+
+
+ /**
+ * Factory Method: Creates a text/plain MimeFile with the supplied name, filename, content and optional charset.
+ *
+ * @param name The name of the new MimeFile
+ * @param fileName The filename of the new MimeFile
+ * @param content The content of the new MimeFile
+ * @param charset The optional charset of the content. Defaults to "us-ascii"
+ *
+ * @return A new MimeFile based on the supplied parameters
+ */
+ static public function fromText(name:String,fileName:String,content:String,charset:String = "us-ascii"):MimeFile
+ {
+ var result:MimeFile = new MimeFile();
+
+ result.name = name;
+ result.fileName = fileName;
+ result.contentType = "text/plain";
+ result.content = new ByteArray();
+ result.content.writeMultiByte(content,charset);
+ result.charset = charset;
+
+ return result;
+ }
+
+ /**
+ * Factory Method: Creates a binary MimeFile with the supplied name, filename, content and optional content-type.
+ *
+ * @param name The name of the new MimeFile
+ * @param fileName The filename of the new MimeFile
+ * @param content The content of the new MimeFile
+ * @param contentType The optional content-type of the content. Defaults to "application/octet"
+ *
+ * @return A new MimeFile based on the supplied parameters
+ */
+ static public function fromByteArray(name:String,fileName:String,content:ByteArray,contentType:String = "application/octet-stream"):MimeFile
+ {
+ var result:MimeFile = new MimeFile();
+
+ result.name = name;
+ result.fileName = fileName;
+ result.contentType = contentType + crlf + "Content-Transfer-Encoding: binary";
+ result.content = content;
+
+ return result;
+ }
+
+
+ public function getName():String
+ {
+ return this.name;
+ }
+
+ public function getFilename():String
+ {
+ return this.fileName;
+ }
+
+
+ public function getHead():String
+ {
+ var head:String = "Content-Type: ";
+
+ head += this.contentType;
+
+ if (this.charset != null)
+ {
+ head += "; charset=" + this.charset;
+ }
+
+ return head;
+ }
+
+
+
+ public function getBody():ByteArray
+ {
+ this.content.position = 0;
+ return this.content;
+ }
+
+ }
+}
50 MimePart.as
@@ -0,0 +1,50 @@
+/**
+ * MimePart Class
+ *
+ * (C) David Verhasselt 2007
+ * Licensed under the MIT license
+ */
+package crowdway.http
+{
+ import flash.utils.ByteArray;
+
+ /**
+ * Interface that defines the message parts a HTTPForm is compiled from.
+ *
+ * @see HTTPForm
+ * @see MimeString
+ * @see MimeFile
+ */
+ public interface MimePart
+ {
+ /**
+ * Get the name of this field
+ *
+ * @return The name of this field, for example "age"
+ */
+ function getName():String;
+
+ /**
+ * Get the filename of this field (only for file-types). If there is none or not available, it returns null.
+ *
+ * @return The filename of this file, for example "horse.txt", or null
+ */
+ function getFilename():String;
+
+ /**
+ * Get the head-string of this field, or null if not available.
+ *
+ * A head-string starts with "Content-Type: " and includes the content-type, an optional charset-parameter, and an optional boundary.
+ *
+ * @return The head-string, or null if not available. Does not include the final CRLF
+ */
+ function getHead():String;
+
+ /**
+ * Get the actual content of this field
+ *
+ * @return The content of this field, not including the final CRLF
+ */
+ function getBody():ByteArray;
+ }
+}
140 MimeString.as
@@ -0,0 +1,140 @@
+/**
+ * MimeString Class
+ *
+ * (C) David Verhasselt 2007
+ * Licensed under the MIT license
+ */
+package crowdway.http
+{
+ import crowdway.http.MimePart;
+
+ import flash.utils.ByteArray;
+ import flash.events.*;
+ import mx.utils.StringUtil;
+
+ import flash.net.*;
+
+ /**
+ * Implements any input-field from a form that can be represented as a string
+ *
+ * @see MimePart
+ * @see MimeFile
+ * @see HTTPForm
+ */
+ public class MimeString implements MimePart
+ {
+ private const crlf= "\r\n";
+
+ // Content parameters
+ private var name:String;
+ private var contentType:String;
+ private var charset:String;
+ private var content:String;
+
+ /**
+ * Factory-Method: Creates a new MimeString with the supplied name, content, and optional charset
+ */
+
+ public static function fromString(name:String,content:String,charset:String = null)
+ {
+ var result:MimeString = new MimeString();
+
+ result.name = name;
+ result.setContent(content,charset);
+
+ return result;
+ }
+
+
+ /**
+ * Set the content of this field.
+ *
+ * If charset is set, content-type and charset are populated and the content is written with an extra linebreak at the end, as in this example:
+ * From: Nathaniel Borenstein <nsb@bellcore.com>
+ * To: Ned Freed <ned@innosoft.com>
+ * Subject: Sample message
+ * MIME-Version: 1.0
+ * Content-type: multipart/mixed; boundary="simple boundary"
+ * This is the preamble. It is to be ignored, though it
+ * is a handy place for mail composers to include an
+ * explanatory note to non-MIME compliant readers.
+ * --simple boundary
+ *
+ * This is implicitly typed plain ASCII text.
+ * It does NOT end with a linebreak.
+ * --simple boundary
+ * Content-type: text/plain; charset=us-ascii
+ *
+ * This is explicitly typed plain ASCII text.
+ * It DOES end with a linebreak.
+ *
+ * --simple boundary--
+ * This is the epilogue. It is also to be ignored
+ *
+ * @param content The new content of the field
+ * @param charset The optional charset of the string, if none set, uses default us-ascii
+ */
+ private function setContent(content:String, charset:String = null)
+ {
+ if (charset != null)
+ {
+ this.contentType = "text/plain";
+ this.charset = charset;
+ //this.content.writeMultiByte(content + crlf,charset);
+ this.content = content;
+ }
+
+ else
+ {
+ this.contentType = null;
+ this.charset = null;
+ //this.content.writeMultiByte(content,"us-ascii");
+ this.content = content;
+ }
+ }
+
+
+ public function getName():String
+ {
+ return this.name;
+ }
+
+ public function getFilename():String
+ {
+ return null;
+
+ }
+
+ public function getHead():String
+ {
+ if (this.contentType == null)
+ {
+ return null;
+ }
+
+ else
+ {
+ return "Content-Type: " + this.contentType + "; charset=" + this.charset;
+ }
+ }
+
+ public function getBody():ByteArray
+ {
+ var result:ByteArray = new ByteArray();
+
+ if (this.contentType != null)
+ {
+ result.writeMultiByte(this.content, this.charset);
+ }
+
+ else
+ {
+ result.writeUTFBytes(this.content + crlf);
+ }
+
+ return result;
+ }
+
+ }
+}
+
23 license
@@ -0,0 +1,23 @@
+Copyright (c) 2006 David Verhasselt <david@crowdway.com>
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
44 readme
@@ -0,0 +1,44 @@
+Crowdway.http Actionscript 3 Library
+------------------------------------
+
+This little library helps you create HTTP requests which a server would interpret as true HTML form submissions. It is possible to set the encoding for each field, please check out the source code for specifics.
+
+Put these files in subdirectories ./crowdway/http/ under the root folder of your project, so that the actionscript compiler will be able to reach them.
+
+Example code:
+
+ httpForm = new HTTPForm("http://www.google.com");
+ httpForm.addEventListener(flash.events.Event.COMPLETE, eventCompleteHandler);
+
+ httpForm.addField(MimeString.fromString("name", "David Verhasselt")); // Add field named "name"
+ httpForm.addField(MimeString.fromString("email", "david@crowdway.com")); // Add field named "email"
+ httpForm.addField(MimeFile.fromByteArray("avatar", "david_at_the_beach_07.jpg", filedata)); // Add filefield named "avatar"
+ httpForm.send();
+
+ function eventCompleteHandler(event:Event):void
+ {
+ var loader:URLLoader = URLLoader(event.target);
+ trace(loader.data);
+ }
+
+The code above emulates a form with 3 inputfields:
+
+ - an inputbox named "name" with value "David Verhasselt"
+ - an inputbox named "email" with value "david@crowdway.com"
+ - a fileinput named "avatar" in which the user selected a file named "david_at_the_beach_07.jpg"
+ with contents the ByteArray filedata
+
+It is sent to http://www.google.com. The server at google.com will think it is receiving a form submission with an attached image. The result will be trace()d.
+
+2009 Addendum: The code above works perfectly with Flash 9. However, starting with Flash 10, Adobe has issued some really constrictive security policies which don't really increase security in my opinion. One of them, explained in [1], pertains to any networking call that contains a file upload. Practically, starting with Flash 10, you can send file uploads using httpForm or an alternative only when it is instigated by a user action. For example, only in an onClick eventhandler or a function called by that eventhandler will httpForm.send() work. If you haven't attached a MimeFile with a filename then this restriction doesn't apply.
+
+If you are willing to forgo the server recognizing the file as a fileupload, you can still send the form with the file added as a regular, raw binary inputfield by dismissing the filename:
+
+ httpForm.addField(MimeFile.fromByteArray("avatar", null, filedata));
+
+The server won't recognize it as a file anymore, but the POST-field named "avatar" will still contain the binary filedata.
+
+[1] http://www.adobe.com/devnet/flashplayer/articles/fplayer10_security_changes_print.html#head34
+
+(c) 2006-2009 David Verhasselt <david@crowdway.com>
+Licensed under the MIT license

0 comments on commit 7476d8a

Please sign in to comment.