2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.thrift
;
20 import static org
.apache
.hadoop
.hbase
.thrift
.TestThriftServerCmdLine
.createBoundServer
;
21 import static org
.junit
.Assert
.assertFalse
;
22 import static org
.junit
.Assert
.fail
;
24 import java
.io
.IOException
;
25 import java
.net
.HttpURLConnection
;
27 import java
.util
.function
.Supplier
;
28 import org
.apache
.hadoop
.conf
.Configuration
;
29 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
30 import org
.apache
.hadoop
.hbase
.HBaseTestingUtil
;
31 import org
.apache
.hadoop
.hbase
.HConstants
;
32 import org
.apache
.hadoop
.hbase
.testclassification
.ClientTests
;
33 import org
.apache
.hadoop
.hbase
.testclassification
.LargeTests
;
34 import org
.apache
.hadoop
.hbase
.thrift
.generated
.Hbase
;
35 import org
.apache
.hadoop
.hbase
.util
.EnvironmentEdgeManager
;
36 import org
.apache
.hadoop
.hbase
.util
.EnvironmentEdgeManagerTestHelper
;
37 import org
.apache
.hadoop
.hbase
.util
.IncrementingEnvironmentEdge
;
38 import org
.apache
.hadoop
.hbase
.util
.TableDescriptorChecker
;
39 import org
.apache
.thrift
.protocol
.TBinaryProtocol
;
40 import org
.apache
.thrift
.protocol
.TProtocol
;
41 import org
.apache
.thrift
.transport
.THttpClient
;
42 import org
.apache
.thrift
.transport
.TTransportException
;
43 import org
.junit
.AfterClass
;
44 import org
.junit
.Assert
;
45 import org
.junit
.BeforeClass
;
46 import org
.junit
.ClassRule
;
47 import org
.junit
.Rule
;
48 import org
.junit
.Test
;
49 import org
.junit
.experimental
.categories
.Category
;
50 import org
.junit
.rules
.ExpectedException
;
51 import org
.slf4j
.Logger
;
52 import org
.slf4j
.LoggerFactory
;
54 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.base
.Joiner
;
57 * Start the HBase Thrift HTTP server on a random port through the command-line
58 * interface and talk to it from client side.
60 @Category({ClientTests
.class, LargeTests
.class})
61 public class TestThriftHttpServer
{
63 public static final HBaseClassTestRule CLASS_RULE
=
64 HBaseClassTestRule
.forClass(TestThriftHttpServer
.class);
66 private static final Logger LOG
=
67 LoggerFactory
.getLogger(TestThriftHttpServer
.class);
69 protected static final HBaseTestingUtil TEST_UTIL
= new HBaseTestingUtil();
72 public static void setUpBeforeClass() throws Exception
{
73 TEST_UTIL
.getConfiguration().setBoolean(Constants
.USE_HTTP_CONF_KEY
, true);
74 TEST_UTIL
.getConfiguration().setBoolean(TableDescriptorChecker
.TABLE_SANITY_CHECKS
, false);
75 TEST_UTIL
.startMiniCluster();
76 //ensure that server time increments every time we do an operation, otherwise
77 //successive puts having the same timestamp will override each other
78 EnvironmentEdgeManagerTestHelper
.injectEdge(new IncrementingEnvironmentEdge());
82 public static void tearDownAfterClass() throws Exception
{
83 TEST_UTIL
.shutdownMiniCluster();
84 EnvironmentEdgeManager
.reset();
88 public void testExceptionThrownWhenMisConfigured() throws IOException
{
89 Configuration conf
= new Configuration(TEST_UTIL
.getConfiguration());
90 conf
.set("hbase.thrift.security.qop", "privacy");
91 conf
.setBoolean("hbase.thrift.ssl.enabled", false);
92 ExpectedException thrown
= ExpectedException
.none();
93 ThriftServerRunner tsr
= null;
95 thrown
.expect(IllegalArgumentException
.class);
96 thrown
.expectMessage("Thrift HTTP Server's QoP is privacy, " +
97 "but hbase.thrift.ssl.enabled is false");
98 tsr
= TestThriftServerCmdLine
.createBoundServer(() -> new ThriftServer(conf
));
99 fail("Thrift HTTP Server starts up even with wrong security configurations.");
100 } catch (Exception e
) {
101 LOG
.info("Expected!", e
);
110 public ExpectedException exception
= ExpectedException
.none();
113 public void testRunThriftServerWithHeaderBufferLength() throws Exception
{
114 // Test thrift server with HTTP header length less than 64k
116 runThriftServer(1024 * 63);
117 } catch (TTransportException tex
) {
118 assertFalse(tex
.getMessage().equals("HTTP Response code: 431"));
121 // Test thrift server with HTTP header length more than 64k, expect an exception
122 exception
.expect(TTransportException
.class);
123 exception
.expectMessage("HTTP Response code: 431");
124 runThriftServer(1024 * 64);
127 protected Supplier
<ThriftServer
> getThriftServerSupplier() {
128 return () -> new ThriftServer(TEST_UTIL
.getConfiguration());
132 public void testRunThriftServer() throws Exception
{
136 void runThriftServer(int customHeaderSize
) throws Exception
{
137 // Add retries in case we see stuff like connection reset
138 Exception clientSideException
= null;
139 for (int i
= 0; i
< 10; i
++) {
140 clientSideException
= null;
141 ThriftServerRunner tsr
= createBoundServer(getThriftServerSupplier());
142 String url
= "http://" + HConstants
.LOCALHOST
+ ":" + tsr
.getThriftServer().listenPort
;
144 checkHttpMethods(url
);
145 talkToThriftServer(url
, customHeaderSize
);
147 } catch (Exception ex
) {
148 clientSideException
= ex
;
149 LOG
.info("Client-side Exception", ex
);
153 if (tsr
.getRunException() != null) {
154 LOG
.error("Invocation of HBase Thrift server threw exception", tsr
.getRunException());
155 throw tsr
.getRunException();
160 if (clientSideException
!= null) {
161 LOG
.error("Thrift Client", clientSideException
);
162 throw clientSideException
;
166 private void checkHttpMethods(String url
) throws Exception
{
167 // HTTP TRACE method should be disabled for security
168 // See https://www.owasp.org/index.php/Cross_Site_Tracing
169 HttpURLConnection conn
= (HttpURLConnection
) new URL(url
).openConnection();
170 conn
.setRequestMethod("TRACE");
172 Assert
.assertEquals(conn
.getResponseMessage(),
173 HttpURLConnection
.HTTP_FORBIDDEN
, conn
.getResponseCode());
176 protected static volatile boolean tableCreated
= false;
178 protected void talkToThriftServer(String url
, int customHeaderSize
) throws Exception
{
179 THttpClient httpClient
= new THttpClient(url
);
182 if (customHeaderSize
> 0) {
183 StringBuilder sb
= new StringBuilder();
184 for (int i
= 0; i
< customHeaderSize
; i
++) {
187 httpClient
.setCustomHeader("User-Agent", sb
.toString());
192 prot
= new TBinaryProtocol(httpClient
);
193 Hbase
.Client client
= new Hbase
.Client(prot
);
195 TestThriftServer
.createTestTables(client
);
198 TestThriftServer
.checkTableList(client
);