Index: reporting/jsp/build.xml =================================================================== --- reporting/jsp/build.xml (revision 2700) +++ reporting/jsp/build.xml (working copy) @@ -91,7 +91,7 @@ - + Index: reporting/jsp/lib/jsp-api-2.0.jar =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: reporting\jsp\lib\jsp-api-2.0.jar ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: reporting/jsp/lib/servlet-api-2.4.jar =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: reporting\jsp\lib\servlet-api-2.4.jar ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: reporting/jsp/lib/servlet.jar =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: reporting/jsp/src/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTag.java =================================================================== --- reporting/jsp/src/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTag.java (revision 2700) +++ reporting/jsp/src/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTag.java (working copy) @@ -77,6 +77,8 @@ private String getArtifactURL() throws JspException { StringBuffer urlBuffer = new StringBuffer(); + urlBuffer.append(getRequest().getContextPath()); + urlBuffer.append("/"); urlBuffer.append(ARTIFACTS_SERVLET_CONTEXT); String project = getProject(); if (project.length() > 0) { Index: reporting/jsp/src/net/sourceforge/cruisecontrol/taglib/TabSheetTag.java =================================================================== --- reporting/jsp/src/net/sourceforge/cruisecontrol/taglib/TabSheetTag.java (revision 2700) +++ reporting/jsp/src/net/sourceforge/cruisecontrol/taglib/TabSheetTag.java (working copy) @@ -64,13 +64,13 @@ + EOL + " " + EOL - + " " + + " " + EOL + " " + EOL; private static final String END_SHEET = " " + EOL - + " " + + " " + EOL + " " + EOL @@ -123,11 +123,13 @@ } private void endTable(final JspWriter out) throws IOException { - out.write(END_SHEET); + final String endSheet = new String(END_SHEET).replaceAll("@contextPath@", getRequest().getContextPath()); + out.write(endSheet); } private void startTable(final JspWriter out) throws IOException { - out.write(START_SHEET); + final String startSheet = new String(START_SHEET).replaceAll("@contextPath@", getRequest().getContextPath()); + out.write(startSheet); } private void clearTabs() { Index: reporting/jsp/src/net/sourceforge/cruisecontrol/util/URLProxyResolver.java =================================================================== --- reporting/jsp/src/net/sourceforge/cruisecontrol/util/URLProxyResolver.java (revision 0) +++ reporting/jsp/src/net/sourceforge/cruisecontrol/util/URLProxyResolver.java (revision 0) @@ -0,0 +1,132 @@ +package net.sourceforge.cruisecontrol.util; + +import java.util.StringTokenizer; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Helper for getting the proxy real hostname/port.
+ * + * Available headers from cruisecontrol when accessed with an apache proxy (tested with apache 2.2).
+ *
    + *
  • Host - [ccontrol_hostame]:[ccontrol_port] ex: localhost:8080
  • + *
  • User-Agent - Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.7) Gecko/20060909 Firefox/1.5.0.7
  • + *
  • Accept - text/xml,application/xml,application/xhtml+xml,text/html;...
  • + *
  • Accept-Language - fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
  • + *
  • Accept-Encoding - gzip,deflate
  • + *
  • Accept-Charset - ISO-8859-1,utf-8;q=0.7,*;q=0.7
  • + *
  • Cookie - JSESSIONID=3m1p9evfp7x49
  • + *
  • Cache-Control - max-age=0
  • + *
  • Max-Forwards - 10
  • + *
  • X-Forwarded-For - [the browser IP than asked for the page]
  • + *
  • X-Forwarded-Host - [proxy_hostname] or [proxy_hostname]:[port_number] + * (port_number = if it was written in the URL the end-user typed)
  • + *
  • X-Forwarded-Server - [proxy_IP]
  • + *
  • Connection - keep-alive
  • + *
+ */ +public class URLProxyResolver { + public static final String X_FORWARDED_FOR = "X-Forwarded-For"; + public static final String X_FORWARDED_HOST = "X-Forwarded-Host"; + + private final HttpServletRequest request; + + public URLProxyResolver(final HttpServletRequest request) { + if (isProxied(request)) { + this.request = new UnProxyServletRequest(request); + } else { + this.request = request; + } + } + + public HttpServletRequest getRequest() { + return request; + } + + public static boolean isProxied(final HttpServletRequest request) { + return request.getHeader(X_FORWARDED_FOR) != null; + } + + /** + * This implementation assumes that both X-Forwarded-For and X-Forwarded-Host exist in the request + * otherwise if it is not the case and the application use the getRemoteAddr() and getRemoteHost() + * there will be some strange results. :) + * + *
  • X-Forwarded-Host: host.name.com
  • + *
  • X-Forwarded-For: [browser's IP]
+ */ + private class UnProxyServletRequest extends HttpServletRequestWrapper { + + private final Log log = LogFactory.getLog(UnProxyServletRequest.class); + + private final String remoteHost; + private final int remotePort; + + public UnProxyServletRequest(final HttpServletRequest request) { + super(request); + // X-forwarded-host contains also the port as hostname:port + // if the user typed something like localhost:port in the browser address bar + String host = getProxyHeader(X_FORWARDED_HOST); + if (log.isDebugEnabled()) { + log.debug("host: " + host); + } + remoteHost = (host != null ? host : super.getRemoteHost()); + + remotePort = extractPortNumber(host); + } + + public String getRemoteAddr() { + String ip = getProxyHeader(X_FORWARDED_FOR); + if (log.isDebugEnabled()) { + log.debug("ip: " + ip); + } + return ip != null ? ip : super.getRemoteAddr(); + } + + public String getRemoteHost() { + return remoteHost; + } + + public int getRemotePort() { + return remotePort; + } + + public String getScheme() { + if (remotePort == 443) { + return "https"; + } + return super.getScheme(); + } + + private int extractPortNumber(final String host) { + final StringTokenizer tokenizer = new StringTokenizer(host, ":"); + if (tokenizer.countTokens() < 2) { + return super.getRemotePort(); + } + + String token = Integer.toString(super.getRemotePort()); + while (tokenizer.hasMoreTokens()) { + token = tokenizer.nextToken(); + } + return Integer.parseInt(token); + } + + protected String getProxyHeader(final String name) { + String value = getHeader(name); + if (value == null) { + return null; + } + // apparently in case of chained proxies you have comma separated ips/host + boolean unique = (value.indexOf(',') == -1); + if (unique) { + return value; + } + String[] ips = value.split(","); + return ips[ips.length - 1]; + } + } +} Property changes on: reporting\jsp\src\net\sourceforge\cruisecontrol\util\URLProxyResolver.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + Date Revision Author HeadURL Id Name: svn:eol-style + native Index: reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockPageContext.java =================================================================== --- reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockPageContext.java (revision 2700) +++ reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockPageContext.java (working copy) @@ -48,6 +48,8 @@ import javax.servlet.http.HttpSession; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.el.ExpressionEvaluator; +import javax.servlet.jsp.el.VariableResolver; /** * @@ -156,4 +158,24 @@ public void setHttpServletRequest(MockServletRequest mockRequest) { request = mockRequest; } + + public void handlePageException(Throwable arg0) throws ServletException, IOException { + // TODO Auto-generated method stub + + } + + public void include(String arg0, boolean arg1) throws ServletException, IOException { + // TODO Auto-generated method stub + + } + + public ExpressionEvaluator getExpressionEvaluator() { + // TODO Auto-generated method stub + return null; + } + + public VariableResolver getVariableResolver() { + // TODO Auto-generated method stub + return null; + } } Index: reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockServletContext.java =================================================================== --- reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockServletContext.java (revision 2700) +++ reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockServletContext.java (working copy) @@ -46,6 +46,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Map; +import java.util.Set; import javax.servlet.ServletContext; import javax.servlet.RequestDispatcher; @@ -161,4 +162,14 @@ public void setBaseResourceDir(File dir) { baseResourceDir = dir; } + + public Set getResourcePaths(String arg0) { + // TODO Auto-generated method stub + return null; + } + + public String getServletContextName() { + // TODO Auto-generated method stub + return null; + } } Index: reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockServletRequest.java =================================================================== --- reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockServletRequest.java (revision 2700) +++ reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockServletRequest.java (working copy) @@ -38,6 +38,7 @@ import java.io.BufferedReader; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.security.Principal; import java.util.Enumeration; import java.util.Locale; @@ -45,6 +46,8 @@ import java.util.HashMap; import java.util.Collections; import java.util.ArrayList; +import java.util.Random; + import javax.servlet.RequestDispatcher; import javax.servlet.ServletInputStream; import javax.servlet.http.Cookie; @@ -56,6 +59,11 @@ * @author Robert Watkins */ public class MockServletRequest implements HttpServletRequest { + + private static final String LOCALHOST = "localhost"; + private static final String LOCALHOST_IP = "127.0.0.1"; + private static final int PORT = 8080; + private Map headers = new HashMap(); private String contextPath = ""; private String servletPath; private Map params = new HashMap(); @@ -115,19 +123,19 @@ } public String getProtocol() { - return null; + return "HTTP/1.1"; } public String getScheme() { - return null; + return "http"; } public String getServerName() { - return null; + return LOCALHOST; } public int getServerPort() { - return 0; + return PORT; } public BufferedReader getReader() throws IOException { @@ -135,11 +143,11 @@ } public String getRemoteAddr() { - return null; + return LOCALHOST_IP; } public String getRemoteHost() { - return null; + return LOCALHOST_IP; } public void setAttribute(String s, Object o) { @@ -180,7 +188,11 @@ return 0; } - public String getHeader(String s) { + public String getHeader(String name) { + final Object value = headers.get(name); + if (value != null) { + return value.toString(); + } return null; } @@ -288,4 +300,39 @@ public void setLocale(Locale locale) { this.locale = locale; } + + public StringBuffer getRequestURL() { + // TODO Auto-generated method stub + return null; + } + + public String getLocalAddr() { + return LOCALHOST_IP; + } + + public String getLocalName() { + return LOCALHOST; + } + + public int getLocalPort() { + return PORT; + } + + public Map getParameterMap() { + // TODO Auto-generated method stub + return null; + } + + public int getRemotePort() { + return (new Random(System.currentTimeMillis())).nextInt(); + } + + public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException { + // TODO Auto-generated method stub + + } + + public void setHeaders(Map headers) { + this.headers = headers; + } } Index: reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockServletResponse.java =================================================================== --- reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockServletResponse.java (revision 2700) +++ reporting/jsp/test/net/sourceforge/cruisecontrol/mock/MockServletResponse.java (working copy) @@ -254,4 +254,14 @@ public Locale getLocale() { return null; } + + public void resetBuffer() { + // TODO Auto-generated method stub + + } + + public void setCharacterEncoding(String arg0) { + // TODO Auto-generated method stub + + } } Index: reporting/jsp/test/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTagTest.java =================================================================== --- reporting/jsp/test/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTagTest.java (revision 2700) +++ reporting/jsp/test/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTagTest.java (working copy) @@ -97,7 +97,7 @@ request.addParameter("log", "log20030611123100"); tag.doInitBody(); String url = (String) pageContext.getAttribute(ArtifactsLinkTag.URL_ATTRIBUTE); - assertEquals("artifacts/20030611123100", url); + assertEquals("/context/artifacts/20030611123100", url); request.removeParameter("log"); } Index: reporting/jsp/test/net/sourceforge/cruisecontrol/taglib/TabSheetTagTest.java =================================================================== --- reporting/jsp/test/net/sourceforge/cruisecontrol/taglib/TabSheetTagTest.java (revision 2700) +++ reporting/jsp/test/net/sourceforge/cruisecontrol/taglib/TabSheetTagTest.java (working copy) @@ -72,10 +72,10 @@ private static final String START_SHEET = "" + "\r\n" + " \r\n" - + " \r\n" + + " \r\n" + " \r\n"; private static final String END_OF_TABLE = " \r\n" - + " \r\n" + + " \r\n" + " \r\n" + "
\r\n"; private static final String START_OF_HEADERS = "
<ww:property value="project"/> Configuration - - - + + + Index: reporting/jsp/webcontent/controlpanel.jsp =================================================================== --- reporting/jsp/webcontent/controlpanel.jsp (revision 2700) +++ reporting/jsp/webcontent/controlpanel.jsp (working copy) @@ -35,12 +35,21 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************************--%> <%@ taglib uri="/WEB-INF/cruisecontrol-jsp11.tld" prefix="cruisecontrol"%> -<%@page import="java.net.*,java.io.*"%> +<%@page import="java.net.*,java.io.*, + net.sourceforge.cruisecontrol.util.URLProxyResolver"%> <% - URL jmx = new URL(jmxBase, "mbean?objectname=CruiseControl+Project%3Aname%3D" + - request.getPathInfo().substring(1)); + String jmx; + if (URLProxyResolver.isProxied(request)) { + jmx = request.getContextPath() + "/jmx/mbean?objectname=CruiseControl+Project%3Aname%3D" + + request.getPathInfo().substring(1); + } else { + URL url = new URL(jmxBase, "mbean?objectname=CruiseControl+Project%3Aname%3D" + + request.getPathInfo().substring(1)); + jmx = url.toExternalForm(); + } %> +

@@ -51,7 +60,7 @@ Index: reporting/jsp/webcontent/error.jsp =================================================================== --- reporting/jsp/webcontent/error.jsp (revision 2700) +++ reporting/jsp/webcontent/error.jsp (working copy) @@ -39,11 +39,7 @@ java.io.PrintWriter, javax.servlet.http.HttpUtils"%> <% - String baseURL = request.getScheme() + "://" + request.getServerName(); - if (!request.getScheme().equals("http") || request.getServerPort() != 80) { - baseURL += ":" + request.getServerPort(); - } - baseURL += request.getContextPath() + "/"; + String baseURL = request.getContextPath() + "/"; String message = exception.getMessage(); if (message == null) { message = "(null)"; Index: reporting/jsp/webcontent/index.jsp =================================================================== --- reporting/jsp/webcontent/index.jsp (revision 2700) +++ reporting/jsp/webcontent/index.jsp (working copy) @@ -50,8 +50,8 @@ <%@ page import="java.util.Date" %> <%@ page import="java.util.Comparator" %> <%@ page import="java.util.Map" %> +<%@ page import="net.sourceforge.cruisecontrol.util.URLProxyResolver" %> - <% final DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, request.getLocale()); final DateFormat dateOnlyFormat = DateFormat.getDateInstance(DateFormat.SHORT, request.getLocale()); @@ -127,12 +127,16 @@ String name = System.getProperty("ccname", ""); String hostname = InetAddress.getLocalHost().getHostName(); boolean jmxEnabled = true; - URL jmxURLPrefix = new URL(jmxBase, "invoke?operation=build&objectname=CruiseControl+Project%3Aname%3D"); + String jmx; + if (URLProxyResolver.isProxied(request)) { + jmx = request.getContextPath() + "/jmx/invoke?operation=build&objectname=CruiseControl+Project%3Aname%3D"; + } else { + URL url = new URL(jmxBase, "invoke?operation=build&objectname=CruiseControl+Project%3Aname%3D"); + jmx = url.toExternalForm(); + } final String statusFileName = application.getInitParameter("currentBuildStatusFile"); - String baseURL = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() - + request.getContextPath() + "/"; String thisURL = request.getRequestURI(); String sort = request.getParameter("sort"); @@ -315,9 +319,8 @@ <%= name%> CruiseControl at <%= hostname %> - - - + +