001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.proxy.session;
021
022import java.net.InetSocketAddress;
023import java.nio.charset.Charset;
024import java.util.List;
025
026import org.apache.mina.core.session.IoSession;
027import org.apache.mina.proxy.ProxyConnector;
028import org.apache.mina.proxy.ProxyLogicHandler;
029import org.apache.mina.proxy.event.IoSessionEventQueue;
030import org.apache.mina.proxy.filter.ProxyFilter;
031import org.apache.mina.proxy.handlers.ProxyRequest;
032import org.apache.mina.proxy.handlers.http.HttpAuthenticationMethods;
033import org.apache.mina.proxy.handlers.http.HttpSmartProxyHandler;
034
035/**
036 * ProxyIoSession.java - Class that contains all informations for the current proxy 
037 * authentication session.
038 * 
039 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
040 * @since MINA 2.0.0-M3
041 */
042public class ProxyIoSession {
043
044    public final static String PROXY_SESSION = ProxyConnector.class.getName() + ".ProxySession";
045
046    private final static String DEFAULT_ENCODING = "ISO-8859-1";
047
048    /**
049     * The list contains the authentication methods to use. 
050     * The order in the list is revelant : if first method is available 
051     * then it will be used etc ...
052     */
053    private List<HttpAuthenticationMethods> preferedOrder;
054
055    /**
056     * The request to send to the proxy.
057     */
058    private ProxyRequest request;
059
060    /**
061     * The currently selected proxy handler. 
062     */
063    private ProxyLogicHandler handler;
064
065    /**
066     * Parent {@link ProxyFilter} handling the session.
067     */
068    private ProxyFilter proxyFilter;
069
070    /**
071     * The session.
072     */
073    private IoSession session;
074
075    /**
076     * The proxy connector.
077     */
078    private ProxyConnector connector;
079
080    /**
081     * Address of the proxy server.
082     */
083    private InetSocketAddress proxyAddress = null;
084
085    /**
086     * A flag that indicates that the proxy closed the connection before handshake 
087     * is done. So we need to reconnect to the proxy to continue the handshaking 
088     * process.  
089     */
090    private boolean reconnectionNeeded = false;
091
092    /**
093     * Name of the charset used for string encoding & decoding.
094     */
095    private String charsetName;
096
097    /**
098     * The session event queue.
099     */
100    private IoSessionEventQueue eventQueue = new IoSessionEventQueue(this);
101
102    /**
103     * Set to true when an exception has been thrown or if authentication failed.
104     */
105    private boolean authenticationFailed;
106
107    /**
108     * Constructor.
109     * 
110     * @param proxyAddress the IP address of the proxy server
111     * @param request the proxy request
112     */
113    public ProxyIoSession(InetSocketAddress proxyAddress, ProxyRequest request) {
114        setProxyAddress(proxyAddress);
115        setRequest(request);
116    }
117
118    /**
119     * @return the pending event queue.
120     */
121    public IoSessionEventQueue getEventQueue() {
122        return eventQueue;
123    }
124
125    /**
126     * @return the list of the prefered order for the authentication methods.
127     * This list is used by the {@link HttpSmartProxyHandler} to determine
128     * which authentication mechanism to use first between those accepted by the
129     * proxy server. This list is only used when connecting to an http proxy.
130     */
131    public List<HttpAuthenticationMethods> getPreferedOrder() {
132        return preferedOrder;
133    }
134
135    /**
136     * Sets the ordered list of prefered authentication mechanisms.
137     * 
138     * @param preferedOrder the ordered list
139     */
140    public void setPreferedOrder(List<HttpAuthenticationMethods> preferedOrder) {
141        this.preferedOrder = preferedOrder;
142    }
143
144    /**
145     * @return the {@link ProxyLogicHandler} currently in use.
146     */
147    public ProxyLogicHandler getHandler() {
148        return handler;
149    }
150
151    /**
152     * Sets the {@link ProxyLogicHandler} to use.
153     * 
154     * @param handler the {@link ProxyLogicHandler} instance
155     */
156    public void setHandler(ProxyLogicHandler handler) {
157        this.handler = handler;
158    }
159
160    /**
161     * @return the {@link ProxyFilter}.
162     */
163    public ProxyFilter getProxyFilter() {
164        return proxyFilter;
165    }
166
167    /**
168     * Sets the {@link ProxyFilter}.
169     * Note : Please do not call this method from your code it could result 
170     * in an unexpected behaviour.
171     * 
172     * @param proxyFilter the filter
173     */
174    public void setProxyFilter(ProxyFilter proxyFilter) {
175        this.proxyFilter = proxyFilter;
176    }
177
178    /**
179     * @return the proxy request.
180     */
181    public ProxyRequest getRequest() {
182        return request;
183    }
184
185    /**
186     * Sets the proxy request.
187     * 
188     * @param request the proxy request
189     */
190    private void setRequest(ProxyRequest request) {
191        if (request == null) {
192            throw new IllegalArgumentException("request cannot be null");
193        }
194
195        this.request = request;
196    }
197
198    /**
199     * @return the current {@link IoSession}.
200     */
201    public IoSession getSession() {
202        return session;
203    }
204
205    /**
206     * Sets the {@link IoSession} in use.
207     * Note : Please do not call this method from your code it could result in an
208     * unexpected behaviour.
209     * 
210     * @param session the current io session
211     */
212    public void setSession(IoSession session) {
213        this.session = session;
214    }
215
216    /**
217     * @return the proxy connector.
218     */
219    public ProxyConnector getConnector() {
220        return connector;
221    }
222
223    /**
224     * Sets the connector reference of this proxy session.
225     * Note : Please do not call this method from your code it could result in an
226     * unexpected behaviour.
227     * 
228     * @param connector the proxy connector
229     */
230    public void setConnector(ProxyConnector connector) {
231        this.connector = connector;
232    }
233
234    /**
235     * @return the IP address of the proxy server.
236     */
237    public InetSocketAddress getProxyAddress() {
238        return proxyAddress;
239    }
240
241    /**
242     * Sets the IP address of the proxy server.
243     * 
244     * @param proxyAddress the IP address of the proxy server
245     */
246    private void setProxyAddress(InetSocketAddress proxyAddress) {
247        if (proxyAddress == null) {
248            throw new IllegalArgumentException("proxyAddress object cannot be null");
249        }
250
251        this.proxyAddress = proxyAddress;
252    }
253
254    /**
255     * @return true if the current authentication process is not finished
256     * but the server has closed the connection.
257     */
258    public boolean isReconnectionNeeded() {
259        return reconnectionNeeded;
260    }
261
262    /**
263     * Sets the reconnection needed flag. If set to true, it means that an
264     * authentication process is currently running but the proxy server did not
265     * kept the connection alive. So we need to reconnect to the server to complete
266     * the process.
267     * Note : Please do not call this method from your code it could result in an
268     * unexpected behaviour.
269     * 
270     * @param reconnectionNeeded the value to set the flag to
271     */
272    public void setReconnectionNeeded(boolean reconnectionNeeded) {
273        this.reconnectionNeeded = reconnectionNeeded;
274    }
275
276    /**
277     * @return a charset instance of the in use charset name.
278     */
279    public Charset getCharset() {
280        return Charset.forName(getCharsetName());
281    }
282
283    /**
284     * @return the used charset name or {@link #DEFAULT_ENCODING} if null.
285     */
286    public String getCharsetName() {
287        if (charsetName == null) {
288            charsetName = DEFAULT_ENCODING;
289        }
290
291        return charsetName;
292    }
293
294    /**
295     * Sets the charset to use.
296     * 
297     * @param charsetName the charset name
298     */
299    public void setCharsetName(String charsetName) {
300        this.charsetName = charsetName;
301    }
302
303    /**
304     * @return true if authentication failed.
305     */
306    public boolean isAuthenticationFailed() {
307        return authenticationFailed;
308    }
309
310    /**
311     * Sets the authentication failed flag.
312     * 
313     * @param authenticationFailed the value to set the flag to
314     */
315    public void setAuthenticationFailed(boolean authenticationFailed) {
316        this.authenticationFailed = authenticationFailed;
317    }
318}