/Users/deen/code/yugabyte-db/src/yb/server/webserver-test.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | |
33 | | #include <iosfwd> |
34 | | #include <string> |
35 | | |
36 | | #include <gtest/gtest.h> |
37 | | |
38 | | #include "yb/gutil/stringprintf.h" |
39 | | #include "yb/gutil/strings/util.h" |
40 | | |
41 | | #include "yb/server/default-path-handlers.h" |
42 | | #include "yb/server/webserver.h" |
43 | | |
44 | | #include "yb/util/curl_util.h" |
45 | | #include "yb/util/net/sockaddr.h" |
46 | | #include "yb/util/status.h" |
47 | | #include "yb/util/status_log.h" |
48 | | #include "yb/util/string_trim.h" |
49 | | #include "yb/util/test_util.h" |
50 | | #include "yb/util/zlib.h" |
51 | | |
52 | | using std::string; |
53 | | using strings::Substitute; |
54 | | |
55 | | DECLARE_int32(webserver_max_post_length_bytes); |
56 | | DECLARE_uint64(webserver_compression_threshold_kb); |
57 | | |
58 | | namespace yb { |
59 | | |
60 | | class WebserverTest : public YBTest { |
61 | | public: |
62 | 6 | WebserverTest() { |
63 | 6 | static_dir_ = GetTestPath("webserver-docroot"); |
64 | 6 | CHECK_OK(env_->CreateDir(static_dir_)); |
65 | | |
66 | 6 | WebserverOptions opts; |
67 | 6 | opts.port = 0; |
68 | 6 | opts.doc_root = static_dir_; |
69 | 6 | server_.reset(new Webserver(opts, "WebserverTest")); |
70 | 6 | } |
71 | | |
72 | 6 | void SetUp() override { |
73 | 6 | YBTest::SetUp(); |
74 | | |
75 | 6 | AddDefaultPathHandlers(server_.get()); |
76 | 6 | ASSERT_OK(server_->Start()); |
77 | | |
78 | 6 | std::vector<Endpoint> addrs; |
79 | 6 | ASSERT_OK(server_->GetBoundAddresses(&addrs)); |
80 | 6 | ASSERT_EQ(addrs.size(), 1); |
81 | 6 | addr_ = addrs[0]; |
82 | 6 | url_ = Substitute("http://$0", ToString(addr_)); |
83 | 6 | } |
84 | | |
85 | | protected: |
86 | | EasyCurl curl_; |
87 | | faststring buf_; |
88 | | std::unique_ptr<Webserver> server_; |
89 | | Endpoint addr_; |
90 | | string url_; |
91 | | |
92 | | string static_dir_; |
93 | | }; |
94 | | |
95 | 1 | TEST_F(WebserverTest, TestIndexPage) { |
96 | 1 | ASSERT_OK(curl_.FetchURL(strings::Substitute("http://$0/", ToString(addr_)), |
97 | 1 | &buf_)); |
98 | | // Should have expected title. |
99 | 1 | ASSERT_STR_CONTAINS(buf_.ToString(), "Yugabyte"); |
100 | | |
101 | | // Should have link to the root path handlers (Home). |
102 | 1 | ASSERT_STR_CONTAINS(buf_.ToString(), "Home"); |
103 | 1 | } |
104 | | |
105 | 1 | TEST_F(WebserverTest, TestHttpCompression) { |
106 | 1 | std::ostringstream oss; |
107 | 1 | string decoded_str; |
108 | 1 | FLAGS_webserver_compression_threshold_kb = 0; |
109 | | |
110 | | // Curl with gzip compression enabled. |
111 | 1 | ASSERT_OK(curl_.FetchURL(url_, &buf_, EasyCurl::kDefaultTimeoutSec, |
112 | 1 | {"Accept-Encoding: deflate, br, gzip"})); |
113 | | |
114 | | // If compressed successfully, we should be able to uncompress. |
115 | 1 | ASSERT_OK(zlib::Uncompress(Slice(buf_.ToString()), &oss)); |
116 | 1 | decoded_str = oss.str(); |
117 | | |
118 | | // Should have expected title. |
119 | 1 | ASSERT_STR_CONTAINS(decoded_str, "YugabyteDB"); |
120 | | |
121 | | // Should have expected header when compressed with headers returned. |
122 | 1 | curl_.set_return_headers(true); |
123 | 1 | ASSERT_OK(curl_.FetchURL(url_, &buf_, EasyCurl::kDefaultTimeoutSec, |
124 | 1 | {"Accept-Encoding: deflate, megaturbogzip, gzip , br"})); |
125 | 1 | ASSERT_STR_CONTAINS(buf_.ToString(), "Content-Encoding: gzip"); |
126 | | |
127 | | |
128 | | // Curl with compression disabled. |
129 | 1 | curl_.set_return_headers(true); |
130 | 1 | ASSERT_OK(curl_.FetchURL(url_, &buf_)); |
131 | | // Check expected header. |
132 | 1 | ASSERT_STR_CONTAINS(buf_.ToString(), "Content-Type:"); |
133 | | |
134 | | // Check unexpected header. |
135 | 1 | ASSERT_STR_NOT_CONTAINS(buf_.ToString(), "Content-Encoding: gzip"); |
136 | | |
137 | | // Should have expected title. |
138 | 1 | ASSERT_STR_CONTAINS(buf_.ToString(), "YugabyteDB"); |
139 | | |
140 | | // Curl with compression enabled but not accepted by YugabyteDB. |
141 | 1 | curl_.set_return_headers(true); |
142 | 1 | ASSERT_OK(curl_.FetchURL(url_, &buf_, EasyCurl::kDefaultTimeoutSec, |
143 | 1 | {"Accept-Encoding: megaturbogzip, deflate, xz"})); |
144 | | // Check expected header. |
145 | 1 | ASSERT_STR_CONTAINS(buf_.ToString(), "HTTP/1.1 200 OK"); |
146 | | |
147 | | // Check unexpected header. |
148 | 1 | ASSERT_STR_NOT_CONTAINS(buf_.ToString(), "Content-Encoding: gzip"); |
149 | | |
150 | | // Should have expected title. |
151 | 1 | ASSERT_STR_CONTAINS(buf_.ToString(), "YugabyteDB"); |
152 | | |
153 | 1 | } |
154 | | |
155 | 1 | TEST_F(WebserverTest, TestDefaultPaths) { |
156 | | // Test memz |
157 | 1 | ASSERT_OK(curl_.FetchURL(strings::Substitute("http://$0/memz?raw=1", ToString(addr_)), |
158 | 1 | &buf_)); |
159 | | #ifdef TCMALLOC_ENABLED |
160 | | ASSERT_STR_CONTAINS(buf_.ToString(), "Bytes in use by application"); |
161 | | #else |
162 | 1 | ASSERT_STR_CONTAINS(buf_.ToString(), "not available unless tcmalloc is enabled"); |
163 | 1 | #endif |
164 | | |
165 | | // Test varz -- check for one of the built-in gflags flags. |
166 | 1 | ASSERT_OK(curl_.FetchURL(strings::Substitute("http://$0/varz?raw=1", ToString(addr_)), |
167 | 1 | &buf_)); |
168 | 1 | ASSERT_STR_CONTAINS(buf_.ToString(), "--v="); |
169 | | |
170 | | // Test status. |
171 | 1 | ASSERT_OK(curl_.FetchURL(strings::Substitute("http://$0/status", ToString(addr_)), |
172 | 1 | &buf_)); |
173 | 1 | ASSERT_STR_EQ_VERBOSE_TRIMMED("{}", buf_.ToString()); |
174 | 1 | } |
175 | | |
176 | | // Used in symbolization test below. |
177 | 0 | void SomeMethodForSymbolTest1() {} |
178 | | // Used in symbolization test below. |
179 | 0 | void SomeMethodForSymbolTest2() {} |
180 | | |
181 | 1 | TEST_F(WebserverTest, TestPprofPaths) { |
182 | | // Test /pprof/cmdline GET |
183 | 1 | ASSERT_OK(curl_.FetchURL(strings::Substitute("http://$0/pprof/cmdline", ToString(addr_)), |
184 | 1 | &buf_)); |
185 | 1 | ASSERT_STR_CONTAINS(buf_.ToString(), "webserver-test"); |
186 | 2 | ASSERT_TRUE(!HasSuffixString(buf_.ToString(), string("\x00", 1))) |
187 | 2 | << "should not have trailing NULL: " << Slice(buf_).ToDebugString(); |
188 | | |
189 | | // Test /pprof/symbol GET |
190 | 1 | ASSERT_OK(curl_.FetchURL(strings::Substitute("http://$0/pprof/symbol", ToString(addr_)), |
191 | 1 | &buf_)); |
192 | 1 | ASSERT_EQ(buf_.ToString(), "num_symbols: 1"); |
193 | | |
194 | | // Test /pprof/symbol POST |
195 | 1 | { |
196 | | // Formulate a request with some valid symbol addresses. |
197 | 1 | string req = StringPrintf("%p+%p", |
198 | 1 | &SomeMethodForSymbolTest1, |
199 | 1 | &SomeMethodForSymbolTest2); |
200 | 1 | SCOPED_TRACE(req); |
201 | 1 | ASSERT_OK(curl_.PostToURL(strings::Substitute("http://$0/pprof/symbol", ToString(addr_)), |
202 | 1 | req, &buf_)); |
203 | 1 | ASSERT_EQ(buf_.ToString(), |
204 | 1 | StringPrintf("%p\tyb::SomeMethodForSymbolTest1()\n" |
205 | 1 | "%p\tyb::SomeMethodForSymbolTest2()\n", |
206 | 1 | &SomeMethodForSymbolTest1, |
207 | 1 | &SomeMethodForSymbolTest2)); |
208 | 1 | } |
209 | 1 | } |
210 | | |
211 | | // Send a POST request with too much data. It should reject |
212 | | // the request with the correct HTTP error code. |
213 | 1 | TEST_F(WebserverTest, TestPostTooBig) { |
214 | 1 | FLAGS_webserver_max_post_length_bytes = 10; |
215 | 1 | string req(10000, 'c'); |
216 | 1 | Status s = curl_.PostToURL(strings::Substitute("http://$0/pprof/symbol", ToString(addr_)), |
217 | 1 | req, &buf_); |
218 | 1 | ASSERT_EQ("Remote error: HTTP 413", s.ToString(/* no file/line */ false)); |
219 | 1 | } |
220 | | |
221 | | // Test that static files are served and that directory listings are |
222 | | // disabled. |
223 | 1 | TEST_F(WebserverTest, TestStaticFiles) { |
224 | | // Fetch a non-existent static file. |
225 | 1 | Status s = curl_.FetchURL(strings::Substitute("http://$0/foo.txt", ToString(addr_)), |
226 | 1 | &buf_); |
227 | 1 | ASSERT_EQ("Remote error: HTTP 404", s.ToString(/* no file/line */ false)); |
228 | | |
229 | | // Create the file and fetch again. This time it should succeed. |
230 | 1 | ASSERT_OK(WriteStringToFile(env_.get(), "hello world", |
231 | 1 | strings::Substitute("$0/foo.txt", static_dir_))); |
232 | 1 | ASSERT_OK(curl_.FetchURL(strings::Substitute("http://$0/foo.txt", ToString(addr_)), |
233 | 1 | &buf_)); |
234 | 1 | ASSERT_EQ("hello world", buf_.ToString()); |
235 | | |
236 | | // Create a directory and ensure that subdirectory listing is disabled. |
237 | 1 | ASSERT_OK(env_->CreateDir(strings::Substitute("$0/dir", static_dir_))); |
238 | 1 | s = curl_.FetchURL(strings::Substitute("http://$0/dir/", ToString(addr_)), |
239 | 1 | &buf_); |
240 | 1 | ASSERT_EQ("Remote error: HTTP 403", s.ToString(/* no file/line */ false)); |
241 | 1 | } |
242 | | |
243 | | } // namespace yb |