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