Kea 2.7.3
http_command_response_creator.cc
Go to the documentation of this file.
1// Copyright (C) 2021-2024 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>
13#include <hooks/hooks_log.h>
14#include <hooks/hooks_manager.h>
16#include <http/response_json.h>
17#include <boost/pointer_cast.hpp>
18#include <iostream>
19
20using namespace isc::config;
21using namespace isc::data;
22using namespace isc::hooks;
23using namespace isc::http;
24using namespace std;
25
26namespace {
27
29struct HttpCommandHooks {
30 int hook_index_http_auth_;
31 int hook_index_http_response_;
32
34 HttpCommandHooks() {
35 hook_index_http_auth_ = HooksManager::registerHook("http_auth");
36 hook_index_http_response_ = HooksManager::registerHook("http_response");
37 }
38};
39
40} // end of anonymous namespace.
41
42// Declare a Hooks object. As this is outside any function or method, it
43// will be instantiated (and the constructor run) when the module is loaded.
44// As a result, the hook indexes will be defined before any method in this
45// module is called.
46HttpCommandHooks Hooks;
47
48namespace isc {
49namespace config {
50
55
59 const HttpStatusCode& status_code) const {
60 HttpResponsePtr response = createStockHttpResponseInternal(request, status_code);
61 response->finalize();
62 return (response);
63}
64
66HttpCommandResponseCreator::
67createStockHttpResponseInternal(const HttpRequestPtr& request,
68 const HttpStatusCode& status_code) const {
69 // The request hasn't been finalized so the request object
70 // doesn't contain any information about the HTTP version number
71 // used. But, the context should have this data (assuming the
72 // HTTP version is parsed OK).
73 HttpVersion http_version(request->context()->http_version_major_,
74 request->context()->http_version_minor_);
75 // We only accept HTTP version 1.0 or 1.1. If other version number is found
76 // we fall back to HTTP/1.0.
77 if ((http_version < HttpVersion(1, 0)) || (HttpVersion(1, 1) < http_version)) {
78 http_version.major_ = 1;
79 http_version.minor_ = 0;
80 }
81 // This will generate the response holding JSON content.
82 HttpResponsePtr response(new HttpResponseJson(http_version, status_code));
83 return (response);
84}
85
87HttpCommandResponseCreator::createDynamicHttpResponse(HttpRequestPtr request) {
88 HttpResponseJsonPtr http_response;
89
90 // Check the basic HTTP authentication.
91 if (config_) {
92 const HttpAuthConfigPtr& auth = config_->getAuthConfig();
93 if (auth) {
94 http_response = auth->checkAuth(*this, request);
95 }
96 }
97
98 // Callout point for "http_auth".
99 bool reset_handle = false;
100 if (HooksManager::calloutsPresent(Hooks.hook_index_http_auth_)) {
101 // Get callout handle.
102 CalloutHandlePtr callout_handle = request->getCalloutHandle();
103 ScopedCalloutHandleState callout_handle_state(callout_handle);
104
105 // Pass arguments.
106 callout_handle->setArgument("request", request);
107 callout_handle->setArgument("response", http_response);
108
109 // Call callouts.
110 HooksManager::callCallouts(Hooks.hook_index_http_auth_,
111 *callout_handle);
112 callout_handle->getArgument("request", request);
113 callout_handle->getArgument("response", http_response);
114
115 // Status other than continue means 'please reset the handle'.
116 if (callout_handle->getStatus() != CalloutHandle::NEXT_STEP_CONTINUE) {
117 reset_handle = true;
118 }
119 }
120
121 // The basic HTTP authentication check or a callout failed and
122 // left a response.
123 if (http_response) {
124 return (http_response);
125 }
126
127 // Reset the handle when a hook asks for.
128 if (reset_handle) {
129 request->resetCalloutHandle();
130 }
131
132 // The request is always non-null, because this is verified by the
133 // createHttpResponse method. Let's try to convert it to the
134 // PostHttpRequestJson type as this is the type generated by the
135 // createNewHttpRequest. If the conversion result is null it means that
136 // the caller did not use createNewHttpRequest method to create this
137 // instance. This is considered an error in the server logic.
138 PostHttpRequestJsonPtr request_json =
139 boost::dynamic_pointer_cast<PostHttpRequestJson>(request);
140 if (!request_json) {
141 // Notify the client that we have a problem with our server.
142 return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
143 }
144
145 // We have already checked that the request is finalized so the call
146 // to getBodyAsJson must not trigger an exception.
147 ConstElementPtr command = request_json->getBodyAsJson();
148
149 // Process command doesn't generate exceptions but can possibly return
150 // null response, if the handler is not implemented properly. This is
151 // again an internal server issue.
152 ConstElementPtr response = config::CommandMgr::instance().processCommand(command);
153
154 if (!response) {
155 // Notify the client that we have a problem with our server.
156 return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
157 }
158
159 // Normal Responses coming from the Kea server must always be wrapped in
160 // a list as they may contain responses from multiple daemons.
161 // If we're emulating that for backward compatibility, then we need to wrap
162 // the answer in a list if it isn't in one already.
163 if ((!config_ || config_->getEmulateAgentResponse()) &&
164 (response->getType() != Element::list)) {
165 ElementPtr response_list = Element::createList();
166 response_list->add(boost::const_pointer_cast<Element>(response));
167 response = response_list;
168 }
169
170 // The response is OK, so let's create new HTTP response with the status OK.
171 http_response = boost::dynamic_pointer_cast<
172 HttpResponseJson>(createStockHttpResponseInternal(request, HttpStatusCode::OK));
173 http_response->setBodyAsJson(response);
174 http_response->finalize();
175
176 // Callout point for "http_response".
177 if (HooksManager::calloutsPresent(Hooks.hook_index_http_response_)) {
178 // Get callout handle.
179 CalloutHandlePtr callout_handle = request->getCalloutHandle();
180 ScopedCalloutHandleState callout_handle_state(callout_handle);
181
182 // Pass arguments.
183 callout_handle->setArgument("request", request);
184 callout_handle->setArgument("response", http_response);
185
186 // Call callouts.
187 HooksManager::callCallouts(Hooks.hook_index_http_response_,
188 *callout_handle);
189 callout_handle->getArgument("response", http_response);
190
191 // Ignore status as the HTTP response is used instead.
192 }
193
194 return (http_response);
195}
196
197} // end of namespace isc::config
198} // end of namespace isc
CtrlAgentHooks Hooks
static CommandMgr & instance()
CommandMgr is a singleton class.
virtual http::HttpRequestPtr createNewHttpRequest() const
Create a new request.
virtual http::HttpResponsePtr createStockHttpResponse(const http::HttpRequestPtr &request, const http::HttpStatusCode &status_code) const
Creates stock HTTP response.
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
@ NEXT_STEP_CONTINUE
continue normally
static int registerHook(const std::string &name)
Register Hook.
static bool calloutsPresent(int index)
Are callouts present?
static void callCallouts(int index, CalloutHandle &handle)
Calls the callouts for a given hook.
Wrapper class around callout handle which automatically resets handle's state.
Represents HTTP response with JSON content.
void setBodyAsJson(const data::ConstElementPtr &json_body)
Generates JSON content from the data structures represented as data::ConstElementPtr.
Represents HTTP POST request with JSON body.
HttpCommandHooks Hooks
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
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