001    /*
002     * Copyright 1999-2002,2004 The Apache Software Foundation.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.apache.commons.latka.http;
018    
019    import java.net.URL;
020    import java.util.LinkedList;
021    
022    import org.apache.commons.httpclient.HttpState;
023    import org.apache.commons.httpclient.Cookie;
024    
025    /**
026     * An implementation of a Latka Session interface based on the Apache Commons 
027     * HttpClient package.
028     *
029     * @todo accept proxy details on create request
030     * @todo fix interface to match proxy details
031     * @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
032     * @author <a href="mailto:mdelagra@us.britannica.com">Morgan Delagrange</a>
033     * @author dIon Gillard
034     * @version $Id: SessionImpl.java 561366 2007-07-31 15:58:29Z rahul $
035     */
036    public class SessionImpl implements Session {
037    
038      /** 
039       * tracks URLs treated by this session
040       * Session will automatically set the referer
041       * header for a request to the URL of the
042       * previous request
043       */
044      protected LinkedList _urls = new LinkedList();
045    
046      /**
047       * this state object 'belongs' to HttpClient
048       * we maintain a reference in SessionImpl for
049       * simplicity
050       */
051      protected HttpState      _state = new HttpState();
052    
053      ///////////////////////////////
054      // Session Interface Methods //
055      ///////////////////////////////
056    
057      /**
058       * Creates a request object with the specified URL, HTTP Method,
059       * and version.
060       *
061       * @param url        The URL to request of the HTTP server.
062       * @param httpMethod An integer representing the HTTP method (e.g. GET, PUT)
063       *        used to communicate with server.
064       * @param version A String representing the version of the HTTP request, i.e.
065       *        1.0 or 1.1.
066       * @return a new <code>Request</code> object representing the <code>url</code>
067       *        and <code>httpMethod</code>
068       * @see org.apache.commons.latka.http.Request#HTTP_METHOD_GET
069       * @see org.apache.commons.latka.http.Request#HTTP_METHOD_POST
070       */
071      public Request createRequest(URL url, int httpMethod, String version) {
072            // default label to null, follow redirects to true and proxy to null
073            return createRequest(null, url, httpMethod, version, true, null);
074      }
075    
076      /**
077       * Creates a labeled request object with the specified URL, HTTP Method, 
078       * version, and redirect handling behavior.
079       *
080       * Note: in the current implementation, old request objects will not be resued. 
081       * 
082       * @param label  Name of the request
083       * @param url        The URL to request of the HTTP server.
084       * @param httpMethod An integer representing the HTTP method (e.g. GET, PUT)
085       *        used to communicate with server.
086       * @param version A String representing the version of the HTTP request, i.e.
087       *        1.0 or 1.1.
088       * @param followRedirects whether HTTP redirects should be processed
089       * @return a new <code>Request</code> object representing the <code>url</code>
090       *        and <code>httpMethod</code>
091       * @see org.apache.commons.latka.http.Request#HTTP_METHOD_GET
092       * @see org.apache.commons.latka.http.Request#HTTP_METHOD_POST
093       */
094      public Request createRequest(String label, URL url, int httpMethod, 
095        String version, boolean followRedirects) {
096          // default proxy to null
097          return createRequest(label, url, httpMethod, version, followRedirects, null);
098      }
099    
100        /**
101         * Creates a request object with the specified URL, HTTP Method, and
102         * version to be accessed via the provided proxy.
103         * 
104         * @param url        The URL to request of the HTTP server.
105         * @param httpMethod An integer representing the HTTP method (e.g. GET, PUT)
106         *      used to communicate with server.
107         * @param version A String representing the version of the HTTP request, i.e.
108         *      1.0 or 1.1.
109         * @return a new {@link Request} object representing the <code>url</code>
110         *      and <code>httpMethod</code>
111         * @param proxy a proxy to use during the request
112         * @see org.apache.commons.latka.http.Request#HTTP_METHOD_GET
113         * @see org.apache.commons.latka.http.Request#HTTP_METHOD_POST
114         * @see org.apache.commons.latka.http.Proxy
115         */
116        public Request createRequest(URL url, int httpMethod, Proxy proxy, String version) {
117            // default label to null, and follow redirects to true
118            return createRequest(null, url, httpMethod, version, true, proxy);
119        }
120    
121        /** 
122         * Create a labeled request , with the specified URL, HTTP method, version, and 
123         * redirect handling behavior, using the given proxy for communications.
124         *
125         * @param label a name used to identify the request
126         * @param url The URL to request of the HTTP server.
127         * @param httpMethod An integer representing the HTTP method (e.g. GET, PUT)
128         *      used to communicate with server.
129         * @param version A String representing the version of the HTTP request, i.e.
130         *      1.0 or 1.1.
131         * @param followRedirects whether to follow HTTP redirection responses
132         * @param proxy a proxy to use during the request
133         * @return a new {@link Request} object representing the <code>url</code>
134         *      and <code>httpMethod</code>.
135         * @see org.apache.commons.latka.http.Request#HTTP_METHOD_GET
136         * @see org.apache.commons.latka.http.Request#HTTP_METHOD_POST
137         * @see org.apache.commons.latka.http.Proxy
138         */
139        public Request createRequest(String label, URL url, int httpMethod,
140            String version, boolean followRedirects, Proxy proxy) {
141        
142            RequestImpl request = new RequestImpl(label, url, httpMethod, _state, 
143                this, followRedirects);
144            request.setProxy(proxy);
145            request.setVersion(version);
146    
147            URL referer = getReferer();
148    
149            if (referer != null) {
150              request.addHeader("Referer", referer.toString());
151            }
152    
153            return request;
154    
155        }
156    
157      /**
158       * Called inside the request.execute() method, setting the
159       * referer for the next request.
160       * 
161       * @param url    URL of the last executed request.
162       */
163      protected void setReferer(URL url) {
164        _urls.add(url);
165      }
166    
167      /**
168       * The URL of the last request that was executed.  This
169       * will be the _actual_ url accessed in the result of 
170       * a 301 or 302 redirect (the page that returned
171       * a 200 status code).
172       * 
173       * @return Referer of the last request, or null if there have
174       *         been no successful requests.
175       */
176      protected URL getReferer() {
177        if (_urls.size() > 0) {
178          return (URL) _urls.getLast();
179        }
180    
181        return null;
182      }
183    
184      /**
185       * Adds a cookie to all HTTP requests whose domain and path match (according 
186       * to RFC2109).
187       *
188       * @param domain  the domain to which the cookie should apply
189       * @param path    the path to which the cookie should apply
190       * @param name    the name of the cookie
191       * @param value   the value of the cookie
192       */
193      public void addCookie(String domain, String path,
194                            String name, String value) {
195    
196        Cookie cookie = new Cookie(domain, name, value);
197        cookie.setPath(path);
198    
199        _state.addCookie(cookie);
200      }
201    
202      /**
203       * Returns the value of cookie <code>name</code>.
204       *
205       * @param name  the name of the cookie
206       *
207       * @return the value of the cookie, or null if the cookie isn't set
208       */
209      public String getCookieValue(String name) {
210        String  value = null;
211        boolean done  = false;
212    
213        Cookie[] cookies = _state.getCookies();
214    
215        for (int i = 0; i < cookies.length && !done; i++) {
216          if (cookies[i].getName().equals(name)) {
217            value = cookies[i].getValue();
218            done = true;
219          }
220        }
221    
222        return value;
223      }
224    
225    }