View Javadoc

1   /*
2    * Copyright 2000-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.jetspeed.services.webpage;
18  
19  // java.io
20  import java.io.IOException;
21  import java.io.FileOutputStream;
22  import java.io.InputStream;
23  import java.io.ByteArrayOutputStream;
24  import java.io.DataOutputStream;
25  
26  // java.util
27  import java.util.Iterator;
28  import java.util.Enumeration;
29  import java.util.HashMap;
30  
31  // javax.servlet
32  import javax.servlet.http.*;
33  
34  // java.net
35  import java.net.URL;
36  import java.net.URLConnection;
37  import java.net.HttpURLConnection;
38  import java.net.URLEncoder;
39  
40  import org.apache.log4j.Logger;
41  
42  /*
43   * Abstract Base class for web page sessions.
44   * Implements the primary dispatcher logic for getting and posting resources.
45   *
46   */
47  
48  public abstract class AbstractSiteSession implements SiteSession
49  {    
50  
51      // the base url of the host being proxied
52      protected String targetBase;
53  
54      // the base url the wps
55      protected String proxyBase;
56  
57      // the cookies collection
58      protected HashMap cookies = new HashMap();
59          
60      // counters
61      protected int hitCount = 0;
62      protected int cacheCount = 0;
63  
64      // the log file singleton instance
65      static Logger log = Logger.getLogger(AbstractSiteSession.class);
66  
67      /***
68       * Create a NetElementSession, which maintains sessions with one network element.
69       * 
70      * @param targetBase the target host's base URL
71      * @param proxyBase the proxy server host URL base address.     
72       */    
73      public AbstractSiteSession(String targetBase, String proxyBase)
74      {
75          this.proxyBase  = proxyBase;
76          this.targetBase = targetBase;
77      }
78  
79      /***
80       * Given a URL, returns the content from that URL in a string.  
81       * All HTTP hyperlinks(HREFs) are rewritten as proxied-referenced hyperlinks.
82       * All relative references to web resources (images, stylesheets, ...) are 
83       * rewritten as absolute references, but are not proxied.
84       * Determines if we are logged on to the target site. If not,
85       * calls logon(), which is a implementation specific 'POST' exchange
86       *
87       * @see logon(String, HttpServletRequest, HttpServletResponse)     
88       *
89       * @param url the proxied resource address.
90       * @param data the rundata
91       *
92       * @exception IOException a servlet exception.
93       */    
94  
95      public void dispatch(String url, ProxyRunData data)
96                   throws IOException
97      {                    
98          try 
99          {
100             Configuration config = Configuration.getInstance();
101                 
102             log.debug("=== Dispatching =" + url);
103             
104             // open a pooled HTTP connection
105             //URL u = new URL(url);
106             URL u = new URL(null, url, new sun.net.www.protocol.http.Handler() );
107             HttpURLConnection con = (HttpURLConnection)u.openConnection();  
108     
109             //if (con instanceof HttpURLConnection) 
110             con.setDoInput(true);
111             con.setDoOutput(true);
112             con.setAllowUserInteraction(false);        
113             con.setFollowRedirects(false);
114     
115             if (data.getPosting()) {
116                 con.setRequestMethod("POST");
117             }
118         
119             // are there any cookies in our current session?
120             if (cookies.isEmpty()) 
121             {
122                 // there are no cookies, must be a new session, so lets logon
123                     log.debug("... no session id provided. Logging on...");
124     
125                 if (false == logon(data))
126                     return;   
127     
128             }        
129     
130             // send the cookies (session ids) back to the NE
131             Iterator it = cookies.values().iterator();
132             Cookie cookie;
133             while (it.hasNext()) {
134                 cookie = (Cookie)it.next();
135                 String sessionID = WebPageHelper.buildCookieString(cookie);
136                 con.setRequestProperty("Cookie", sessionID);
137                 log.debug("... Sending Session ID: " + sessionID );
138             }            
139     
140             // we have to get the post parameters from the servlet container,
141             // and then re-encode them. i wish i could find out how to keep
142             // the servlet container from reading them, because now i have to
143             // parse them out, and then re-encode
144             if (data.getPosting()) {
145     
146                 // get the post params 
147                 StringBuffer postParams = new StringBuffer();
148                 int count = 0;
149                 Enumeration e = data.getRequest().getParameterNames();
150                 while (e.hasMoreElements())
151                 {
152     
153                     String name = (String) e.nextElement();
154                     if (name.equals(config.getSID()) ||
155                         name.equals(config.getURL())) {
156                         continue;
157                     }                                      
158     
159                     String values[] = data.getRequest().getParameterValues(name);
160                     if (values != null) 
161                     {
162                         for (int i = 0; i < values.length; i++) {
163                             if (count > 0) {
164                                 postParams.append("&");
165                             }
166                             postParams.append(name);
167                             postParams.append("=");
168                             postParams.append(URLEncoder.encode(values[i]));
169                             count++;
170                         }
171                     }
172                 }
173                 String  postString = postParams.toString();            
174                 con.setRequestProperty("Content-length", String.valueOf(postString.length()) );
175                 // write directly to the output stream            
176                 DataOutputStream dos = new DataOutputStream(con.getOutputStream());            
177     
178                 log.debug("... POST: " + postString);
179                 dos.writeBytes(postString);
180                 dos.close();
181             }
182            
183             int rc = con.getResponseCode();
184     
185             // Get the Session Information from Headers
186             int contentType = WebPageHelper.getContentType(con.getHeaderField("content-type"), u.toString());
187             String location = con.getHeaderField("Location");
188             
189             if ((rc == con.HTTP_MOVED_PERM || rc == con.HTTP_MOVED_TEMP) && null != location) 
190             {
191                 log.debug("+++ REDIRECT = " + location);
192                 location = WebPageHelper.concatURLs(targetBase, location);
193                 dispatch(location , data);
194                 return;
195             }
196     
197             // get cookies set from server
198             String cookieString = con.getHeaderField("Set-Cookie");
199             if (null != cookieString) 
200             {
201                 log.debug("... new SessionID found: " + cookieString);
202                 WebPageHelper.parseCookies(cookieString, this);            
203             }
204     
205             if (contentType == WebPageHelper.CT_IMAGE || 
206                 contentType == WebPageHelper.CT_BINARY ||
207                 contentType == WebPageHelper.CT_APPLICATION) {
208                 // wasn't in the cache, get it from host
209                 getBinaryContent(con, data.getResponse());
210                 return;
211             }
212         
213             rewriteContent(data, con, contentType, url);
214     
215         }
216         catch (IOException ex)
217         {
218             log.error("*** PROXY DISPATCH EXCEPTION = " + ex);
219                 throw ex;
220         }
221 
222     }
223 
224     /***
225      * Gets the HTML content from the URL Connection stream and returns it
226      * in a string
227      *
228      * @param con The URLConnection to read from.
229      * @param resource The full URL of the resource.
230      * @return The HTML Content from the stream.
231      *
232      * @exception IOException a servlet exception.
233      */
234     public String getHTMLContent(URLConnection con, 
235                                  ProxyRunData data,
236                                  String resource) throws IOException 
237     {
238 
239         int CAPACITY = 4096;
240 
241         InputStream is = con.getInputStream();
242         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
243         
244         Configuration config = Configuration.getInstance();
245         FileOutputStream fos = null;
246         boolean logging = config.getEnableContentLog();
247         if (logging) 
248         {
249             if (data != null)
250             {
251                 String fileName = data.getServlet().getServletContext().getRealPath(
252                                         config.getLogLocation() );
253                 fos = new FileOutputStream(fileName, true);
254                 WebPageHelper.writeHeader(fos, resource);
255             }
256         }
257         
258         //now process the InputStream...
259         
260         byte[] bytes = new byte[CAPACITY];
261 
262         int readCount = 0;
263         int total = 0;
264 
265         while( ( readCount = is.read( bytes )) > 0 ) 
266         {                                        
267             buffer.write( bytes, 0, readCount);
268             if (logging)
269             {
270                 fos.write( bytes, 0, readCount);
271             }
272             total += readCount;
273         }     
274         if (logging) 
275         {
276             fos.close();
277         }
278         is.close();
279 
280         return buffer.toString();
281     }
282 
283     /***
284      * Gets the HTML content from the URL Connection stream and writes it to respones
285      *
286      * @param con The URLConnection to read from.
287      *
288      * @exception IOException a servlet exception.
289      */
290     public void getBinaryContent(URLConnection con,
291                                  HttpServletResponse response) throws IOException 
292     {
293 
294         int CAPACITY = 4096;
295 
296 
297         InputStream is = con.getInputStream();
298 
299        // FileOutputStream fos = new FileOutputStream("/test.fw", true);
300 
301         //now process the InputStream...
302         
303         byte[] bytes = new byte[CAPACITY];
304 
305         int readCount = 0;
306         while( ( readCount = is.read( bytes )) > 0 ) {
307                                         
308             response.getOutputStream().write(bytes, 0, readCount);
309             //fos.write( bytes, 0, readCount);
310         }        
311         
312         //fos.close();
313         is.close();
314 
315     }
316 
317     /***
318       * Given a cookie, it first checks to see if that cookie is already
319       * managed in this session. If it is, it means that the session has
320       * timed out and that the network element has now created a new session.
321       * In that case, replace the cookie, and re-establish the session (logon)
322       * If its a new cookie, we will still need to logon, and and the cookie to
323       * the managed cookies collection for this session.
324       *
325       * @param cookie new cookie returned from target server.
326       * @return true when a new cookie added, false when updated.
327       *
328       */
329     public boolean addCookieToSession(Cookie cookie)
330     {
331         boolean added = (null == cookies.get(cookie.getName()));
332         cookies.put(cookie.getName(), cookie); // adds or updates        
333         return added;
334     }
335 
336     /*
337      * Gets the hitcount for this session.
338      *
339      * @return the hitcount for this session.
340      */
341     public int getHitCount()
342     {
343         return hitCount;
344     }
345 
346     /*
347      * Increments the hitcount for this session.
348      *
349      */
350     public void incHitCount()
351     {
352         hitCount++;
353     }
354 
355     /*
356      * Gets the cache count for this session.
357      *
358      * @return the cache count for this session.
359      */
360     public int getCacheCount()
361     {
362         return cacheCount;
363     }
364 
365     /*
366      * Increments the hitcount for this session.
367      *
368      */
369     public void incCacheCount()
370     {
371         cacheCount++;
372     }
373 
374 
375 }
376