mas01mj@732
|
1 /*
|
mas01mj@732
|
2 Copyright (c) 2008, Adobe Systems Incorporated
|
mas01mj@732
|
3 All rights reserved.
|
mas01mj@732
|
4
|
mas01mj@732
|
5 Redistribution and use in source and binary forms, with or without
|
mas01mj@732
|
6 modification, are permitted provided that the following conditions are
|
mas01mj@732
|
7 met:
|
mas01mj@732
|
8
|
mas01mj@732
|
9 * Redistributions of source code must retain the above copyright notice,
|
mas01mj@732
|
10 this list of conditions and the following disclaimer.
|
mas01mj@732
|
11
|
mas01mj@732
|
12 * Redistributions in binary form must reproduce the above copyright
|
mas01mj@732
|
13 notice, this list of conditions and the following disclaimer in the
|
mas01mj@732
|
14 documentation and/or other materials provided with the distribution.
|
mas01mj@732
|
15
|
mas01mj@732
|
16 * Neither the name of Adobe Systems Incorporated nor the names of its
|
mas01mj@732
|
17 contributors may be used to endorse or promote products derived from
|
mas01mj@732
|
18 this software without specific prior written permission.
|
mas01mj@732
|
19
|
mas01mj@732
|
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
mas01mj@732
|
21 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
mas01mj@732
|
22 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
mas01mj@732
|
23 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
mas01mj@732
|
24 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
mas01mj@732
|
25 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
mas01mj@732
|
26 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
mas01mj@732
|
27 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
mas01mj@732
|
28 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
mas01mj@732
|
29 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
mas01mj@732
|
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
mas01mj@732
|
31 */
|
mas01mj@732
|
32 package com.adobe.net.proxies
|
mas01mj@732
|
33 {
|
mas01mj@732
|
34 import flash.events.Event;
|
mas01mj@732
|
35 import flash.events.IOErrorEvent;
|
mas01mj@732
|
36 import flash.events.ProgressEvent;
|
mas01mj@732
|
37 import flash.net.Socket;
|
mas01mj@732
|
38
|
mas01mj@732
|
39 /**
|
mas01mj@732
|
40 * This class allows TCP socket connections through HTTP proxies in accordance with
|
mas01mj@732
|
41 * RFC 2817:
|
mas01mj@732
|
42 *
|
mas01mj@732
|
43 * ftp://ftp.rfc-editor.org/in-notes/rfc2817.txt
|
mas01mj@732
|
44 *
|
mas01mj@732
|
45 * It can also be used to make direct connections to a destination, as well. If you
|
mas01mj@732
|
46 * pass the host and port into the constructor, no proxy will be used. You can also
|
mas01mj@732
|
47 * call connect, passing in the host and the port, and if you didn't set the proxy
|
mas01mj@732
|
48 * info, a direct connection will be made. A proxy is only used after you have called
|
mas01mj@732
|
49 * the setProxyInfo function.
|
mas01mj@732
|
50 *
|
mas01mj@732
|
51 * The connection to and negotiation with the proxy is completely hidden. All the
|
mas01mj@732
|
52 * same events are thrown whether you are using a proxy or not, and the data you
|
mas01mj@732
|
53 * receive from the target server will look exact as it would if you were connected
|
mas01mj@732
|
54 * to it directly rather than through a proxy.
|
mas01mj@732
|
55 *
|
mas01mj@732
|
56 * @author Christian Cantrell
|
mas01mj@732
|
57 *
|
mas01mj@732
|
58 **/
|
mas01mj@732
|
59 public class RFC2817Socket
|
mas01mj@732
|
60 extends Socket
|
mas01mj@732
|
61 {
|
mas01mj@732
|
62 private var proxyHost:String = null;
|
mas01mj@732
|
63 private var host:String = null;
|
mas01mj@732
|
64 private var proxyPort:int = 0;
|
mas01mj@732
|
65 private var port:int = 0;
|
mas01mj@732
|
66 private var deferredEventHandlers:Object = new Object();
|
mas01mj@732
|
67 private var buffer:String = new String();
|
mas01mj@732
|
68
|
mas01mj@732
|
69 /**
|
mas01mj@732
|
70 * Construct a new RFC2817Socket object. If you pass in the host and the port,
|
mas01mj@732
|
71 * no proxy will be used. If you want to use a proxy, instantiate with no
|
mas01mj@732
|
72 * arguments, call setProxyInfo, then call connect.
|
mas01mj@732
|
73 **/
|
mas01mj@732
|
74 public function RFC2817Socket(host:String = null, port:int = 0)
|
mas01mj@732
|
75 {
|
mas01mj@732
|
76 super(host, port);
|
mas01mj@732
|
77 }
|
mas01mj@732
|
78
|
mas01mj@732
|
79 /**
|
mas01mj@732
|
80 * Set the proxy host and port number. Your connection will only proxied if
|
mas01mj@732
|
81 * this function has been called.
|
mas01mj@732
|
82 **/
|
mas01mj@732
|
83 public function setProxyInfo(host:String, port:int):void
|
mas01mj@732
|
84 {
|
mas01mj@732
|
85 this.proxyHost = host;
|
mas01mj@732
|
86 this.proxyPort = port;
|
mas01mj@732
|
87
|
mas01mj@732
|
88 var deferredSocketDataHandler:Object = this.deferredEventHandlers[ProgressEvent.SOCKET_DATA];
|
mas01mj@732
|
89 var deferredConnectHandler:Object = this.deferredEventHandlers[Event.CONNECT];
|
mas01mj@732
|
90
|
mas01mj@732
|
91 if (deferredSocketDataHandler != null)
|
mas01mj@732
|
92 {
|
mas01mj@732
|
93 super.removeEventListener(ProgressEvent.SOCKET_DATA, deferredSocketDataHandler.listener, deferredSocketDataHandler.useCapture);
|
mas01mj@732
|
94 }
|
mas01mj@732
|
95
|
mas01mj@732
|
96 if (deferredConnectHandler != null)
|
mas01mj@732
|
97 {
|
mas01mj@732
|
98 super.removeEventListener(Event.CONNECT, deferredConnectHandler.listener, deferredConnectHandler.useCapture);
|
mas01mj@732
|
99 }
|
mas01mj@732
|
100 }
|
mas01mj@732
|
101
|
mas01mj@732
|
102 /**
|
mas01mj@732
|
103 * Connect to the specified host over the specified port. If you want your
|
mas01mj@732
|
104 * connection proxied, call the setProxyInfo function first.
|
mas01mj@732
|
105 **/
|
mas01mj@732
|
106 public override function connect(host:String, port:int):void
|
mas01mj@732
|
107 {
|
mas01mj@732
|
108 if (this.proxyHost == null)
|
mas01mj@732
|
109 {
|
mas01mj@732
|
110 this.redirectConnectEvent();
|
mas01mj@732
|
111 this.redirectSocketDataEvent();
|
mas01mj@732
|
112 super.connect(host, port);
|
mas01mj@732
|
113 }
|
mas01mj@732
|
114 else
|
mas01mj@732
|
115 {
|
mas01mj@732
|
116 this.host = host;
|
mas01mj@732
|
117 this.port = port;
|
mas01mj@732
|
118 super.addEventListener(Event.CONNECT, this.onConnect);
|
mas01mj@732
|
119 super.addEventListener(ProgressEvent.SOCKET_DATA, this.onSocketData);
|
mas01mj@732
|
120 super.connect(this.proxyHost, this.proxyPort);
|
mas01mj@732
|
121 }
|
mas01mj@732
|
122 }
|
mas01mj@732
|
123
|
mas01mj@732
|
124 private function onConnect(event:Event):void
|
mas01mj@732
|
125 {
|
mas01mj@732
|
126 this.writeUTFBytes("CONNECT "+this.host+":"+this.port+" HTTP/1.1\n\n");
|
mas01mj@732
|
127 this.flush();
|
mas01mj@732
|
128 this.redirectConnectEvent();
|
mas01mj@732
|
129 }
|
mas01mj@732
|
130
|
mas01mj@732
|
131 private function onSocketData(event:ProgressEvent):void
|
mas01mj@732
|
132 {
|
mas01mj@732
|
133 while (this.bytesAvailable != 0)
|
mas01mj@732
|
134 {
|
mas01mj@732
|
135 this.buffer += this.readUTFBytes(1);
|
mas01mj@732
|
136 if (this.buffer.search(/\r?\n\r?\n$/) != -1)
|
mas01mj@732
|
137 {
|
mas01mj@732
|
138 this.checkResponse(event);
|
mas01mj@732
|
139 break;
|
mas01mj@732
|
140 }
|
mas01mj@732
|
141 }
|
mas01mj@732
|
142 }
|
mas01mj@732
|
143
|
mas01mj@732
|
144 private function checkResponse(event:ProgressEvent):void
|
mas01mj@732
|
145 {
|
mas01mj@732
|
146 var responseCode:String = this.buffer.substr(this.buffer.indexOf(" ")+1, 3);
|
mas01mj@732
|
147
|
mas01mj@732
|
148 if (responseCode.search(/^2/) == -1)
|
mas01mj@732
|
149 {
|
mas01mj@732
|
150 var ioError:IOErrorEvent = new IOErrorEvent(IOErrorEvent.IO_ERROR);
|
mas01mj@732
|
151 ioError.text = "Error connecting to the proxy ["+this.proxyHost+"] on port ["+this.proxyPort+"]: " + this.buffer;
|
mas01mj@732
|
152 this.dispatchEvent(ioError);
|
mas01mj@732
|
153 }
|
mas01mj@732
|
154 else
|
mas01mj@732
|
155 {
|
mas01mj@732
|
156 this.redirectSocketDataEvent();
|
mas01mj@732
|
157 this.dispatchEvent(new Event(Event.CONNECT));
|
mas01mj@732
|
158 if (this.bytesAvailable > 0)
|
mas01mj@732
|
159 {
|
mas01mj@732
|
160 this.dispatchEvent(event);
|
mas01mj@732
|
161 }
|
mas01mj@732
|
162 }
|
mas01mj@732
|
163 this.buffer = null;
|
mas01mj@732
|
164 }
|
mas01mj@732
|
165
|
mas01mj@732
|
166 private function redirectConnectEvent():void
|
mas01mj@732
|
167 {
|
mas01mj@732
|
168 super.removeEventListener(Event.CONNECT, onConnect);
|
mas01mj@732
|
169 var deferredEventHandler:Object = this.deferredEventHandlers[Event.CONNECT];
|
mas01mj@732
|
170 if (deferredEventHandler != null)
|
mas01mj@732
|
171 {
|
mas01mj@732
|
172 super.addEventListener(Event.CONNECT, deferredEventHandler.listener, deferredEventHandler.useCapture, deferredEventHandler.priority, deferredEventHandler.useWeakReference);
|
mas01mj@732
|
173 }
|
mas01mj@732
|
174 }
|
mas01mj@732
|
175
|
mas01mj@732
|
176 private function redirectSocketDataEvent():void
|
mas01mj@732
|
177 {
|
mas01mj@732
|
178 super.removeEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
|
mas01mj@732
|
179 var deferredEventHandler:Object = this.deferredEventHandlers[ProgressEvent.SOCKET_DATA];
|
mas01mj@732
|
180 if (deferredEventHandler != null)
|
mas01mj@732
|
181 {
|
mas01mj@732
|
182 super.addEventListener(ProgressEvent.SOCKET_DATA, deferredEventHandler.listener, deferredEventHandler.useCapture, deferredEventHandler.priority, deferredEventHandler.useWeakReference);
|
mas01mj@732
|
183 }
|
mas01mj@732
|
184 }
|
mas01mj@732
|
185
|
mas01mj@732
|
186 public override function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int=0.0, useWeakReference:Boolean=false):void
|
mas01mj@732
|
187 {
|
mas01mj@732
|
188 if (type == Event.CONNECT || type == ProgressEvent.SOCKET_DATA)
|
mas01mj@732
|
189 {
|
mas01mj@732
|
190 this.deferredEventHandlers[type] = {listener:listener,useCapture:useCapture, priority:priority, useWeakReference:useWeakReference};
|
mas01mj@732
|
191 }
|
mas01mj@732
|
192 else
|
mas01mj@732
|
193 {
|
mas01mj@732
|
194 super.addEventListener(type, listener, useCapture, priority, useWeakReference);
|
mas01mj@732
|
195 }
|
mas01mj@732
|
196 }
|
mas01mj@732
|
197 }
|
mas01mj@732
|
198 } |