001 /*
002 Licensed to the Apache Software Foundation (ASF) under one
003 or more contributor license agreements. See the NOTICE file
004 distributed with this work for additional information
005 regarding copyright ownership. The ASF licenses this file
006 to you under the Apache License, Version 2.0 (the
007 "License"); you may not use this file except in compliance
008 with the License. You may obtain a copy of the License at
009
010 http://www.apache.org/licenses/LICENSE-2.0
011
012 Unless required by applicable law or agreed to in writing,
013 software distributed under the License is distributed on an
014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 KIND, either express or implied. See the License for the
016 specific language governing permissions and limitations
017 under the License.
018 */
019 package org.apache.wiki.url;
020
021 import java.io.UnsupportedEncodingException;
022 import java.net.MalformedURLException;
023 import java.net.URL;
024 import java.util.Properties;
025
026 import javax.servlet.http.HttpServletRequest;
027
028 import org.apache.commons.lang.StringUtils;
029
030 import org.apache.wiki.WikiContext;
031 import org.apache.wiki.WikiEngine;
032 import org.apache.wiki.ui.Command;
033 import org.apache.wiki.ui.CommandResolver;
034 import org.apache.wiki.util.TextUtil;
035
036 /**
037 * Implements the default URL constructor using links directly to the
038 * JSP pages. This is what JSPWiki by default is using. For example,
039 * WikiContext.VIEW points at "Wiki.jsp", etc.
040 *
041 * @since 2.2
042 */
043 public class DefaultURLConstructor
044 implements URLConstructor
045 {
046 protected WikiEngine m_engine;
047
048 /**
049 * Contains the absolute path of the JSPWiki Web application without the
050 * actual servlet (which is the m_urlPrefix).
051 */
052 protected String m_pathPrefix = "";
053
054 /**
055 *
056 * {@inheritDoc}
057 */
058 public void initialize( WikiEngine engine,
059 Properties properties )
060 {
061 m_engine = engine;
062
063 String baseurl = engine.getBaseURL();
064
065 if( baseurl != null && baseurl.length() > 0 )
066 {
067 try
068 {
069 URL url = new URL( baseurl );
070
071 String path = url.getPath();
072
073 m_pathPrefix = path;
074 }
075 catch( MalformedURLException e )
076 {
077 m_pathPrefix = "/JSPWiki/"; // Just a guess.
078 }
079 }
080 }
081
082 /**
083 * Does replacement of some particular variables. The variables are:
084 *
085 * <ul>
086 * <li> "%u" - inserts either the base URL (when absolute is required), or the base path
087 * (which is an absolute path without the host name).
088 * <li> "%U" - always inserts the base URL
089 * <li> "%p" - always inserts the base path
090 * <li> "%n" - inserts the page name
091 * </ul>
092 *
093 * @param baseptrn The pattern to use
094 * @param name The page name
095 * @param absolute If true, %u is always the entire base URL, otherwise it depends on
096 * the setting in jspwiki.properties.
097 * @return A replacement.
098 */
099 protected final String doReplacement( String baseptrn, String name, boolean absolute )
100 {
101 String baseurl = m_pathPrefix;
102
103 if( absolute ) baseurl = m_engine.getBaseURL();
104
105 baseptrn = TextUtil.replaceString( baseptrn, "%u", baseurl );
106 baseptrn = TextUtil.replaceString( baseptrn, "%U", m_engine.getBaseURL() );
107 baseptrn = TextUtil.replaceString( baseptrn, "%n", encodeURI(name) );
108 baseptrn = TextUtil.replaceString( baseptrn, "%p", m_pathPrefix );
109
110 return baseptrn;
111 }
112
113 /**
114 * URLEncoder returns pluses, when we want to have the percent
115 * encoding. See http://issues.apache.org/bugzilla/show_bug.cgi?id=39278
116 * for more info.
117 *
118 * We also convert any %2F's back to slashes to make nicer-looking URLs.
119 */
120 private String encodeURI( String uri )
121 {
122 uri = m_engine.encodeName(uri);
123
124 uri = StringUtils.replace( uri, "+", "%20" );
125 uri = StringUtils.replace( uri, "%2F", "/" );
126
127 return uri;
128 }
129
130 /**
131 * Returns the URL pattern for a supplied wiki request context.
132 * @param context the wiki context
133 * @param name the wiki page
134 * @return A pattern for replacement.
135 * @throws IllegalArgumentException if the context cannot be found
136 */
137 public static String getURLPattern( String context, String name )
138 throws IllegalArgumentException
139 {
140 if( context.equals(WikiContext.VIEW) && name == null)
141 {
142 // FIXME
143 return "%uWiki.jsp";
144 }
145
146 // Find the action matching our pattern (could throw exception)
147 Command command = CommandResolver.findCommand( context );
148
149 return command.getURLPattern();
150 }
151
152 /**
153 * Constructs the actual URL based on the context.
154 */
155 private String makeURL( String context,
156 String name,
157 boolean absolute )
158 {
159 return doReplacement( getURLPattern(context,name), name, absolute );
160 }
161
162 /**
163 * Constructs the URL with a bunch of parameters.
164 * @param parameters If null or empty, no parameters are added.
165 *
166 * {@inheritDoc}
167 */
168 public String makeURL( String context,
169 String name,
170 boolean absolute,
171 String parameters )
172 {
173 if( parameters != null && parameters.length() > 0 )
174 {
175 if( context.equals(WikiContext.ATTACH) )
176 {
177 parameters = "?"+parameters;
178 }
179 else if( context.equals(WikiContext.NONE) )
180 {
181 parameters = (name.indexOf('?') != -1 ) ? "&" : "?" + parameters;
182 }
183 else
184 {
185 parameters = "&"+parameters;
186 }
187 }
188 else
189 {
190 parameters = "";
191 }
192 return makeURL( context, name, absolute )+parameters;
193 }
194
195 /**
196 * Should parse the "page" parameter from the actual
197 * request.
198 *
199 * {@inheritDoc}
200 */
201 public String parsePage( String context,
202 HttpServletRequest request,
203 String encoding )
204 throws UnsupportedEncodingException
205 {
206 String pagereq = request.getParameter( "page" );
207
208 if( context.equals(WikiContext.ATTACH) )
209 {
210 pagereq = parsePageFromURL( request, encoding );
211 }
212
213 return pagereq;
214 }
215
216 /**
217 * There's a bug in Tomcat until 5.5.16 at least: The "+" sign is not
218 * properly decoded by the servlet container, and therefore request.getPathInfo()
219 * will return faulty results for paths which contains + signs to signify spaces.
220 * <p>
221 * This method provides a workaround by simply parsing the getRequestURI(), which
222 * is returned from the servlet container undedecoded.
223 * <p>
224 * Please see <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=39278">Tomcat Bug 39278</a>
225 * for more information.
226 *
227 * @param request A HTTP servlet request
228 * @param encoding The used encoding
229 * @return a String, decoded by JSPWiki, specifying extra path information that comes
230 * after the servlet path but before the query string in the request URL;
231 * or null if the URL does not have any extra path information
232 * @throws UnsupportedEncodingException
233 */
234 /*
235 private static String getPathInfo( HttpServletRequest request, String encoding )
236 throws UnsupportedEncodingException
237 {
238 String c = request.getContextPath(); // Undecoded
239 String s = request.getServletPath(); // Decoded
240 String u = request.getRequestURI(); // Undecoded
241
242 c = URLDecoder.decode( c, encoding );
243 u = URLDecoder.decode( u, encoding );
244
245 String pi = u.substring( s.length()+c.length() );
246
247 if( pi.length() == 0 ) pi = null;
248
249 return pi;
250 }
251 */
252 /**
253 * Takes the name of the page from the request URI.
254 * The initial slash is also removed. If there is no page,
255 * returns null.
256 *
257 * @param request The request to parse
258 * @param encoding The encoding to use
259 *
260 * @return a parsed page name, or null, if it cannot be found
261 *
262 * @throws UnsupportedEncodingException If the encoding is not recognized.
263 */
264 public static String parsePageFromURL( HttpServletRequest request,
265 String encoding )
266 throws UnsupportedEncodingException
267 {
268 String name = request.getPathInfo();
269
270 if( name == null || name.length() <= 1 )
271 {
272 return null;
273 }
274 else if( name.charAt(0) == '/' )
275 {
276 name = name.substring(1);
277 }
278
279 //
280 // This is required, because by default all URLs are handled
281 // as Latin1, even if they are really UTF-8.
282 //
283
284 // name = TextUtil.urlDecode( name, encoding );
285
286 return name;
287 }
288
289
290 /**
291 * This method is not needed for the DefaultURLConstructor.
292 *
293 * @param request The HTTP Request that was used to end up in this page.
294 * @return "Wiki.jsp", "PageInfo.jsp", etc. Just return the name,
295 * JSPWiki will figure out the page.
296 */
297 public String getForwardPage( HttpServletRequest request )
298 {
299 return request.getPathInfo();
300 }
301 }