Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for JSON-C library #10178

Closed
wants to merge 12 commits into from

Conversation

ondrejholy
Copy link
Contributor

The AAD authentication and SDL prefs currently relies on the cJSON library. This is not available in RHEL for example. Let's add an option to build with the JSON-C library instead.

Related: #10009

This is in preparation for the subsequent commit adding test case for
the prefs functionality to avoid building the code twice.
The CJSON_FOUND macro can be set despite the fact that should be used
by the prefs functionality. Let's use the WITH_CJSON macro instead to
avoid this situation. This is in preparation for the subsequent commit
adding JSON-C support for the prefs functionality.
Let's add test case for SDL prefs functionality. This is in preparation
for the subsequent commit adding JSON-C support to ensure it doesn't
break something.
Let's use the cJSON_GetObjectItemCaseSensitive function instead of the
cJSON_GetObjectItem function. This is in preparation for the subsequent
commit adding JSON-C support to achieve consistent behavior. JSON-C doesn't
support case-insensitive comparison. Although this is backwards incompatible
change, it is not documented anywhere that it should be case-insensitive.
The SDL prefs functionality currently relies on the cJSON library.
This is not available in RHEL for example. Let's add an option to
build with the JSON-C library instead.

Related: FreeRDP#10009
Let's use the cJSON_GetObjectItemCaseSensitive function instead of the
cJSON_GetObjectItem function. This is in preparation for the subsequent
commit adding JSON-C support to achieve consistent behavior. JSON-C doesn't
support case-insensitive comparison. The protocol is case sensitive anyway.
Let's use the cJSON_GetStringValue function instead of dereference. This is in
preparation for the subsequent commit adding JSON-C support to simplify things.
Currently, the `arm_handle_bad_request` function returns `FALSE` when the
`cJSON_ParseWithLength` function fails to parse the message, but only when
the `cJSON_GetErrorPtr` returns a valid pointer. It would be better to
return regardless of the `cJSON_GetErrorPtr` return value.
The AAD functionality currently relies on the cJSON library. This is
not available in RHEL for example. Let's add an option to build with
the JSON-C library instead.

Related: FreeRDP#10009
@ondrejholy
Copy link
Contributor Author

The implementation is pretty straightforward. It includes a test case for SDL prefs, however, the AAD authentication hasn't been tested. @fifthdegree , it seems that you are the author of the AAD support. Is there any chance, that you can test this, please?

@freerdp-bot
Copy link

Refer to this link for build results (access rights to CI server needed):
https://ci.freerdp.com//job/PullRequestTester/11943/

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions


static std::string item_to_str(cJSON *item, const std::string& fallback = "")
{
if (!item || !cJSON_IsString(item))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion 'cJSON *' -> bool [readability-implicit-bool-conversion]

Suggested change
if (!item || !cJSON_IsString(item))
if ((item == nullptr) || !cJSON_IsString(item))

if (!item || !cJSON_IsString(item))
return fallback;
auto str = cJSON_GetStringValue(item);
if (!str)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion 'char *' -> bool [readability-implicit-bool-conversion]

Suggested change
if (!str)
if (str == nullptr)

{
#if defined(WITH_CJSON) || defined(WITH_JSONC)
auto item = get_item(key);
if (!item || !cJSON_IsBool(item))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion 'cJSON *' -> bool [readability-implicit-bool-conversion]

Suggested change
if (!item || !cJSON_IsBool(item))
if ((item == nullptr) || !cJSON_IsBool(item))

auto item = get_item(key);
if (!item || !cJSON_IsBool(item))
return fallback;
return cJSON_IsTrue(item);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion 'cJSON_bool' (aka 'int') -> bool [readability-implicit-bool-conversion]

Suggested change
return cJSON_IsTrue(item);
return cJSON_IsTrue(item) != 0;

{
#if defined(WITH_CJSON) || defined(WITH_JSONC)
auto item = get_item(key);
if (!item || !cJSON_IsNumber(item))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion 'cJSON *' -> bool [readability-implicit-bool-conversion]

Suggested change
if (!item || !cJSON_IsNumber(item))
if ((item == nullptr) || !cJSON_IsNumber(item))

#endif

auto bool_value_nonexistent = sdl_get_pref_bool("bool_key_nonexistent", false);
WINPR_ASSERT(!bool_value_nonexistent);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]

	WINPR_ASSERT(!bool_value_nonexistent);
 ^
Additional context

winpr/include/winpr/assert.h:38: expanded from macro 'WINPR_ASSERT'

			winpr_int_assert(#cond, __FILE__, __func__, __LINE__); \
                                     ^


auto array_value = sdl_get_pref_array("array_key", { "c", "b", "a" });
#if defined(WITH_CJSON) || defined(WITH_JSONC)
WINPR_ASSERT(array_value.size() == 3 && array_value[0] == "a" && array_value[1] == "b" &&

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: avoid do-while loops [cppcoreguidelines-avoid-do-while]

	WINPR_ASSERT(array_value.size() == 3 && array_value[0] == "a" && array_value[1] == "b" &&
 ^
Additional context

winpr/include/winpr/assert.h:35: expanded from macro 'WINPR_ASSERT'

	do                                                             \
 ^


auto array_value = sdl_get_pref_array("array_key", { "c", "b", "a" });
#if defined(WITH_CJSON) || defined(WITH_JSONC)
WINPR_ASSERT(array_value.size() == 3 && array_value[0] == "a" && array_value[1] == "b" &&

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]

	WINPR_ASSERT(array_value.size() == 3 && array_value[0] == "a" && array_value[1] == "b" &&
 ^
Additional context

winpr/include/winpr/assert.h:38: expanded from macro 'WINPR_ASSERT'

			winpr_int_assert(#cond, __FILE__, __func__, __LINE__); \
                                     ^

#endif

auto array_value_nonexistent = sdl_get_pref_array("array_key_nonexistent", { "c", "b", "a" });
WINPR_ASSERT(array_value_nonexistent.size() == 3 && array_value_nonexistent[0] == "c" &&

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: avoid do-while loops [cppcoreguidelines-avoid-do-while]

	WINPR_ASSERT(array_value_nonexistent.size() == 3 && array_value_nonexistent[0] == "c" &&
 ^
Additional context

winpr/include/winpr/assert.h:35: expanded from macro 'WINPR_ASSERT'

	do                                                             \
 ^

#endif

auto array_value_nonexistent = sdl_get_pref_array("array_key_nonexistent", { "c", "b", "a" });
WINPR_ASSERT(array_value_nonexistent.size() == 3 && array_value_nonexistent[0] == "c" &&

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]

	WINPR_ASSERT(array_value_nonexistent.size() == 3 && array_value_nonexistent[0] == "c" &&
 ^
Additional context

winpr/include/winpr/assert.h:38: expanded from macro 'WINPR_ASSERT'

			winpr_int_assert(#cond, __FILE__, __func__, __LINE__); \
                                     ^

@fifthdegree
Copy link
Contributor

Sorry, I no longer have the proper setup (or spare time :) to test this.

@akallabeth akallabeth added this to the next-3.0 milestone May 11, 2024
@akallabeth
Copy link
Member

@ondrejholy thanks for the pull!
feel free to ignore clang-tidy suggestions (they are sometimes useful, but not always as you can see)

# JSONC_INCLUDE_DIRS - JSON-C include directories
# JSONC_LIBRARIES - libraries needed for linking

find_package(PkgConfig REQUIRED)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will abort configuration on a system without pkg-config

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the dependencies already require pkg-config, but it is true that they are not built by default, or only on Linux. So I will change that to not require it. Also the pkg_check_modules result was not used by mistake, so I will add the missing HINTS...

# CJSON_INCLUDE_DIRS - cJSON include directories
# CJSON_LIBRARIES - libraries needed for linking

find_package(PkgConfig REQUIRED)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will abort detection on a system without pkg-config

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change it here as well. I will also replace CJSON_LIBRARIES with cJSON_LIBRARIES as I have just found out that there is a bug on the master branch. The code currently relies on pkg-config results that use CJSON prefix and ignores results from find_library. The same applies for find_path.


#elif defined(WITH_JSONC)

#include <json-c/json.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure this is an API we´d like to ship as our own like this in public headers.
might be better to use some thin wrapper and use our own naming scheme here to have that abstracted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other option would be to just move this to internals like before with cJSON so that we do not expose this ourselves. (you need to redo the used symbols for SDL client, but well...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I expected that you wouldn't like this approach. I am just preparing a wrapper to avoid the code duplication...

NAMES cjson
REQUIRED
)
if (WITH_JSONC)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should still search for the library (with REQUIRED keyword).
the detection before is used to determine the default value of the WITH_AAD option, but here we enforce the requirements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the message(FATAL_ERROR "AAD support requested but cJSON not found") enough?

@akallabeth akallabeth mentioned this pull request May 14, 2024
@akallabeth akallabeth closed this May 14, 2024
@akallabeth akallabeth removed this from the next-3.0 milestone May 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants