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, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.http; 019 020import java.io.IOException; 021import java.util.Random; 022import javax.servlet.Filter; 023import javax.servlet.FilterChain; 024import javax.servlet.FilterConfig; 025import javax.servlet.ServletException; 026import javax.servlet.ServletRequest; 027import javax.servlet.ServletResponse; 028import javax.servlet.http.HttpServletRequest; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.hbase.HBaseClassTestRule; 031import org.apache.hadoop.hbase.testclassification.MiscTests; 032import org.apache.hadoop.hbase.testclassification.SmallTests; 033import org.apache.hadoop.net.NetUtils; 034import org.apache.hadoop.util.StringUtils; 035import org.junit.Assert; 036import org.junit.ClassRule; 037import org.junit.Ignore; 038import org.junit.Test; 039import org.junit.experimental.categories.Category; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043@Category({MiscTests.class, SmallTests.class}) 044public class TestServletFilter extends HttpServerFunctionalTest { 045 @ClassRule 046 public static final HBaseClassTestRule CLASS_RULE = 047 HBaseClassTestRule.forClass(TestServletFilter.class); 048 049 private static final Logger LOG = LoggerFactory.getLogger(HttpServer.class); 050 private static volatile String uri = null; 051 052 /** A very simple filter which record the uri filtered. */ 053 static public class SimpleFilter implements Filter { 054 private FilterConfig filterConfig = null; 055 056 @Override 057 public void init(FilterConfig filterConfig) throws ServletException { 058 this.filterConfig = filterConfig; 059 } 060 061 @Override 062 public void destroy() { 063 this.filterConfig = null; 064 } 065 066 @Override 067 public void doFilter(ServletRequest request, ServletResponse response, 068 FilterChain chain) throws IOException, ServletException { 069 if (filterConfig == null) { 070 return; 071 } 072 073 uri = ((HttpServletRequest)request).getRequestURI(); 074 LOG.info("filtering " + uri); 075 chain.doFilter(request, response); 076 } 077 078 /** Configuration for the filter */ 079 static public class Initializer extends FilterInitializer { 080 public Initializer() {} 081 082 @Override 083 public void initFilter(FilterContainer container, Configuration conf) { 084 container.addFilter("simple", SimpleFilter.class.getName(), null); 085 } 086 } 087 } 088 089 private static void assertExceptionContains(String string, Throwable t) { 090 String msg = t.getMessage(); 091 Assert.assertTrue( 092 "Expected to find '" + string + "' but got unexpected exception:" 093 + StringUtils.stringifyException(t), msg.contains(string)); 094 } 095 096 @Test 097 @Ignore 098 //From stack 099 // Its a 'foreign' test, one that came in from hadoop when we copy/pasted http 100 // It's second class. Could comment it out if only failing test (as per @nkeywal – sort of) 101 public void testServletFilter() throws Exception { 102 Configuration conf = new Configuration(); 103 104 //start an http server with CountingFilter 105 conf.set(HttpServer.FILTER_INITIALIZERS_PROPERTY, 106 SimpleFilter.Initializer.class.getName()); 107 HttpServer http = createTestServer(conf); 108 http.start(); 109 110 final String fsckURL = "/fsck"; 111 final String stacksURL = "/stacks"; 112 final String ajspURL = "/a.jsp"; 113 final String logURL = "/logs/a.log"; 114 final String hadooplogoURL = "/static/hadoop-logo.jpg"; 115 116 final String[] urls = {fsckURL, stacksURL, ajspURL, logURL, hadooplogoURL}; 117 final Random ran = new Random(); 118 final int[] sequence = new int[50]; 119 120 //generate a random sequence and update counts 121 for(int i = 0; i < sequence.length; i++) { 122 sequence[i] = ran.nextInt(urls.length); 123 } 124 125 //access the urls as the sequence 126 final String prefix = "http://" 127 + NetUtils.getHostPortString(http.getConnectorAddress(0)); 128 try { 129 for (int aSequence : sequence) { 130 access(prefix + urls[aSequence]); 131 132 //make sure everything except fsck get filtered 133 if (aSequence == 0) { 134 assertNull(uri); 135 } else { 136 assertEquals(urls[aSequence], uri); 137 uri = null; 138 } 139 } 140 } finally { 141 http.stop(); 142 } 143 } 144 145 static public class ErrorFilter extends SimpleFilter { 146 @Override 147 public void init(FilterConfig arg0) throws ServletException { 148 throw new ServletException("Throwing the exception from Filter init"); 149 } 150 151 /** Configuration for the filter */ 152 static public class Initializer extends FilterInitializer { 153 public Initializer() { 154 } 155 156 @Override 157 public void initFilter(FilterContainer container, Configuration conf) { 158 container.addFilter("simple", ErrorFilter.class.getName(), null); 159 } 160 } 161 } 162 163 @Test 164 public void testServletFilterWhenInitThrowsException() throws Exception { 165 Configuration conf = new Configuration(); 166 // start an http server with ErrorFilter 167 conf.set(HttpServer.FILTER_INITIALIZERS_PROPERTY, 168 ErrorFilter.Initializer.class.getName()); 169 HttpServer http = createTestServer(conf); 170 try { 171 http.start(); 172 fail("expecting exception"); 173 } catch (IOException e) { 174 assertExceptionContains("Problem starting http server", e); 175 } 176 } 177 178 /** 179 * Similar to the above test case, except that it uses a different API to add the 180 * filter. Regression test for HADOOP-8786. 181 */ 182 @Test 183 public void testContextSpecificServletFilterWhenInitThrowsException() 184 throws Exception { 185 Configuration conf = new Configuration(); 186 HttpServer http = createTestServer(conf); 187 HttpServer.defineFilter(http.webAppContext, 188 "ErrorFilter", ErrorFilter.class.getName(), 189 null, null); 190 try { 191 http.start(); 192 fail("expecting exception"); 193 } catch (IOException e) { 194 assertExceptionContains("Unable to initialize WebAppContext", e); 195 } 196 } 197}