KickJava   Java API By Example, From Geeks To Geeks.

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


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.InputStream JavaDoc;
23 import java.net.MalformedURLException JavaDoc;
24 import java.net.URL JavaDoc;
25 import java.net.URLDecoder JavaDoc;
26 import java.text.SimpleDateFormat JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Date JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.StringTokenizer JavaDoc;
32 import java.util.zip.GZIPInputStream JavaDoc;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 import com.maverick.http.HttpResponse;
38 import com.sslexplorer.boot.CaseInsensitiveMap;
39 import com.sslexplorer.boot.HttpConstants;
40 import com.sslexplorer.boot.Util;
41 import com.sslexplorer.core.CookieItem;
42 import com.sslexplorer.core.CookieMap;
43 import com.sslexplorer.policyframework.LaunchSession;
44
45 /**
46  * @author Brett Smith <brett@3sp.com>
47  */

48 public class ProxiedResponseProcessor {
49     final static Log log = LogFactory.getLog(ProxiedResponseProcessor.class);
50
51     private ProxiedRequestDispatcher requestDispatcher;
52     private int maxAge;
53     private ContentCache cache;
54     private SimpleDateFormat JavaDoc sdf;
55     private RequestProcessor requestProcessor;
56     // private boolean keepAlive;
57
private Date JavaDoc expiryDate;
58     private CookieMap cookieMap;
59     private String JavaDoc contentType;
60     private int contentLength;
61     private List JavaDoc headers;
62     private boolean cacheable;
63     private InputStream JavaDoc serverIn;
64     private String JavaDoc charset;
65     static CaseInsensitiveMap ignoreHeaders = new CaseInsensitiveMap();
66
67     static {
68         ignoreHeaders.put(HttpConstants.HDR_PROXY_CONNECTION, Boolean.TRUE);
69         ignoreHeaders.put(HttpConstants.HDR_ACCEPT_ENCODING, Boolean.TRUE);
70         ignoreHeaders.put(HttpConstants.HDR_TRANSFER_ENCODING, Boolean.TRUE);
71         ignoreHeaders.put(HttpConstants.HDR_TE, Boolean.TRUE);
72         ignoreHeaders.put(HttpConstants.HDR_TRAILER, Boolean.TRUE);
73         ignoreHeaders.put(HttpConstants.HDR_PROXY_AUTHORIZATION, Boolean.TRUE);
74         ignoreHeaders.put(HttpConstants.HDR_PROXY_AUTHENTICATE, Boolean.TRUE);
75         ignoreHeaders.put(HttpConstants.HDR_UPGRADE, Boolean.TRUE);
76         ignoreHeaders.put(HttpConstants.HDR_CONTENT_ENCODING, Boolean.TRUE);
77     }
78
79     /**
80      *
81      */

82     public ProxiedResponseProcessor(RequestProcessor requestProcessor, ProxiedRequestDispatcher requestDispatcher, int maxAge,
83                                     ContentCache cache, CookieMap cookieMap) {
84         this.requestDispatcher = requestDispatcher;
85         this.requestProcessor = requestProcessor;
86         this.maxAge = maxAge;
87         this.cache = cache;
88         this.cookieMap = cookieMap;
89         // keepAlive = requestDispatcher.isKeepAlive();
90
sdf = new SimpleDateFormat JavaDoc("EEEE, dd-MMM-yy HH:mm:ss zzz");
91     }
92
93     public ProxiedRequestDispatcher getRequestDispatcher() {
94         return requestDispatcher;
95     }
96
97     public void processResponse() throws Exception JavaDoc {
98
99         HttpResponse serverResponse = requestDispatcher.getServerResponse();
100         headers = new ArrayList JavaDoc();
101
102         // Determine if the response can be cached, and if so, for how long
103
expiryDate = maxAge == 0 ? null : new Date JavaDoc(System.currentTimeMillis() + maxAge);
104         cacheable = false;
105         if (cache != null && HttpConstants.METHOD_GET.equals(requestProcessor.getRequestMethod())
106             && requestDispatcher.getResponseCode() == HttpConstants.RESP_200_OK) {
107             cacheable = true;
108
109             // HTTP 1.0
110
String JavaDoc cacheControl = serverResponse.getHeaderField(HttpConstants.HDR_PRAGMA);
111             if (cacheControl != null && cacheControl.equalsIgnoreCase("no-cache")) {
112                 if (log.isDebugEnabled())
113                     log.debug("Not caching as server explicitly requested not to.");
114                 cacheable = false;
115             } else {
116                 String JavaDoc expires = serverResponse.getHeaderField(HttpConstants.HDR_EXPIRES);
117                 if (expires != null) {
118                     try {
119                         expiryDate = sdf.parse(expires);
120                     } catch (Exception JavaDoc e2) {
121                     }
122                 }
123             }
124
125             // HTTP 1.1
126
if (cacheable) {
127                 cacheControl = serverResponse.getHeaderField(HttpConstants.HDR_CACHE_CONTROL);
128                 if (cacheControl != null) {
129                     StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(cacheControl, ";");
130                     while (tok.hasMoreTokens()) {
131                         String JavaDoc t = tok.nextToken().trim();
132                         String JavaDoc tl = t.toLowerCase();
133                         if (t.startsWith("no-cache") || t.startsWith("no-store")) {
134                             cacheable = false;
135                             if (log.isDebugEnabled())
136                                 log.debug("Not caching as server explicitly requested not to.");
137                         } else if (tl.startsWith("max-age")) {
138                             try {
139                                 expiryDate.setTime(expiryDate.getTime() - (Integer.parseInt(Util.valueOfNameValuePair(tl))));
140                             } catch (Exception JavaDoc e2) {
141                             }
142                         }
143                     }
144                 }
145             }
146         }
147
148         String JavaDoc contentEncoding = serverResponse.getHeaderField(HttpConstants.HDR_CONTENT_ENCODING);
149         serverIn = serverResponse.getInputStream();
150
151         if ("gzip".equals(contentEncoding)) {
152             serverIn = new GZIPInputStream JavaDoc(serverIn);
153         } else if ("identity".equals(contentEncoding) || contentEncoding == null) {
154             // Plain
155
} else {
156             throw new Exception JavaDoc("Invalid content encoding " + serverResponse.getHeaderField(HttpConstants.HDR_CONTENT_ENCODING));
157         }
158
159         String JavaDoc[] challenges = serverResponse.getHeaderFields("www-authenticate");
160
161         if (challenges != null) {
162             serverResponse.removeFields("www-authenticate");
163
164             for (int i = 0; i < challenges.length; i++) {
165                 if (challenges[i].toLowerCase().startsWith("basic") || challenges[i].toLowerCase().startsWith("digest")
166                     || challenges[i].toLowerCase().startsWith("ntlm")) {
167                     if(i==0)
168                         serverResponse.setHeaderField("WWW-Authenticate", challenges[i]);
169                     else
170                         serverResponse.addHeaderField("WWW-Authenticate", challenges[i]);
171                 }
172             }
173         }
174
175         // response.setStatus(serverResponse.getStatus());
176
// response.setReason(serverResponse.getReason());
177

178         serverResponse.removeFields("Server");
179         serverResponse.removeFields("Date");
180
181         for (Enumeration JavaDoc e = serverResponse.getHeaderFieldNames(); e.hasMoreElements();) {
182             String JavaDoc hdr = (String JavaDoc) e.nextElement();
183             if (log.isDebugEnabled())
184                 log.debug("Received header " + hdr);
185             String JavaDoc[] val = serverResponse.getHeaderFields(hdr);
186
187             for (int i = 0; i < val.length; i++) {
188
189                 if (hdr.equalsIgnoreCase("Content-Type")) {
190
191                     StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(val[i], ";");
192                     while (tok.hasMoreTokens()) {
193                         String JavaDoc t = tok.nextToken().trim();
194                         String JavaDoc tl = t.toLowerCase();
195                         if (tl.startsWith("charset=")) {
196                             charset = Util.valueOfNameValuePair(t);
197                         } else {
198                             contentType = Util.valueOfNameValuePair(t);
199                         }
200                     }
201
202                     contentType = val[i];
203                     if (log.isDebugEnabled())
204                         log.debug("Received content type " + contentType + " (charset = " + charset + ")");
205                 } else if (hdr.equalsIgnoreCase("Content-Length")) {
206                     try {
207                         contentLength = Integer.parseInt(val[i]);
208                     } catch (Exception JavaDoc ex) {
209
210                     }
211                     if (log.isDebugEnabled())
212                         log.debug("Received content length " + contentLength);
213                 } else {
214                     if (hdr.equalsIgnoreCase("Location")) {
215                         
216                         if(log.isDebugEnabled())
217                             log.debug("Processing Location header value '" + val[i] + "'");
218                         
219                         URL JavaDoc actual;
220                         try {
221                             actual = new URL JavaDoc(Util.urlDecode(val[i]));
222                         } catch(MalformedURLException JavaDoc ex) {
223                             actual = new URL JavaDoc(requestProcessor.getRequestParameters().getProxiedURLBase(), Util.urlDecode(val[i]));
224                         }
225
226                         cache.clear(actual.toExternalForm());
227                         URL JavaDoc newVal = new URL JavaDoc(requestProcessor.getRequestBaseURL(), "/replacementProxyEngine?" + LaunchSession.LONG_LAUNCH_ID
228                             + "="
229                             + requestProcessor.getLaunchId()
230                             + "&sslex_url="
231                             + Util.urlEncode(actual.toExternalForm()));
232                         if (log.isDebugEnabled())
233                             log.debug("Found location of header " + val[i]
234                                 + " changing to "
235                                 + newVal
236                                 + " ( removed "
237                                 + actual.toExternalForm()
238                                 + " from cache");
239                         val[i] = newVal.toExternalForm();
240                     } else if (hdr.equalsIgnoreCase("Set-Cookie")) {
241                         val[i] = parseCookie(val[i]);
242                     }
243                     if (log.isDebugEnabled())
244                         log.debug("Adding header " + hdr + " = " + val[i]);
245                     headers.add(new Header(hdr, val[i]));
246                 }
247
248             }
249         }
250
251     }
252
253     public List JavaDoc getHeaders() {
254         return headers;
255     }
256
257     /**
258      * @return
259      */

260     public String JavaDoc getContentType() {
261         return contentType;
262     }
263
264     public String JavaDoc getCharset() {
265         return charset;
266     }
267
268     public int getContentLength() {
269         return contentLength;
270     }
271
272     /**
273      * @return
274      */

275     public boolean isCacheable() {
276         return cacheable;
277     }
278
279     public InputStream JavaDoc getProxiedInputStream() {
280         return serverIn;
281     }
282
283     /**
284      * @return
285      */

286     public Date JavaDoc getCacheExpiryDate() {
287         return expiryDate;
288     }
289     
290     String JavaDoc parseCookie(String JavaDoc val) {
291         StringBuffer JavaDoc newVal = new StringBuffer JavaDoc();
292         StringTokenizer JavaDoc t = new StringTokenizer JavaDoc(val, ";");
293         String JavaDoc elementName = null;
294         String JavaDoc elementValue = null;
295
296         try {
297             while (t.hasMoreTokens()) {
298                 /* Get the name and value of the cookie field element */
299                 String JavaDoc name = Util.trimBoth(t.nextToken());
300                 int idx = name.indexOf('=');
301                 if (idx > -1) {
302                     elementValue = name.substring(idx + 1);
303                     elementName = name.substring(0, idx);
304                 } else {
305                     elementName = name;
306                     elementValue = "";
307                 }
308                 
309                 /* Ignore domain and path, fake cookie names and include all other elements */
310                 
311                 if (elementName.equalsIgnoreCase("path") || elementName.equalsIgnoreCase("domain")) {
312                     // Ignore path and domain
313
} else if (elementName.equalsIgnoreCase("expires") ||
314                                 elementName.equalsIgnoreCase("max-age") ||
315                                 elementName.equalsIgnoreCase("secure") ||
316                                 elementName.equalsIgnoreCase("version") ||
317                                 elementName.equalsIgnoreCase("comment") ) {
318                     // Include these
319
if(newVal.length() > 0) {
320                         newVal.append("; ");
321                     }
322                     newVal.append(elementName);
323                     if(!elementValue.equals("")) {
324                         newVal.append("=");
325                         newVal.append(elementValue);
326                     }
327                 } else {
328                     // Assume to be a cookie name
329
String JavaDoc fakeCookieName = Math.abs((requestProcessor.getRequestParameters().getProxiedURL().getProtocol()
330                             + ":"
331                             + requestProcessor.getRequestParameters().getProxiedURL().getHost()).hashCode()) + "_" + elementName;
332                     CookieItem cookieItem = new CookieItem(elementName, fakeCookieName);
333                     cookieMap.put(cookieItem);
334                     if(newVal.length() > 0) {
335                         newVal.append("; ");
336                     }
337                     newVal.append(fakeCookieName);
338                     if(!elementValue.equals("")) {
339                         newVal.append("=");
340                         newVal.append(Util.urlEncode(elementValue));
341                     }
342                 }
343             }
344         } catch (Exception JavaDoc ex) {
345             log.warn("Invalid cookie.", ex);
346         }
347         return newVal.toString();
348     }
349     
350
351
352 }
353
Popular Tags