Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
Kea
Commits
715d18f9
Commit
715d18f9
authored
Jan 07, 2017
by
Marcin Siodelski
Browse files
[master] Merge branch 'trac5088'
parents
76451257
3bcb33f2
Changes
23
Hide whitespace changes
Inline
Side-by-side
configure.ac
View file @
715d18f9
...
...
@@ -128,6 +128,14 @@ for retry in "none" "--std=c++11" "--std=c++0x" "--std=c++1x" "fail"; do
AC_MSG_WARN([unsupported C++11 feature])
AC_MSG_NOTICE([retrying by adding $retry to $CXX])
CXX="$CXX_SAVED $retry"
AC_MSG_CHECKING($retry support)
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[],
[int myincr = 1;])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
continue])
fi
AC_MSG_CHECKING(std::unique_ptr support)
...
...
@@ -140,6 +148,35 @@ for retry in "none" "--std=c++11" "--std=c++0x" "--std=c++1x" "fail"; do
[AC_MSG_RESULT([no])
continue])
AC_MSG_CHECKING(cbegin/cend support)
feature="cbegin/cend"
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[#include <string>],
[const std::string& s = "abcd";
unsigned count = 0;
for (std::string::const_iterator i = s.cbegin();
i != s.cend(); ++i)
if (*i == 'b')
++count;])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
continue])
AC_MSG_CHECKING(final method support)
feature="final method"
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[],
[class Foo {
public:
virtual ~Foo() {};
virtual void bar() final;
}])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
continue])
AC_MSG_CHECKING(aggregate initialization support)
feature="aggregate initialization"
AC_COMPILE_IFELSE(
...
...
@@ -155,7 +192,7 @@ for retry in "none" "--std=c++11" "--std=c++0x" "--std=c++1x" "fail"; do
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[],
[auto incr = [[]](int x) { return x + 1; };])],
[auto
my
incr = [[]](int x) { return x + 1; };])],
[AC_MSG_RESULT([yes])
break],
[AC_MSG_RESULT([no])
...
...
@@ -1280,7 +1317,7 @@ if test "x$enable_gtest" = "xyes" ; then
[AC_MSG_ERROR([no gtest source at $GTEST_SOURCE])])
fi
have_gtest_source=yes
GTEST_LD
FLAGS
="\$(top_builddir)/ext/gtest/libgtest.a"
GTEST_LD
ADD
="\$(top_builddir)/ext/gtest/libgtest.a"
DISTCHECK_GTEST_CONFIGURE_FLAG="--with-gtest-source=$GTEST_SOURCE"
GTEST_INCLUDES="-I$GTEST_SOURCE -I$GTEST_SOURCE/include"
fi
...
...
src/lib/http/Makefile.am
View file @
715d18f9
...
...
@@ -22,13 +22,18 @@ EXTRA_DIST = http_messages.mes
CLEANFILES
=
*
.gcno
*
.gcda http_messages.h http_messages.cc s-messages
lib_LTLIBRARIES
=
libkea-http.la
libkea_http_la_SOURCES
=
http_log.cc http_log.h
libkea_http_la_SOURCES
=
date_time.cc date_time.h
libkea_http_la_SOURCES
+=
http_log.cc http_log.h
libkea_http_la_SOURCES
+=
header_context.h
libkea_http_la_SOURCES
+=
http_types.h
libkea_http_la_SOURCES
+=
post_request.cc post_request.h
libkea_http_la_SOURCES
+=
post_request_json.cc post_request_json.h
libkea_http_la_SOURCES
+=
request.cc request.h
libkea_http_la_SOURCES
+=
request_context.h
libkea_http_la_SOURCES
+=
request_parser.cc request_parser.h
libkea_http_la_SOURCES
+=
response.cc response.h
libkea_http_la_SOURCES
+=
response_creator.cc response_creator.h
libkea_http_la_SOURCES
+=
response_json.cc response_json.h
nodist_libkea_http_la_SOURCES
=
http_messages.cc http_messages.h
...
...
src/lib/http/date_time.cc
0 → 100644
View file @
715d18f9
// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include
<http/date_time.h>
#include
<boost/date_time/time_facet.hpp>
#include
<boost/date_time/local_time/local_time.hpp>
#include
<locale>
#include
<sstream>
using
namespace
boost
::
local_time
;
using
namespace
boost
::
posix_time
;
namespace
isc
{
namespace
http
{
HttpDateTime
::
HttpDateTime
()
:
time_
(
boost
::
posix_time
::
microsec_clock
::
universal_time
())
{
}
HttpDateTime
::
HttpDateTime
(
const
boost
::
posix_time
::
ptime
&
t
)
:
time_
(
t
)
{
}
std
::
string
HttpDateTime
::
rfc1123Format
()
const
{
return
(
toString
(
"%a, %d %b %Y %H:%M:%S GMT"
,
"RFC 1123"
));
}
std
::
string
HttpDateTime
::
rfc850Format
()
const
{
return
(
toString
(
"%A, %d-%b-%y %H:%M:%S GMT"
,
"RFC 850"
));
}
std
::
string
HttpDateTime
::
asctimeFormat
()
const
{
return
(
toString
(
"%a %b %e %H:%M:%S %Y"
,
"asctime"
));
}
HttpDateTime
HttpDateTime
::
fromRfc1123
(
const
std
::
string
&
time_string
)
{
return
(
HttpDateTime
(
fromString
(
time_string
,
"%a, %d %b %Y %H:%M:%S %ZP"
,
"RFC 1123"
)));
}
HttpDateTime
HttpDateTime
::
fromRfc850
(
const
std
::
string
&
time_string
)
{
return
(
HttpDateTime
(
fromString
(
time_string
,
"%A, %d-%b-%y %H:%M:%S %ZP"
,
"RFC 850"
)));
}
HttpDateTime
HttpDateTime
::
fromAsctime
(
const
std
::
string
&
time_string
)
{
// The asctime() puts space instead of leading 0 in days of
// month. The %e # formatter of time_input_facet doesn't deal
// with this. To deal with this, we make a copy of the string
// holding formatted time and replace a space preceding day
// number with 0. Thanks to this workaround we can use the
// %d formatter which seems to work fine. This has a side
// effect of accepting timestamps such as Sun Nov 06 08:49:37 1994,
// but it should be ok to be liberal in this case.
std
::
string
time_string_copy
(
time_string
);
boost
::
replace_all
(
time_string_copy
,
" "
,
" 0"
);
return
(
HttpDateTime
(
fromString
(
time_string_copy
,
"%a %b %d %H:%M:%S %Y"
,
"asctime"
,
false
)));
}
HttpDateTime
HttpDateTime
::
fromAny
(
const
std
::
string
&
time_string
)
{
HttpDateTime
date_time
;
// Try to parse as a timestamp specified in RFC 1123 format.
try
{
date_time
=
fromRfc1123
(
time_string
);
return
(
date_time
);
}
catch
(...)
{
// Ignore errors, simply try different format.
}
// Try to parse as a timestamp specified in RFC 850 format.
try
{
date_time
=
fromRfc850
(
time_string
);
return
(
date_time
);
}
catch
(...)
{
// Ignore errors, simply try different format.
}
// Try to parse as a timestamp output by asctime() function.
try
{
date_time
=
fromAsctime
(
time_string
);
}
catch
(...)
{
isc_throw
(
HttpTimeConversionError
,
"unsupported time format of the '"
<<
time_string
<<
"'"
);
}
return
(
date_time
);
}
std
::
string
HttpDateTime
::
toString
(
const
std
::
string
&
format
,
const
std
::
string
&
method_name
)
const
{
std
::
ostringstream
s
;
// Create raw pointer. The output stream will take responsibility for
// deleting the object.
time_facet
*
df
(
new
time_facet
(
format
.
c_str
()));
s
.
imbue
(
std
::
locale
(
std
::
locale
::
classic
(),
df
));
// Convert time value to a string.
s
<<
time_
;
if
(
s
.
fail
())
{
isc_throw
(
HttpTimeConversionError
,
"unable to convert "
<<
"time value of '"
<<
time_
<<
"'"
<<
" to "
<<
method_name
<<
" format"
);
}
return
(
s
.
str
());
}
ptime
HttpDateTime
::
fromString
(
const
std
::
string
&
time_string
,
const
std
::
string
&
format
,
const
std
::
string
&
method_name
,
const
bool
zone_check
)
{
std
::
istringstream
s
(
time_string
);
// Create raw pointer. The input stream will take responsibility for
// deleting the object.
time_input_facet
*
tif
(
new
time_input_facet
(
format
));
s
.
imbue
(
std
::
locale
(
std
::
locale
::
classic
(),
tif
));
time_zone_ptr
zone
(
new
posix_time_zone
(
"GMT"
));
local_date_time
ldt
=
local_microsec_clock
::
local_time
(
zone
);
// Parse the time value. The stream will not automatically detect whether
// the zone is GMT. We need to check it on our own.
s
>>
ldt
;
if
(
s
.
fail
()
||
(
zone_check
&&
(
!
ldt
.
zone
()
||
ldt
.
zone
()
->
std_zone_abbrev
()
!=
"GMT"
)))
{
isc_throw
(
HttpTimeConversionError
,
"unable to parse "
<<
method_name
<<
" time value of '"
<<
time_string
<<
"'"
);
}
return
(
ldt
.
local_time
());
}
}
// namespace http
}
// namespace isc
src/lib/http/date_time.h
0 → 100644
View file @
715d18f9
// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef HTTP_DATE_TIME_H
#define HTTP_DATE_TIME_H
#include
<exceptions/exceptions.h>
#include
<boost/date_time/posix_time/posix_time.hpp>
#include
<string>
namespace
isc
{
namespace
http
{
/// @brief Exception thrown when there is an error during time conversion.
///
/// The most common reason for this exception is that the unsupported time
/// format was used as an input to the time parsing functions.
class
HttpTimeConversionError
:
public
Exception
{
public:
HttpTimeConversionError
(
const
char
*
file
,
size_t
line
,
const
char
*
what
)
:
isc
::
Exception
(
file
,
line
,
what
)
{
};
};
/// @brief This class parses and generates time values used in HTTP.
///
/// The HTTP protocol have historically allowed 3 different date/time formats
/// (see https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html). These are:
/// - Sun, 06 Nov 1994 08:49:37 GMT
/// - Sunday, 06-Nov-94 08:49:37 GMT
/// - Sun Nov 6 08:49:37 1994
///
/// The first format is preferred but implementations must also support
/// remaining two obsolete formats for compatibility. This class implements
/// parsers and generators for all three formats. It uses @c boost::posix_time
/// to represent time and date. It uses @c boost::date_time::time_facet
/// and @c boost::date_time::time_input_facet to generate and parse the
/// timestamps.
class
HttpDateTime
{
public:
/// @brief Default constructor.
///
/// Sets current universal time as time value.
HttpDateTime
();
/// @brief Construct from @c boost::posix_time::ptime object.
///
/// @param t time value to be set.
explicit
HttpDateTime
(
const
boost
::
posix_time
::
ptime
&
t
);
/// @brief Returns time encapsulated by this class.
///
/// @return @c boost::posix_time::ptime value encapsulated by the instance
/// of this class.
boost
::
posix_time
::
ptime
getPtime
()
const
{
return
(
time_
);
}
/// @brief Returns time value formatted as specified in RFC 1123.
///
/// @return A string containing time value formatted as
/// Sun, 06 Nov 1994 08:49:37 GMT.
std
::
string
rfc1123Format
()
const
;
/// @brief Returns time value formatted as specified in RFC 850.
///
/// @return A string containing time value formatted as
/// Sunday, 06-Nov-94 08:49:37 GMT.
std
::
string
rfc850Format
()
const
;
/// @brief Returns time value formatted as output of ANSI C's
/// asctime().
///
/// @return A string containing time value formatted as
/// Sun Nov 6 08:49:37 1994.
std
::
string
asctimeFormat
()
const
;
/// @brief Creates an instance from a string containing time value
/// formatted as specified in RFC 1123.
///
/// @param time_string Input string holding formatted time value.
/// @return Instance of @ref HttpDateTime.
/// @throw HttpTimeConversionError if provided timestamp has invalid
/// format.
static
HttpDateTime
fromRfc1123
(
const
std
::
string
&
time_string
);
/// @brief Creates an instance from a string containing time value
/// formatted as specified in RFC 850.
///
/// @param time_string Input string holding formatted time value.
/// @return Instance of @ref HttpDateTime.
/// @throw HttpTimeConversionError if provided timestamp has invalid
/// format.
static
HttpDateTime
fromRfc850
(
const
std
::
string
&
time_string
);
/// @brief Creates an instance from a string containing time value
/// formatted as output from asctime() function.
///
/// @param time_string Input string holding formatted time value.
/// @return Instance of @ref HttpDateTime.
/// @throw HttpTimeConversionError if provided timestamp has invalid
/// format.
static
HttpDateTime
fromAsctime
(
const
std
::
string
&
time_string
);
/// @brief Creates an instance from a string containing time value
/// formatted in one of the supported formats.
///
/// This method will detect the format of the time value and parse it.
/// It tries parsing the value in the following order:
/// - a format specified in RFC 1123,
/// - a format specified in RFC 850,
/// - a format of asctime output.
///
/// @param time_string Input string holding formatted time value.
/// @return Instance of @ref HttpDateTime.
/// @throw HttpTimeConversionError if provided value doesn't match any
/// of the supported formats.
static
HttpDateTime
fromAny
(
const
std
::
string
&
time_string
);
private:
/// @brief Generic method formatting a time value to a specified format.
////
/// @param format Time format as accepted by the
/// @c boost::date_time::time_facet.
std
::
string
toString
(
const
std
::
string
&
format
,
const
std
::
string
&
method_name
)
const
;
/// @brief Generic method parsing time value and converting it to the
/// instance of @c boost::posix_time::ptime.
///
/// @param time_string Input string holding formatted time value.
/// @param format Time format as accepted by the
/// @c boost::date_time::time_input_facet.
/// @param method_name Name of the expected format to appear in the error
/// message if parsing fails, e.g. RFC 1123, RFC 850 or asctime.
/// @param zone_check Indicates if the time zone name should be validated
/// during parsing. This should be set to false for the formats which
/// lack time zones (e.g. asctime).
///
/// @return Instance of the @ref boost::posix_time::ptime created from the
/// input string.
/// @throw HttpTimeConversionError if provided value doesn't match the
/// specified format.
static
boost
::
posix_time
::
ptime
fromString
(
const
std
::
string
&
time_string
,
const
std
::
string
&
format
,
const
std
::
string
&
method_name
,
const
bool
zone_check
=
true
);
/// @brief Time value encapsulated by this class instance.
boost
::
posix_time
::
ptime
time_
;
};
}
// namespace http
}
// namespace isc
#endif
src/lib/http/http_types.h
0 → 100644
View file @
715d18f9
// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef HTTP_TYPES_H
#define HTTP_TYPES_H
/// @brief HTTP protocol version.
struct
HttpVersion
{
unsigned
major_
;
///< Major HTTP version.
unsigned
minor_
;
///< Minor HTTP version.
/// @brief Constructor.
///
/// @param major Major HTTP version.
/// @param minor Minor HTTP version.
explicit
HttpVersion
(
const
unsigned
major
,
const
unsigned
minor
)
:
major_
(
major
),
minor_
(
minor
)
{
}
/// @brief Operator less.
///
/// @param rhs Version to compare to.
bool
operator
<
(
const
HttpVersion
&
rhs
)
const
{
return
((
major_
<
rhs
.
major_
)
||
((
major_
==
rhs
.
major_
)
&&
(
minor_
<
rhs
.
minor_
)));
}
/// @brief Operator equal.
///
/// @param rhs Version to compare to.
bool
operator
==
(
const
HttpVersion
&
rhs
)
const
{
return
((
major_
==
rhs
.
major_
)
&&
(
minor_
==
rhs
.
minor_
));
}
/// @brief Operator not equal.
///
/// @param rhs Version to compare to.
bool
operator
!=
(
const
HttpVersion
&
rhs
)
const
{
return
(
!
operator
==
(
rhs
));
}
};
#endif
src/lib/http/request.cc
View file @
715d18f9
// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016
-2017
Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
...
...
@@ -66,8 +66,8 @@ HttpRequest::create() {
}
// Check if the HTTP version is allowed for this request.
if
(
!
inRequiredSet
(
std
::
make_pair
(
context_
->
http_version_major_
,
context_
->
http_version_minor_
),
if
(
!
inRequiredSet
(
HttpVersion
(
context_
->
http_version_major_
,
context_
->
http_version_minor_
),
required_versions_
))
{
isc_throw
(
BadValue
,
"use of HTTP version "
<<
context_
->
http_version_major_
<<
"."
...
...
@@ -144,11 +144,11 @@ HttpRequest::getUri() const {
return
(
context_
->
uri_
);
}
HttpRequest
::
HttpVersion
HttpVersion
HttpRequest
::
getHttpVersion
()
const
{
checkCreated
();
return
(
std
::
make_pair
(
context_
->
http_version_major_
,
context_
->
http_version_minor_
));
return
(
HttpVersion
(
context_
->
http_version_major_
,
context_
->
http_version_minor_
));
}
std
::
string
...
...
src/lib/http/request.h
View file @
715d18f9
// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016
-2017
Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
...
...
@@ -8,7 +8,9 @@
#define HTTP_REQUEST_H
#include
<exceptions/exceptions.h>
#include
<http/http_types.h>
#include
<http/request_context.h>
#include
<boost/shared_ptr.hpp>
#include
<map>
#include
<set>
#include
<stdint.h>
...
...
@@ -34,6 +36,14 @@ public:
HttpRequestError
(
file
,
line
,
what
)
{
};
};
class
HttpRequest
;
/// @brief Pointer to the @ref HttpRequest object.
typedef
boost
::
shared_ptr
<
HttpRequest
>
HttpRequestPtr
;
/// @brief Pointer to the const @ref HttpRequest object.
typedef
boost
::
shared_ptr
<
const
HttpRequest
>
ConstHttpRequestPtr
;
/// @brief Represents HTTP request message.
///
/// This object represents parsed HTTP message. The @ref HttpRequestContext
...
...
@@ -51,9 +61,6 @@ public:
class
HttpRequest
{
public:
/// @brief Type of HTTP version, including major and minor version number.
typedef
std
::
pair
<
unsigned
int
,
unsigned
int
>
HttpVersion
;
/// @brief HTTP methods.
enum
class
Method
{
HTTP_GET
,
...
...
@@ -190,6 +197,16 @@ public:
/// @brief Returns HTTP message body as string.
std
::
string
getBody
()
const
;
/// @brief Checks if the request has been successfully finalized.
///
/// The request is gets finalized on successfull call to
/// @ref HttpRequest::finalize.
///
/// @return true if the request has been finalized, false otherwise.
bool
isFinalized
()
const
{
return
(
finalized_
);
}
//@}
protected:
...
...
src/lib/http/response.cc
0 → 100644
View file @
715d18f9
// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include
<http/date_time.h>
#include
<http/response.h>
#include
<boost/date_time/local_time/local_time.hpp>
#include
<boost/date_time/time_facet.hpp>
#include
<sstream>
using
namespace
boost
::
local_time
;
using
namespace
isc
::
http
;
namespace
{
/// @brief A map of status codes to status names.
const
std
::
map
<
HttpStatusCode
,
std
::
string
>
status_code_to_description
=
{
{
HttpStatusCode
::
OK
,
"OK"
},
{
HttpStatusCode
::
CREATED
,
"Created"
},
{
HttpStatusCode
::
ACCEPTED
,
"Accepted"
},
{
HttpStatusCode
::
NO_CONTENT
,
"No Content"
},
{
HttpStatusCode
::
MULTIPLE_CHOICES
,
"Multiple Choices"
},
{
HttpStatusCode
::
MOVED_PERMANENTLY
,
"Moved Permanently"
},
{
HttpStatusCode
::
MOVED_TEMPORARILY
,
"Moved Temporarily"
},
{
HttpStatusCode
::
NOT_MODIFIED
,
"Not Modified"
},
{
HttpStatusCode
::
BAD_REQUEST
,
"Bad Request"
},
{
HttpStatusCode
::
UNAUTHORIZED
,
"Unauthorized"
},
{
HttpStatusCode
::
FORBIDDEN
,
"Forbidden"
},
{
HttpStatusCode
::
NOT_FOUND
,
"Not Found"
},
{
HttpStatusCode
::
INTERNAL_SERVER_ERROR
,
"Internal Server Error"
},
{
HttpStatusCode
::
NOT_IMPLEMENTED
,
"Not Implemented"
},
{
HttpStatusCode
::
BAD_GATEWAY
,
"Bad Gateway"
},
{
HttpStatusCode
::
SERVICE_UNAVAILABLE
,
"Service Unavailable"
}
};
/// @brief New line (CRLF).
const
std
::
string
crlf
=
"
\r\n
"
;
}
namespace
isc
{
namespace
http
{
HttpResponse
::
HttpResponse
(
const
HttpVersion
&
version
,
const
HttpStatusCode
&
status_code
,
const
CallSetGenericBody
&
generic_body
)
:
http_version_
(
version
),
status_code_
(
status_code
),
headers_
(),
body_
()
{
if
(
generic_body
.
set_
)
{
// This currently does nothing, but it is useful to have it here as
// an example how to implement it in the derived classes.
setGenericBody
(
status_code
);
}
}
void
HttpResponse
::
setBody
(
const
std
::
string
&
body
)
{
body_
=
body
;
}
bool
HttpResponse
::
isClientError
(
const
HttpStatusCode
&
status_code
)
{
// Client errors have status codes of 4XX.
uint16_t
c
=
statusCodeToNumber
(
status_code
);
return
((
c
>=
400
)
&&
(
c
<
500
));
}
bool
HttpResponse
::
isServerError
(
const
HttpStatusCode
&
status_code
)
{
// Server errors have status codes of 5XX.
uint16_t
c
=
statusCodeToNumber
(
status_code
);
return
((
c
>=
500
)
&&
(
c
<
600
));
}
std
::
string
HttpResponse
::
statusCodeToString
(
const
HttpStatusCode
&
status_code
)
{
auto
status_code_it
=
status_code_to_description
.
find
(
status_code
);
if
(
status_code_it
==
status_code_to_description
.
end
())
{
isc_throw
(
HttpResponseError
,
"internal server error: no HTTP status"
" description for the given status code "
<<
static_cast
<
uint16_t
>
(
status_code
));
}
return
(
status_code_it
->
second
);
}
<