KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > quercus > lib > UrlRewriterCallback


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Emil Ong
28  */

29
30 package com.caucho.quercus.lib;
31
32 import com.caucho.quercus.env.*;
33 import com.caucho.util.URLUtil;
34
35 import java.lang.reflect.Method JavaDoc;
36 import java.net.URI JavaDoc;
37 import java.net.URISyntaxException JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.HashMap JavaDoc;
40
41 /**
42  * Implements the built-in URL rewriter for passing session ids and other
43  * variables.
44  */

45 public class UrlRewriterCallback extends CallbackFunction {
46   private StringBuilder JavaDoc _rewriterQuery = new StringBuilder JavaDoc();
47   private ArrayList JavaDoc<String JavaDoc[]> _rewriterVars = new ArrayList JavaDoc<String JavaDoc[]>();
48
49   public UrlRewriterCallback(Env env)
50   {
51     super(env, "URL-Rewriter");
52
53     try {
54       Method JavaDoc rewriterMethod =
55         UrlRewriterCallback.class.getMethod("_internal_url_rewriter",
56                                             Env.class, String JavaDoc.class);
57       setFunction(new JavaMethod(env.getModuleContext(), rewriterMethod));
58     } catch (NoSuchMethodException JavaDoc e) {
59     } catch (SecurityException JavaDoc e) {
60     }
61   }
62
63   /**
64    * Returns the unique rewriter.
65    */

66   public static UrlRewriterCallback getInstance(Env env)
67   {
68     OutputBuffer ob = env.getOutputBuffer();
69
70     for (; ob != null; ob = ob.getNext()) {
71       Callback callback = ob.getCallback();
72
73       if (callback instanceof UrlRewriterCallback)
74         return (UrlRewriterCallback)callback;
75     }
76
77     return null;
78   }
79
80   /**
81    * Adds a rewrite variable. Intended for
82    * <code>output_add_rewrite_var()</code>.
83    */

84   public void addRewriterVar(String JavaDoc var, String JavaDoc value)
85   {
86     if (_rewriterQuery.length() > 0)
87       _rewriterQuery.append("&");
88
89     String JavaDoc encodedVar = URLUtil.encodeURL(var.replaceAll(" ", "+"));
90     String JavaDoc encodedValue = URLUtil.encodeURL(value.replaceAll(" ", "+"));
91
92     _rewriterQuery.append(encodedVar + "=" + encodedValue);
93     _rewriterVars.add(new String JavaDoc[] {encodedVar, encodedValue});
94   }
95
96   /**
97    * Resets (clears) all the rewrite variables. Intended for
98    * <code>output_reset_rewrite_vars()</code>.
99    */

100   public void resetRewriterVars()
101   {
102     _rewriterQuery = new StringBuilder JavaDoc();
103     _rewriterVars.clear();
104   }
105   
106   /**
107    * Callback function to rewrite URLs to include session information.
108    */

109   public static Value _internal_url_rewriter(Env env, String JavaDoc buffer)
110   {
111     UrlRewriterCallback rewriter = getInstance(env);
112
113     // We should never have been called in this case, but
114
// return the buffer unmodified anyway.
115
if (rewriter == null)
116       return NullValue.NULL;
117     
118     Parser parser = rewriter.new Parser(buffer, env);
119     return parser.parse();
120   }
121
122   private class Parser {
123     private Env _env;
124
125     private boolean _includeSessionInfo = false;
126     private String JavaDoc _sessionName = null;
127     private String JavaDoc _sessionId = null;
128     private String JavaDoc _javaSessionName = null;
129     private String JavaDoc _javaSessionId = null;
130
131     private int _index;
132     private String JavaDoc _value;
133     private boolean _quoted;
134
135     private String JavaDoc _input;
136     private StringBuilderValue _output = new StringBuilderValue();
137
138     public Parser(String JavaDoc input, Env env)
139     {
140       _input = input;
141       _env = env;
142       _index = 0;
143     }
144
145     public Value parse()
146     {
147       if (_env.getSession() != null && _env.getJavaSession() != null &&
148           _env.getIni("session.use_trans_sid").toBoolean()) {
149         _includeSessionInfo = true;
150
151         _sessionName = _env.getIni("session.name").toString();
152         _sessionId = _env.getSession().getId();
153
154     _javaSessionName = _env.getQuercus().getCookieName();
155
156         _javaSessionId = _env.getJavaSession().getId();
157       }
158
159       if (_includeSessionInfo == false && _rewriterVars.isEmpty())
160         return NullValue.NULL;
161
162       String JavaDoc [] tagPairs =
163         _env.getIni("url_rewriter.tags").toString().split(",");
164       HashMap JavaDoc<String JavaDoc,String JavaDoc> tags = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
165
166       for (String JavaDoc tagPair : tagPairs) {
167         String JavaDoc [] tagAttribute = tagPair.split("=");
168
169         switch (tagAttribute.length) {
170           case 1:
171             tags.put(tagAttribute[0], null);
172             break;
173
174           case 2:
175             tags.put(tagAttribute[0], tagAttribute[1]);
176             break;
177
178           default:
179             break;
180         }
181       }
182
183       for (String JavaDoc tag = getNextTag(); tag != null; tag = getNextTag()) {
184         if (tags.containsKey(tag)) {
185           String JavaDoc attribute = tags.get(tag);
186           
187           if (attribute == null) {
188             consumeToEndOfTag();
189             
190             if (_includeSessionInfo) {
191               String JavaDoc phpSessionInputTag =
192                 "<input type=\"hidden\" name=\"" + _sessionName + "\"" +
193                 " value=\"" + _sessionId + "\" />";
194
195               _output.append(phpSessionInputTag );
196             }
197
198             for (String JavaDoc[] entry : _rewriterVars) {
199               String JavaDoc inputTag =
200                 "<input type=\"hidden\" name=\"" + entry[0] + "\"" +
201                 " value=\"" + entry[1] + "\" />";
202               _output.append(inputTag);
203             }
204           } else {
205             int valueEnd = 0;
206
207             for (valueEnd = getNextAttribute(attribute);
208                  valueEnd == 0;
209                  valueEnd = getNextAttribute(attribute))
210             {}
211
212             if (valueEnd > 0) {
213               _output.append(rewriteUrl(_value));
214
215               if (_quoted)
216                 consumeOneCharacter();
217             }
218           }
219         }
220       }
221
222       return _output;
223     }
224
225     /**
226      * Finds the next tag in the string returns it.
227      */

228     private String JavaDoc getNextTag()
229     {
230       int tagStart = _input.indexOf('<', _index);
231
232       if (tagStart < 0) {
233         _output.append(_input.substring(_index));
234         return null;
235       }
236
237       // consume everything upto the tag opening
238
_output.append(_input.substring(_index, tagStart + 1));
239
240       // skip the '<'
241
_index = tagStart + 1;
242       
243       consumeNonWhiteSpace();
244
245       return _input.substring(tagStart + 1, _index);
246     }
247
248     /**
249      * Finds the next attribute matching the given name.
250      *
251      * @return -1 if no more valid attributes can be found, 0 if the next
252      * attribute is not the one sought, and 1 if the attribute was found.
253      *
254      * The _index pointer will refer to the end position for the value
255      * in the _input in the final case, but only those characters up to
256      * the beginning of the value will have been copied to the output.
257      */

258     private int getNextAttribute(String JavaDoc attribute)
259     {
260       consumeWhiteSpace();
261
262       int attributeStart = _index;
263
264       while (_index < _input.length() &&
265              isValidAttributeCharacter(_input.charAt(_index)))
266         consumeOneCharacter();
267         
268       // no valid attribute was found (we're probably at the end of the tag)
269
if (_index == attributeStart)
270         return -1;
271
272       String JavaDoc foundAttribute = _input.substring(attributeStart, _index);
273
274       consumeWhiteSpace();
275
276       // Any attributes that we will affect are of the form attr=value
277
if (_input.length() <= _index || _input.charAt(_index) != '=')
278         return -1;
279
280       consumeOneCharacter();
281
282       consumeWhiteSpace();
283
284       // check for quoting
285
char quote = ' ';
286       
287       if (_input.charAt(_index) == '"' || _input.charAt(_index) == '\'') {
288         _quoted = true;
289         quote = _input.charAt(_index);
290
291         consumeOneCharacter();
292       }
293
294       int valueEnd = _index;
295       
296       if (_quoted) {
297         valueEnd = _input.indexOf(quote, _index);
298       
299         // try to account for unclosed quotes
300
int tagEnd = _input.indexOf('>', _index);
301
302         if (valueEnd < 0) {
303           if (tagEnd > 0)
304             valueEnd = tagEnd;
305           else
306             valueEnd = _input.length();
307         }
308       } else {
309         // skip to the end of the value
310
for (valueEnd = _index;
311              valueEnd < _input.length() &&
312              _input.charAt(valueEnd) != '/' &&
313              _input.charAt(valueEnd) != '>' &&
314              _input.charAt(valueEnd) != ' ';
315              valueEnd++) {}
316       }
317
318       if (foundAttribute.equals(attribute)) {
319         _value = _input.substring(_index, valueEnd);
320
321         _index = valueEnd;
322
323         return 1;
324       } else {
325         // make sure to skip the complete attribute if it's not the
326
// one we're looking for.
327
if (_quoted)
328           valueEnd += 1;
329
330         _output.append(_input.substring(_index, valueEnd));
331
332         _index = valueEnd;
333
334         return 0;
335       }
336     }
337
338     private void consumeOneCharacter()
339     {
340       if (_index < _input.length()) {
341         _output.append(_input.charAt(_index));
342         _index += 1;
343       }
344     }
345
346     private void consumeWhiteSpace()
347     {
348       while (_index < _input.length() &&
349              Character.isWhitespace(_input.charAt(_index)))
350         consumeOneCharacter();
351     }
352
353     private void consumeNonWhiteSpace()
354     {
355       while (_index < _input.length() &&
356              !Character.isWhitespace(_input.charAt(_index)))
357         consumeOneCharacter();
358     }
359
360     private void consumeToEndOfTag()
361     {
362       while (_input.charAt(_index) != '>')
363         consumeOneCharacter();
364
365       // consume the '>'
366
consumeOneCharacter();
367     }
368
369     private boolean isValidAttributeCharacter(char ch)
370     {
371       return Character.isLetterOrDigit(ch) ||
372              (ch == '-') || (ch == '.') || (ch == '_') || (ch == ':');
373     }
374
375     private String JavaDoc rewriteUrl(String JavaDoc urlString)
376     {
377       // according to php documentation, it only adds tags to the
378
// end of relative URLs, but according to RFC 2396, any
379
// URI beginning with '/' (e.g. <a HREF="../../../../../foo">link</a>) is
380
// absolute. Nonetheless, php does add session ids to these
381
// links. Thus php must be defining "relative" as relative
382
// to the host, not the hierarchy. Thus we only check to make
383
// sure that the scheme and authority are undefined, not that
384
// the first character of the path begins with '/'.
385

386       URI JavaDoc uri;
387
388       try {
389         uri = new URI JavaDoc(urlString);
390       } catch (URISyntaxException JavaDoc e) {
391         return urlString;
392       }
393
394       if ((uri.getScheme() != null) || (uri.getAuthority() != null)) {
395         return urlString;
396       }
397
398       StringBuilder JavaDoc query = new StringBuilder JavaDoc();
399
400       if (uri.getQuery() != null) {
401         query.append("?");
402         query.append(uri.getQuery());
403         query.append("&");
404       }
405       else
406         query.append("?");
407
408       if (_includeSessionInfo) {
409         query.append(_sessionName);
410         query.append("=");
411         query.append(_sessionId);
412       }
413
414       if (_rewriterQuery.length() != 0) {
415         if (_includeSessionInfo)
416           query.append("&");
417
418         query.append(_rewriterQuery);
419       }
420
421       StringBuilder JavaDoc newUri = new StringBuilder JavaDoc();
422
423       if (uri.getPath() != null)
424         newUri.append(uri.getPath());
425
426       newUri.append(query);
427
428       if (uri.getFragment() != null) {
429         newUri.append("#");
430         newUri.append(uri.getFragment());
431       }
432
433       return newUri.toString();
434     }
435   }
436 }
437
Popular Tags