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 }