Kea 3.2.0-git
cmd_response_creator.cc
Go to the documentation of this file.
1// Copyright (C) 2021-2026 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <config/command_mgr.h>
11#include <config/config_log.h>
14#include <http/response_json.h>
15#include <boost/pointer_cast.hpp>
16#include <iostream>
17
18using namespace isc::config;
19using namespace isc::data;
20using namespace isc::http;
21using namespace std;
22
23namespace isc {
24namespace config {
25
27
29
31
36
40 const HttpStatusCode& status_code) const {
41 HttpResponsePtr response = createStockHttpResponseInternal(request, status_code);
42 response->finalize();
43 return (response);
44}
45
47CmdResponseCreator::
48createStockHttpResponseInternal(const HttpRequestPtr& request,
49 const HttpStatusCode& status_code) const {
50 // The request hasn't been finalized so the request object
51 // doesn't contain any information about the HTTP version number
52 // used. But, the context should have this data (assuming the
53 // HTTP version is parsed OK).
54 HttpVersion http_version(request->context()->http_version_major_,
55 request->context()->http_version_minor_);
56 // We only accept HTTP version 1.0 or 1.1. If other version number is found
57 // we fall back to HTTP/1.0.
58 if ((http_version < HttpVersion(1, 0)) || (HttpVersion(1, 1) < http_version)) {
59 http_version.major_ = 1;
60 http_version.minor_ = 0;
61 }
62 // This will generate the response holding JSON content.
63 HttpResponsePtr response(new HttpResponseJson(http_version, status_code));
64 return (response);
65}
66
68CmdResponseCreator::createDynamicHttpResponse(HttpRequestPtr request) {
69 HttpResponseJsonPtr http_response;
70
71 // Check the basic HTTP authentication.
73 http_response = http_auth_config_->checkAuth(*this, request);
74 if (http_response) {
75 return (http_response);
76 }
77 }
78
79 // The request is always non-null, because this is verified by the
80 // createHttpResponse method. Let's try to convert it to the
81 // PostHttpRequestJson type as this is the type generated by the
82 // createNewHttpRequest. If the conversion result is null it means that
83 // the caller did not use createNewHttpRequest method to create this
84 // instance. This is considered an error in the server logic.
85 PostHttpRequestJsonPtr request_json = boost::dynamic_pointer_cast<
86 PostHttpRequestJson>(request);
87 if (!request_json) {
88 // Notify the client that we have a problem with our server.
89 return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
90 }
91
92 // We have already checked that the request is finalized so the call
93 // to getBodyAsJson must not trigger an exception.
94 ConstElementPtr command = request_json->getBodyAsJson();
95
96 // Filter the command.
97 http_response = filterCommand(request, command, command_accept_list_);
98 if (http_response) {
99 return (http_response);
100 }
101
102 // Process command doesn't generate exceptions but can possibly return
103 // null response, if the handler is not implemented properly. This is
104 // again an internal server issue.
106
107 if (!response) {
108 // Notify the client that we have a problem with our server.
109 return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
110 }
111
112 // Normal Responses coming from the Kea control socket must always be wrapped in
113 // a list as backword compatibility with the deprecated (removed) Control-Agent
114 // which contain responses from multiple daemons.
115 // If we're emulating that for backward compatibility, then we need to wrap
116 // the answer in a list if it isn't in one already.
117 if (EMULATE_AGENT_RESPONSE && (response->getType() != Element::list)) {
118 ElementPtr response_list = Element::createList();
119 response_list->add(boost::const_pointer_cast<Element>(response));
120 response = response_list;
121 }
122
123 // The response is OK, so let's create new HTTP response with the status OK.
124 http_response = boost::dynamic_pointer_cast<
125 HttpResponseJson>(createStockHttpResponseInternal(request, HttpStatusCode::OK));
126 http_response->setBodyAsJson(response);
127 http_response->finalize();
128
129 return (http_response);
130}
131
134 const ConstElementPtr& body,
135 const unordered_set<string>& accept) {
136 HttpResponseJsonPtr response;
137 if (!body || accept.empty()) {
138 return (response);
139 }
140 if (body->getType() != Element::map) {
141 return (response);
142 }
143 ConstElementPtr elem = body->get(CONTROL_COMMAND);
144 if (!elem || (elem->getType() != Element::string)) {
145 return (response);
146 }
147 string command = elem->stringValue();
148 if (command.empty() || accept.count(command)) {
149 return (response);
150 }
151
152 // Reject the command.
155 .arg(command)
156 .arg(request->getRemote());
157 // From CmdResponseCreator::createStockHttpResponseInternal.
158 HttpVersion http_version(request->context()->http_version_major_,
159 request->context()->http_version_minor_);
160 if ((http_version < HttpVersion(1, 0)) ||
161 (HttpVersion(1, 1) < http_version)) {
162 http_version.major_ = 1;
163 http_version.minor_ = 0;
164 }
166 response.reset(new HttpResponseJson(http_version, status_code));
167 ElementPtr response_body = Element::createMap();
168 uint16_t result = HttpResponse::statusCodeToNumber(status_code);
169 response_body->set(CONTROL_RESULT,
170 Element::create(static_cast<long long>(result)));
171 const string& text = HttpResponse::statusCodeToString(status_code);
172 response_body->set(CONTROL_TEXT, Element::create(text));
173 response->setBodyAsJson(response_body);
174 response->finalize();
175 return (response);
176}
177
178} // end of namespace isc::config
179} // end of namespace isc
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:299
@ map
Definition data.h:160
@ list
Definition data.h:159
@ string
Definition data.h:157
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:354
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:349
virtual isc::data::ConstElementPtr processCommand(const isc::data::ConstElementPtr &cmd)
Triggers command processing.
http::HttpResponseJsonPtr filterCommand(const http::HttpRequestPtr &request, const data::ConstElementPtr &body, const std::unordered_set< std::string > &accept)
Filter commands.
static http::HttpAuthConfigPtr http_auth_config_
The server current authentication configuration.
virtual http::HttpResponsePtr createStockHttpResponse(const http::HttpRequestPtr &request, const http::HttpStatusCode &status_code) const
Creates stock HTTP response.
static bool EMULATE_AGENT_RESPONSE
The emulate agent response flag.
virtual http::HttpRequestPtr createNewHttpRequest() const
Create a new request.
static std::unordered_set< std::string > command_accept_list_
The server command accept list.
static CommandMgr & instance()
CommandMgr is a singleton class.
Represents HTTP response with JSON content.
static uint16_t statusCodeToNumber(const HttpStatusCode &status_code)
Convenience method converting status code to numeric value.
Definition response.cc:184
static std::string statusCodeToString(const HttpStatusCode &status_code)
Converts status code to string.
Definition response.cc:173
Represents HTTP POST request with JSON body.
This file contains several functions and constants that are used for handling commands and responses ...
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
const char * CONTROL_TEXT
String used for storing textual description ("text").
const char * CONTROL_COMMAND
String used for commands ("command").
const isc::log::MessageID COMMAND_HTTP_LISTENER_COMMAND_REJECTED
const char * CONTROL_RESULT
String used for result, i.e. integer status ("result").
const int DBG_COMMAND
Definition config_log.h:24
isc::log::Logger command_logger("commands")
Command processing Logger.
Definition config_log.h:21
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
HttpStatusCode
HTTP status codes (cf RFC 2068).
Definition response.h:30
boost::shared_ptr< PostHttpRequestJson > PostHttpRequestJsonPtr
Pointer to PostHttpRequestJson.
boost::shared_ptr< HttpAuthConfig > HttpAuthConfigPtr
Type of shared pointers to HTTP authentication configuration.
Definition auth_config.h:97
boost::shared_ptr< HttpResponseJson > HttpResponseJsonPtr
Pointer to the HttpResponseJson object.
boost::shared_ptr< HttpResponse > HttpResponsePtr
Pointer to the HttpResponse object.
Definition response.h:81
boost::shared_ptr< HttpRequest > HttpRequestPtr
Pointer to the HttpRequest object.
Definition request.h:30
Defines the logger used by the top-level component of kea-lfc.
HTTP protocol version.
Definition http_types.h:14
unsigned minor_
Minor HTTP version.
Definition http_types.h:16
unsigned major_
Major HTTP version.
Definition http_types.h:15