mas01mj@732: /* mas01mj@732: Copyright (c) 2008, Adobe Systems Incorporated mas01mj@732: All rights reserved. mas01mj@732: mas01mj@732: Redistribution and use in source and binary forms, with or without mas01mj@732: modification, are permitted provided that the following conditions are mas01mj@732: met: mas01mj@732: mas01mj@732: * Redistributions of source code must retain the above copyright notice, mas01mj@732: this list of conditions and the following disclaimer. mas01mj@732: mas01mj@732: * Redistributions in binary form must reproduce the above copyright mas01mj@732: notice, this list of conditions and the following disclaimer in the mas01mj@732: documentation and/or other materials provided with the distribution. mas01mj@732: mas01mj@732: * Neither the name of Adobe Systems Incorporated nor the names of its mas01mj@732: contributors may be used to endorse or promote products derived from mas01mj@732: this software without specific prior written permission. mas01mj@732: mas01mj@732: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS mas01mj@732: IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, mas01mj@732: THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR mas01mj@732: PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR mas01mj@732: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, mas01mj@732: EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, mas01mj@732: PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR mas01mj@732: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF mas01mj@732: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING mas01mj@732: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS mas01mj@732: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. mas01mj@732: */ mas01mj@732: package com.adobe.net.proxies mas01mj@732: { mas01mj@732: import flash.events.Event; mas01mj@732: import flash.events.IOErrorEvent; mas01mj@732: import flash.events.ProgressEvent; mas01mj@732: import flash.net.Socket; mas01mj@732: mas01mj@732: /** mas01mj@732: * This class allows TCP socket connections through HTTP proxies in accordance with mas01mj@732: * RFC 2817: mas01mj@732: * mas01mj@732: * ftp://ftp.rfc-editor.org/in-notes/rfc2817.txt mas01mj@732: * mas01mj@732: * It can also be used to make direct connections to a destination, as well. If you mas01mj@732: * pass the host and port into the constructor, no proxy will be used. You can also mas01mj@732: * call connect, passing in the host and the port, and if you didn't set the proxy mas01mj@732: * info, a direct connection will be made. A proxy is only used after you have called mas01mj@732: * the setProxyInfo function. mas01mj@732: * mas01mj@732: * The connection to and negotiation with the proxy is completely hidden. All the mas01mj@732: * same events are thrown whether you are using a proxy or not, and the data you mas01mj@732: * receive from the target server will look exact as it would if you were connected mas01mj@732: * to it directly rather than through a proxy. mas01mj@732: * mas01mj@732: * @author Christian Cantrell mas01mj@732: * mas01mj@732: **/ mas01mj@732: public class RFC2817Socket mas01mj@732: extends Socket mas01mj@732: { mas01mj@732: private var proxyHost:String = null; mas01mj@732: private var host:String = null; mas01mj@732: private var proxyPort:int = 0; mas01mj@732: private var port:int = 0; mas01mj@732: private var deferredEventHandlers:Object = new Object(); mas01mj@732: private var buffer:String = new String(); mas01mj@732: mas01mj@732: /** mas01mj@732: * Construct a new RFC2817Socket object. If you pass in the host and the port, mas01mj@732: * no proxy will be used. If you want to use a proxy, instantiate with no mas01mj@732: * arguments, call setProxyInfo, then call connect. mas01mj@732: **/ mas01mj@732: public function RFC2817Socket(host:String = null, port:int = 0) mas01mj@732: { mas01mj@732: super(host, port); mas01mj@732: } mas01mj@732: mas01mj@732: /** mas01mj@732: * Set the proxy host and port number. Your connection will only proxied if mas01mj@732: * this function has been called. mas01mj@732: **/ mas01mj@732: public function setProxyInfo(host:String, port:int):void mas01mj@732: { mas01mj@732: this.proxyHost = host; mas01mj@732: this.proxyPort = port; mas01mj@732: mas01mj@732: var deferredSocketDataHandler:Object = this.deferredEventHandlers[ProgressEvent.SOCKET_DATA]; mas01mj@732: var deferredConnectHandler:Object = this.deferredEventHandlers[Event.CONNECT]; mas01mj@732: mas01mj@732: if (deferredSocketDataHandler != null) mas01mj@732: { mas01mj@732: super.removeEventListener(ProgressEvent.SOCKET_DATA, deferredSocketDataHandler.listener, deferredSocketDataHandler.useCapture); mas01mj@732: } mas01mj@732: mas01mj@732: if (deferredConnectHandler != null) mas01mj@732: { mas01mj@732: super.removeEventListener(Event.CONNECT, deferredConnectHandler.listener, deferredConnectHandler.useCapture); mas01mj@732: } mas01mj@732: } mas01mj@732: mas01mj@732: /** mas01mj@732: * Connect to the specified host over the specified port. If you want your mas01mj@732: * connection proxied, call the setProxyInfo function first. mas01mj@732: **/ mas01mj@732: public override function connect(host:String, port:int):void mas01mj@732: { mas01mj@732: if (this.proxyHost == null) mas01mj@732: { mas01mj@732: this.redirectConnectEvent(); mas01mj@732: this.redirectSocketDataEvent(); mas01mj@732: super.connect(host, port); mas01mj@732: } mas01mj@732: else mas01mj@732: { mas01mj@732: this.host = host; mas01mj@732: this.port = port; mas01mj@732: super.addEventListener(Event.CONNECT, this.onConnect); mas01mj@732: super.addEventListener(ProgressEvent.SOCKET_DATA, this.onSocketData); mas01mj@732: super.connect(this.proxyHost, this.proxyPort); mas01mj@732: } mas01mj@732: } mas01mj@732: mas01mj@732: private function onConnect(event:Event):void mas01mj@732: { mas01mj@732: this.writeUTFBytes("CONNECT "+this.host+":"+this.port+" HTTP/1.1\n\n"); mas01mj@732: this.flush(); mas01mj@732: this.redirectConnectEvent(); mas01mj@732: } mas01mj@732: mas01mj@732: private function onSocketData(event:ProgressEvent):void mas01mj@732: { mas01mj@732: while (this.bytesAvailable != 0) mas01mj@732: { mas01mj@732: this.buffer += this.readUTFBytes(1); mas01mj@732: if (this.buffer.search(/\r?\n\r?\n$/) != -1) mas01mj@732: { mas01mj@732: this.checkResponse(event); mas01mj@732: break; mas01mj@732: } mas01mj@732: } mas01mj@732: } mas01mj@732: mas01mj@732: private function checkResponse(event:ProgressEvent):void mas01mj@732: { mas01mj@732: var responseCode:String = this.buffer.substr(this.buffer.indexOf(" ")+1, 3); mas01mj@732: mas01mj@732: if (responseCode.search(/^2/) == -1) mas01mj@732: { mas01mj@732: var ioError:IOErrorEvent = new IOErrorEvent(IOErrorEvent.IO_ERROR); mas01mj@732: ioError.text = "Error connecting to the proxy ["+this.proxyHost+"] on port ["+this.proxyPort+"]: " + this.buffer; mas01mj@732: this.dispatchEvent(ioError); mas01mj@732: } mas01mj@732: else mas01mj@732: { mas01mj@732: this.redirectSocketDataEvent(); mas01mj@732: this.dispatchEvent(new Event(Event.CONNECT)); mas01mj@732: if (this.bytesAvailable > 0) mas01mj@732: { mas01mj@732: this.dispatchEvent(event); mas01mj@732: } mas01mj@732: } mas01mj@732: this.buffer = null; mas01mj@732: } mas01mj@732: mas01mj@732: private function redirectConnectEvent():void mas01mj@732: { mas01mj@732: super.removeEventListener(Event.CONNECT, onConnect); mas01mj@732: var deferredEventHandler:Object = this.deferredEventHandlers[Event.CONNECT]; mas01mj@732: if (deferredEventHandler != null) mas01mj@732: { mas01mj@732: super.addEventListener(Event.CONNECT, deferredEventHandler.listener, deferredEventHandler.useCapture, deferredEventHandler.priority, deferredEventHandler.useWeakReference); mas01mj@732: } mas01mj@732: } mas01mj@732: mas01mj@732: private function redirectSocketDataEvent():void mas01mj@732: { mas01mj@732: super.removeEventListener(ProgressEvent.SOCKET_DATA, onSocketData); mas01mj@732: var deferredEventHandler:Object = this.deferredEventHandlers[ProgressEvent.SOCKET_DATA]; mas01mj@732: if (deferredEventHandler != null) mas01mj@732: { mas01mj@732: super.addEventListener(ProgressEvent.SOCKET_DATA, deferredEventHandler.listener, deferredEventHandler.useCapture, deferredEventHandler.priority, deferredEventHandler.useWeakReference); mas01mj@732: } mas01mj@732: } mas01mj@732: mas01mj@732: public override function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int=0.0, useWeakReference:Boolean=false):void mas01mj@732: { mas01mj@732: if (type == Event.CONNECT || type == ProgressEvent.SOCKET_DATA) mas01mj@732: { mas01mj@732: this.deferredEventHandlers[type] = {listener:listener,useCapture:useCapture, priority:priority, useWeakReference:useWeakReference}; mas01mj@732: } mas01mj@732: else mas01mj@732: { mas01mj@732: super.addEventListener(type, listener, useCapture, priority, useWeakReference); mas01mj@732: } mas01mj@732: } mas01mj@732: } mas01mj@732: }