1
#include "source/server/admin/admin_filter.h"
2

            
3
#include "source/server/admin/utils.h"
4

            
5
namespace Envoy {
6
namespace Server {
7

            
8
567
AdminFilter::AdminFilter(const Admin& admin) : admin_(admin) {}
9

            
10
Http::FilterHeadersStatus AdminFilter::decodeHeaders(Http::RequestHeaderMap& headers,
11
591
                                                     bool end_stream) {
12
591
  request_headers_ = &headers;
13
591
  if (end_stream) {
14
422
    onComplete();
15
422
  }
16

            
17
591
  return Http::FilterHeadersStatus::StopIteration;
18
591
}
19

            
20
20
Http::FilterDataStatus AdminFilter::decodeData(Buffer::Instance& data, bool end_stream) {
21
  // Currently we generically buffer all admin request data in case a handler wants to use it.
22
  // If we ever support streaming admin requests we may need to revisit this. Note, we must use
23
  // addDecodedData() here since we might need to perform onComplete() processing if end_stream is
24
  // true.
25
20
  decoder_callbacks_->addDecodedData(data, false);
26

            
27
20
  if (end_stream) {
28
19
    onComplete();
29
19
  }
30

            
31
20
  return Http::FilterDataStatus::StopIterationNoBuffer;
32
20
}
33

            
34
1
Http::FilterTrailersStatus AdminFilter::decodeTrailers(Http::RequestTrailerMap&) {
35
1
  onComplete();
36
1
  return Http::FilterTrailersStatus::StopIteration;
37
1
}
38

            
39
439
void AdminFilter::onDestroy() {
40
439
  for (const auto& callback : on_destroy_callbacks_) {
41
24
    callback();
42
24
  }
43
439
}
44

            
45
24
void AdminFilter::addOnDestroyCallback(std::function<void()> cb) {
46
24
  on_destroy_callbacks_.push_back(std::move(cb));
47
24
}
48

            
49
38
Http::StreamDecoderFilterCallbacks& AdminFilter::getDecoderFilterCallbacks() const {
50
38
  ASSERT(decoder_callbacks_ != nullptr);
51
38
  return *decoder_callbacks_;
52
38
}
53

            
54
40
const Buffer::Instance* AdminFilter::getRequestBody() const {
55
40
  return decoder_callbacks_->decodingBuffer();
56
40
}
57

            
58
876
const Http::RequestHeaderMap& AdminFilter::getRequestHeaders() const {
59
876
  ASSERT(request_headers_ != nullptr);
60
876
  return *request_headers_;
61
876
}
62

            
63
378
Http::Utility::QueryParamsMulti AdminFilter::queryParams() const {
64
378
  absl::string_view path = request_headers_->getPathValue();
65
378
  Http::Utility::QueryParamsMulti query =
66
378
      Http::Utility::QueryParamsMulti::parseAndDecodeQueryString(path);
67
378
  if (!query.data().empty()) {
68
278
    return query;
69
278
  }
70

            
71
  // Check if the params are in the request's body.
72
100
  if (request_headers_->getContentTypeValue() ==
73
100
      Http::Headers::get().ContentTypeValues.FormUrlEncoded) {
74
1
    const Buffer::Instance* body = getRequestBody();
75
1
    if (body != nullptr) {
76
1
      query = Http::Utility::QueryParamsMulti::parseParameters(body->toString(), 0, true);
77
1
    }
78
1
  }
79

            
80
100
  return query;
81
378
}
82

            
83
442
void AdminFilter::onComplete() {
84
442
  absl::string_view path = request_headers_->getPathValue();
85
442
  ENVOY_STREAM_LOG(debug, "request complete: path: {}", *decoder_callbacks_, path);
86

            
87
442
  auto header_map = Http::ResponseHeaderMapImpl::create();
88
442
  RELEASE_ASSERT(request_headers_, "");
89
442
  Admin::RequestPtr handler = admin_.makeRequest(*this);
90
442
  Http::Code code = handler->start(*header_map);
91
442
  Utility::populateFallbackResponseHeaders(code, *header_map);
92
442
  decoder_callbacks_->encodeHeaders(std::move(header_map), false,
93
442
                                    StreamInfo::ResponseCodeDetails::get().AdminFilterResponse);
94

            
95
  // TODO(#31087): use high/lower watermarks to apply flow-control to the admin http port.
96
442
  bool more_data;
97
442
  do {
98
442
    Buffer::OwnedImpl response;
99
442
    more_data = handler->nextChunk(response);
100
442
    bool end_stream = end_stream_on_complete_ && !more_data;
101
442
    ENVOY_LOG_MISC(debug, "nextChunk: response.length={} more_data={} end_stream={}",
102
442
                   response.length(), more_data, end_stream);
103
442
    if (response.length() > 0 || end_stream) {
104
421
      decoder_callbacks_->encodeData(response, end_stream);
105
421
    }
106
442
  } while (more_data);
107
442
}
108

            
109
} // namespace Server
110
} // namespace Envoy