Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/root/operations/admin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ modify different aspects of the server:
In the future additional security options will be added to the administration interface. This
work is tracked in `this <https://github.com/envoyproxy/envoy/issues/2763>`_ issue.

All mutations should be sent as HTTP POST operations. For a limited time, they will continue
to work with HTTP GET, with a warning logged.
All mutations must be sent as HTTP POST operations. When a mutation is requested via GET,
the request has no effect, and an HTTP 400 (Invalid Request) response is returned.

.. http:get:: /

Expand Down Expand Up @@ -354,4 +354,4 @@ The fields are:
set to '0'.
* Latency information is currently unavailable.



7 changes: 5 additions & 2 deletions source/server/http/admin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -953,16 +953,19 @@ Http::Code AdminImpl::runCallback(absl::string_view path_and_query,

for (const UrlHandler& handler : handlers_) {
if (path_and_query.compare(0, query_index, handler.prefix_) == 0) {
found_handler = true;
if (handler.mutates_server_state_) {
const absl::string_view method =
admin_stream.getRequestHeaders().Method()->value().getStringView();
if (method != Http::Headers::get().MethodValues.Post) {
ENVOY_LOG(warn, "admin path \"{}\" mutates state, method={} rather than POST",
ENVOY_LOG(error, "admin path \"{}\" mutates state, method={} rather than POST",
handler.prefix_, method);
code = Http::Code::BadRequest;
response.add("Invalid request; POST required");
break;
}
}
code = handler.handler_(path_and_query, response_headers, response, admin_stream);
found_handler = true;
break;
}
}
Expand Down
32 changes: 16 additions & 16 deletions test/integration/integration_admin_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ TEST_P(IntegrationAdminTest, HealthCheck) {
initialize();

BufferingStreamDecoderPtr response = IntegrationUtil::makeSingleRequest(
lookupPort("http"), "GET", "/healthcheck", "", downstreamProtocol(), version_);
lookupPort("http"), "POST", "/healthcheck", "", downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("200", response->headers().Status()->value().c_str());

response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET", "/healthcheck/fail", "",
downstreamProtocol(), version_);
response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "POST", "/healthcheck/fail",
"", downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("200", response->headers().Status()->value().c_str());

Expand All @@ -35,7 +35,7 @@ TEST_P(IntegrationAdminTest, HealthCheck) {
EXPECT_TRUE(response->complete());
EXPECT_STREQ("503", response->headers().Status()->value().c_str());

response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET", "/healthcheck/ok", "",
response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "POST", "/healthcheck/ok", "",
downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("200", response->headers().Status()->value().c_str());
Expand All @@ -60,39 +60,39 @@ TEST_P(IntegrationAdminTest, AdminLogging) {
initialize();

BufferingStreamDecoderPtr response = IntegrationUtil::makeSingleRequest(
lookupPort("admin"), "GET", "/logging", "", downstreamProtocol(), version_);
lookupPort("admin"), "POST", "/logging", "", downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("404", response->headers().Status()->value().c_str());

// Bad level
response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET", "/logging?level=blah",
response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "POST", "/logging?level=blah",
"", downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("404", response->headers().Status()->value().c_str());

// Bad logger
response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET", "/logging?blah=info",
response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "POST", "/logging?blah=info",
"", downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("404", response->headers().Status()->value().c_str());

// This is going to stomp over custom log levels that are set on the command line.
response = IntegrationUtil::makeSingleRequest(
lookupPort("admin"), "GET", "/logging?level=warning", "", downstreamProtocol(), version_);
lookupPort("admin"), "POST", "/logging?level=warning", "", downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("200", response->headers().Status()->value().c_str());
for (const Logger::Logger& logger : Logger::Registry::loggers()) {
EXPECT_EQ("warning", logger.levelString());
}

response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET", "/logging?assert=trace",
"", downstreamProtocol(), version_);
response = IntegrationUtil::makeSingleRequest(
lookupPort("admin"), "POST", "/logging?assert=trace", "", downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("200", response->headers().Status()->value().c_str());
EXPECT_EQ(spdlog::level::trace, Logger::Registry::getLog(Logger::Id::assert).level());

const char* level_name = spdlog::level::level_names[default_log_level_];
response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET",
response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "POST",
fmt::format("/logging?level={}", level_name), "",
downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
Expand Down Expand Up @@ -224,7 +224,7 @@ TEST_P(IntegrationAdminTest, Admin) {
EXPECT_THAT(response->body(), testing::HasSubstr("added_via_api"));
EXPECT_STREQ("text/plain; charset=UTF-8", ContentType(response));

response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET", "/cpuprofiler", "",
response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "POST", "/cpuprofiler", "",
downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("400", response->headers().Status()->value().c_str());
Expand All @@ -236,7 +236,7 @@ TEST_P(IntegrationAdminTest, Admin) {
EXPECT_STREQ("200", response->headers().Status()->value().c_str());
EXPECT_STREQ("text/plain; charset=UTF-8", ContentType(response));

response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET", "/reset_counters", "",
response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "POST", "/reset_counters", "",
downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("200", response->headers().Status()->value().c_str());
Expand Down Expand Up @@ -341,12 +341,12 @@ TEST_P(IntegrationAdminTest, AdminCpuProfilerStart) {

initialize();
BufferingStreamDecoderPtr response = IntegrationUtil::makeSingleRequest(
lookupPort("admin"), "GET", "/cpuprofiler?enable=y", "", downstreamProtocol(), version_);
lookupPort("admin"), "POST", "/cpuprofiler?enable=y", "", downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("200", response->headers().Status()->value().c_str());

response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET", "/cpuprofiler?enable=n",
"", downstreamProtocol(), version_);
response = IntegrationUtil::makeSingleRequest(
lookupPort("admin"), "POST", "/cpuprofiler?enable=n", "", downstreamProtocol(), version_);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("200", response->headers().Status()->value().c_str());
}
Expand Down
2 changes: 1 addition & 1 deletion test/integration/server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ IntegrationTestServer::~IntegrationTestServer() {
ENVOY_LOG(info, "stopping integration test server");

BufferingStreamDecoderPtr response =
IntegrationUtil::makeSingleRequest(server_->admin().socket().localAddress(), "GET",
IntegrationUtil::makeSingleRequest(server_->admin().socket().localAddress(), "POST",
"/quitquitquit", "", Http::CodecClient::Type::HTTP1);
EXPECT_TRUE(response->complete());
EXPECT_STREQ("200", response->headers().Status()->value().c_str());
Expand Down
10 changes: 5 additions & 5 deletions test/server/http/admin_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -417,15 +417,15 @@ TEST_P(AdminInstanceTest, AdminProfiler) {

#endif

TEST_P(AdminInstanceTest, MutatesWarnWithGet) {
TEST_P(AdminInstanceTest, MutatesErrorWithGet) {
Buffer::OwnedImpl data;
Http::HeaderMapImpl header_map;
const std::string path("/healthcheck/fail");
// TODO(jmarantz): the call to getCallback should be made to fail, but as an interim we will
// just issue a warning, so that scripts using curl GET comamnds to mutate state can be fixed.
EXPECT_LOG_CONTAINS("warning",
EXPECT_LOG_CONTAINS("error",
"admin path \"" + path + "\" mutates state, method=GET rather than POST",
EXPECT_EQ(Http::Code::OK, getCallback(path, header_map, data)));
EXPECT_EQ(Http::Code::BadRequest, getCallback(path, header_map, data)));
}

TEST_P(AdminInstanceTest, AdminBadProfiler) {
Expand Down Expand Up @@ -638,15 +638,15 @@ TEST_P(AdminInstanceTest, RuntimeModify) {
overrides["nothing"] = "";
EXPECT_CALL(loader, mergeValues(overrides)).Times(1);
EXPECT_EQ(Http::Code::OK,
getCallback("/runtime_modify?foo=bar&x=42&nothing=", header_map, response));
postCallback("/runtime_modify?foo=bar&x=42&nothing=", header_map, response));
EXPECT_EQ("OK\n", response.toString());
}

TEST_P(AdminInstanceTest, RuntimeModifyNoArguments) {
Http::HeaderMapImpl header_map;
Buffer::OwnedImpl response;

EXPECT_EQ(Http::Code::BadRequest, getCallback("/runtime_modify", header_map, response));
EXPECT_EQ(Http::Code::BadRequest, postCallback("/runtime_modify", header_map, response));
EXPECT_TRUE(absl::StartsWith(response.toString(), "usage:"));
}

Expand Down