KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > replacementproxy > ProxiedResponseDispatcher


1 /*
2  * SSL-Explorer
3  *
4  * Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */

19             
20 package com.sslexplorer.replacementproxy;
21
22 import java.io.ByteArrayOutputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.io.OutputStream JavaDoc;
26 import java.lang.reflect.Constructor JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.text.SimpleDateFormat JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34
35 import com.sslexplorer.boot.ReplacementEngine;
36 import com.sslexplorer.boot.Replacer;
37 import com.sslexplorer.boot.RequestHandlerResponse;
38 import com.sslexplorer.boot.Util;
39 import com.sslexplorer.policyframework.LaunchSession;
40 import com.sslexplorer.security.User;
41 import com.sslexplorer.webforwards.WebForwardDatabaseFactory;
42 import com.sslexplorer.webforwards.WebForwardTypes;
43
44 /**
45  * @author Brett Smith <brett@3sp.com>
46  */

47 public class ProxiedResponseDispatcher {
48
49     final static Log log = LogFactory.getLog(ProxiedResponseDispatcher.class);
50
51     private RequestProcessor requestProcessor;
52     private ProxiedResponseProcessor responseProcessor;
53     private RequestHandlerResponse response;
54     private LaunchSession launchSession;
55     private ContentCache cache;
56     private SimpleDateFormat JavaDoc sdf;
57     private ReplacementProxyMethodHandler proxyMethodHandler;
58
59     public ProxiedResponseDispatcher(ReplacementProxyMethodHandler proxyMethodHandler, RequestProcessor requestProcessor, ProxiedResponseProcessor responseProcessor,
60                     RequestHandlerResponse response, LaunchSession launchSession, ContentCache cache) {
61         this.proxyMethodHandler = proxyMethodHandler;
62         this.responseProcessor = responseProcessor;
63         this.requestProcessor = requestProcessor;
64         this.response = response;
65         this.cache = cache;
66         this.launchSession = launchSession;
67         sdf = new SimpleDateFormat JavaDoc("EEEE, dd-MMM-yy HH:mm:ss zzz");
68
69     }
70
71     public void sendResponse() throws Exception JavaDoc {
72         // Only set the content type for the response if the target server
73
// returned it
74
String JavaDoc type = responseProcessor.getContentType();
75         if (type == null) {
76             // If the mime type is not returned, then guess it from our own map
77
type = requestProcessor.getSession().getServletContext().getMimeType(
78                              requestProcessor.getRequestParameters().getProxiedURL().getFile());
79             if (log.isDebugEnabled())
80                 log.debug("Guessed response type " + type + " from URL");
81         }
82         else {
83             if (log.isDebugEnabled())
84                 log.debug("Sending response of type " + type);
85         }
86         if (type != null) {
87             response.setField("Content-Type", type);
88         }
89
90         int code = responseProcessor.getRequestDispatcher().getResponseCode();
91         if (log.isDebugEnabled())
92             log.debug("Sending response code " + code);
93         response.setStatus(code);
94
95         // Configure replacement proxy content encoding
96
if(requestProcessor.getWebForward().getEncoding()==null || requestProcessor.getWebForward().getEncoding().equals(WebForwardTypes.DEFAULT_ENCODING)) {
97             if(responseProcessor.getCharset() != null) {
98                 response.setCharacterEncoding(responseProcessor.getCharset());
99             }
100         } else
101             response.setCharacterEncoding(requestProcessor.getWebForward().getEncoding());
102         
103         // Add all of the headers to the response
104
copyHeaders();
105
106         //
107
OutputStream JavaDoc responseOut = getOutputStream(type);
108
109         //
110
InputStream JavaDoc serverIn = responseProcessor.getProxiedInputStream();
111         User user = launchSession.getSession().getUser();
112
113         if (serverIn != null) {
114
115             // Get just type mime type part of the content type
116

117             String JavaDoc mimeType = type;
118             int idx = mimeType == null ? -1 : mimeType.indexOf(";");
119             if (idx != -1) {
120                 mimeType = mimeType.substring(0, idx);
121             }
122
123             // If there is no content type or are no replaces
124
List JavaDoc replacements = WebForwardDatabaseFactory.getInstance().getReplacementsForContent(
125                             user.getPrincipalName(), Replacement.REPLACEMENT_TYPE_RECEIVED_CONTENT, mimeType,
126                             requestProcessor.getRequestParameters().getProxiedURL().toExternalForm());
127             if (replacements.size() > 0) {
128                 // The default replacer
129
if (log.isDebugEnabled())
130                     log.debug("Found " + replacements.size() + ", processing");
131                 ReplacementEngine replace = new ReplacementEngine();
132                 
133                 if(!requestProcessor.getWebForward().getEncoding().equals(WebForwardTypes.DEFAULT_ENCODING))
134                     replace.setEncoding(requestProcessor.getWebForward().getEncoding());
135                 else
136                     replace.setEncoding(responseProcessor.getCharset());
137                 
138                 replace.setCaseSensitive(false);
139                 replace.setDotAll(true);
140                 final BaseSearch baseSearch = new BaseSearch();
141                 replace.addPattern("(<base*\\s+(?:href)\\=['\\\"]*)([^\\s'>\\\"]*)([^>]*)(>)", baseSearch, "");
142
143                 Replacer replacer = new ProxyReplacer(requestProcessor, baseSearch);
144
145                 for (Iterator JavaDoc i = replacements.iterator(); i.hasNext();) {
146                     Replacement r = (Replacement) i.next();
147                     if (log.isDebugEnabled())
148                         log.debug("Adding replacement pattern '" + r.getMatchPattern() + "' = '" + r.getReplacePattern() + "'");
149                     if (r.getReplacePattern().startsWith("#")) {
150                         String JavaDoc cn = r.getReplacePattern().substring(1);
151                         try {
152                             Class JavaDoc clazz = Class.forName(cn);
153                             Constructor JavaDoc c = clazz.getConstructor(new Class JavaDoc[] { URL JavaDoc.class, String JavaDoc.class });
154                             Replacer re = (Replacer) (c.newInstance(new Object JavaDoc[] { requestProcessor.getRequestParameters().getProxiedURLBase(), requestProcessor.getLaunchId() }));
155                             if (log.isDebugEnabled())
156                                 log.debug("Loaded custom replacer " + cn + ".");
157                             replace.addPattern(r.getMatchPattern(), re, null);
158                         } catch (Throwable JavaDoc t) {
159                             log.error("Could not load custom replacer " + cn + ".", t);
160                         }
161                     } else {
162                         replace.addPattern(r.getMatchPattern(), replacer, r.getReplacePattern());
163                     }
164                 }
165
166                 OutputStream JavaDoc monitorOut = responseOut;
167                 int origLen = responseProcessor.getContentLength();
168                 int len = origLen == -1 ? 1024 : responseProcessor.getContentLength();
169                 if (log.isDebugEnabled())
170                     log.debug("Reading response from target and processing into memory (" + len + " bytes buffer)");
171                 monitorOut = new ByteArrayOutputStream JavaDoc(len);
172                 long length = replace.replace(serverIn, monitorOut);
173                 if (log.isDebugEnabled())
174                     log.debug("Replacement complete");
175                                 
176
177                 /* Tack some javascript on to the end of the page for JavaScript based automatic
178                  * authentication
179                  */

180                 if (mimeType.equals("text/html") && requestProcessor.getWebForward().getFormType().equals(WebForwardTypes.FORM_SUBMIT_JAVASCRIPT)
181                         && !Boolean.TRUE.equals(launchSession.getAttribute(ProxiedRequestDispatcher.LAUNCH_ATTR_AUTH_POSTED))) {
182                     length = proxyMethodHandler.addJavaScriptAuthenticationCode(launchSession, monitorOut, length);
183                 }
184
185                 if (origLen != -1) {
186                     if (log.isDebugEnabled())
187                         log.debug("New output length is " + length);
188                     response.setContentLength((int) length);
189                 }
190                 if (log.isDebugEnabled())
191                     log.debug("Writing respone back to client");
192                 responseOut.write(((ByteArrayOutputStream JavaDoc) monitorOut).toByteArray());
193             } else {
194                 if (log.isDebugEnabled())
195                     log.debug("Just copying content type of " + type);
196                 Util.copy(serverIn, responseOut);
197             }
198
199             if (log.isDebugEnabled()) {
200                 // Cache the response
201
if (responseProcessor.isCacheable()) {
202                     log.debug("Caching page "
203                                     + requestProcessor.getRequestParameters().getProxiedURL()
204                                     + (responseProcessor.getCacheExpiryDate() == null ? " (never expires)" : (" (expires on " + sdf
205                                                     .format(responseProcessor.getCacheExpiryDate()))) + ")");
206                     if (!cache.store(requestProcessor.getRequestParameters().getProxiedURL(), (CacheingOutputStream) responseOut, responseProcessor
207                                     .getCacheExpiryDate() == null ? null : new Long JavaDoc(responseProcessor.getCacheExpiryDate().getTime()),
208                                     null)) {
209                         log.warn("Failed to cache page " + requestProcessor.getRequestParameters().getProxiedURL());
210                     } else {
211                         log.debug("Cached page " + requestProcessor.getRequestParameters().getProxiedURL());
212                     }
213                 } else {
214                     log.debug("Removing " + requestProcessor.getRequestParameters().getProxiedURL() + " from cache");
215                     cache.clear(requestProcessor.getRequestParameters().getProxiedURL());
216                 }
217             }
218         } else {
219             throw new Exception JavaDoc("No streams.");
220         }
221     }
222     
223     void copyHeaders() {
224
225         for (Iterator JavaDoc i = responseProcessor.getHeaders().iterator(); i.hasNext();) {
226             Header hi = (Header) i.next();
227             
228             /* This must be ADD, not SET as Set-Cookie could appear multiple times */
229             response.addField(hi.getName(), hi.getVal());
230         }
231     }
232     
233     OutputStream JavaDoc getOutputStream(String JavaDoc type) throws IOException JavaDoc {
234         if (responseProcessor.isCacheable()) {
235             if (log.isDebugEnabled())
236                 log.debug("Opening output stream via a cache");
237             return new CacheingOutputStream(response.getOutputStream(), responseProcessor.getContentLength() == -1 ? 1024
238                             : responseProcessor.getContentLength(), responseProcessor.getHeaders(), type);
239         } else {
240             if (log.isDebugEnabled())
241                 log.debug("Opening non-cached output stream");
242             return response.getOutputStream();
243         }
244     }
245 }
246
Popular Tags