Everywhere: Make JSON serialization fallible
This allows us to eliminate a major source of infallible allocation in the Kernel, as well as lay down the groundwork for OOM fallibility in userland.
This commit is contained in:
parent
6682afb5d4
commit
feb00b7105
Notes:
sideshowbarker
2024-07-17 18:09:57 +09:00
Author: https://github.com/IdanHo Commit: https://github.com/SerenityOS/serenity/commit/feb00b7105 Pull-request: https://github.com/SerenityOS/serenity/pull/12754 Reviewed-by: https://github.com/bgianfo ✅ Reviewed-by: https://github.com/elcuco
18 changed files with 837 additions and 592 deletions
|
@ -85,8 +85,9 @@ private:
|
|||
template<typename Builder>
|
||||
inline void JsonArray::serialize(Builder& builder) const
|
||||
{
|
||||
JsonArraySerializer serializer { builder };
|
||||
for_each([&](auto& value) { serializer.add(value); });
|
||||
auto serializer = MUST(JsonArraySerializer<>::try_create(builder));
|
||||
for_each([&](auto& value) { MUST(serializer.add(value)); });
|
||||
MUST(serializer.finish());
|
||||
}
|
||||
|
||||
template<typename Builder>
|
||||
|
|
|
@ -1,132 +1,216 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
|
||||
* Copyright (c) 2022, Idan Horowitz <idan.horowitz@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/JsonValue.h>
|
||||
#include <AK/Error.h>
|
||||
#include <AK/Try.h>
|
||||
|
||||
#ifndef KERNEL
|
||||
# include <AK/JsonValue.h>
|
||||
#endif
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename Builder>
|
||||
inline constexpr bool IsLegacyBuilder = requires(Builder builder) { builder.try_append('\0'); };
|
||||
|
||||
template<typename Builder = void>
|
||||
class JsonObjectSerializer;
|
||||
|
||||
template<typename Builder>
|
||||
template<typename Builder = void>
|
||||
class JsonArraySerializer {
|
||||
public:
|
||||
explicit JsonArraySerializer(Builder& builder)
|
||||
: m_builder(builder)
|
||||
static ErrorOr<JsonArraySerializer> try_create(Builder& builder)
|
||||
{
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(builder.try_append('['));
|
||||
else
|
||||
TRY(builder.append('['));
|
||||
return JsonArraySerializer { builder };
|
||||
}
|
||||
|
||||
JsonArraySerializer(JsonArraySerializer&& other)
|
||||
: m_builder(other.m_builder)
|
||||
, m_empty(other.m_empty)
|
||||
, m_finished(exchange(other.m_finished, true))
|
||||
{
|
||||
(void)m_builder.append('[');
|
||||
}
|
||||
|
||||
JsonArraySerializer(const JsonArraySerializer&) = delete;
|
||||
JsonArraySerializer(JsonArraySerializer&&) = delete;
|
||||
|
||||
~JsonArraySerializer()
|
||||
{
|
||||
if (!m_finished)
|
||||
finish();
|
||||
VERIFY(m_finished);
|
||||
}
|
||||
|
||||
#ifndef KERNEL
|
||||
void add(const JsonValue& value)
|
||||
ErrorOr<void> add(const JsonValue& value)
|
||||
{
|
||||
begin_item();
|
||||
TRY(begin_item());
|
||||
value.serialize(m_builder);
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
void add(StringView value)
|
||||
ErrorOr<void> add(StringView value)
|
||||
{
|
||||
begin_item();
|
||||
(void)m_builder.append('"');
|
||||
(void)m_builder.append_escaped_for_json(value);
|
||||
(void)m_builder.append('"');
|
||||
TRY(begin_item());
|
||||
if constexpr (IsLegacyBuilder<Builder>) {
|
||||
TRY(m_builder.try_append('"'));
|
||||
TRY(m_builder.try_append_escaped_for_json(value));
|
||||
TRY(m_builder.try_append('"'));
|
||||
} else {
|
||||
TRY(m_builder.append('"'));
|
||||
TRY(m_builder.append_escaped_for_json(value));
|
||||
TRY(m_builder.append('"'));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void add(const String& value)
|
||||
#ifndef KERNEL
|
||||
ErrorOr<void> add(const String& value)
|
||||
{
|
||||
begin_item();
|
||||
(void)m_builder.append('"');
|
||||
(void)m_builder.append_escaped_for_json(value);
|
||||
(void)m_builder.append('"');
|
||||
TRY(begin_item());
|
||||
if constexpr (IsLegacyBuilder<Builder>) {
|
||||
TRY(m_builder.try_append('"'));
|
||||
TRY(m_builder.try_append_escaped_for_json(value));
|
||||
TRY(m_builder.try_append('"'));
|
||||
} else {
|
||||
TRY(m_builder.append('"'));
|
||||
TRY(m_builder.append_escaped_for_json(value));
|
||||
TRY(m_builder.append('"'));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
ErrorOr<void> add(const char* value)
|
||||
{
|
||||
TRY(begin_item());
|
||||
if constexpr (IsLegacyBuilder<Builder>) {
|
||||
TRY(m_builder.try_append('"'));
|
||||
TRY(m_builder.try_append_escaped_for_json(value));
|
||||
TRY(m_builder.try_append('"'));
|
||||
} else {
|
||||
TRY(m_builder.append('"'));
|
||||
TRY(m_builder.append_escaped_for_json(value));
|
||||
TRY(m_builder.append('"'));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void add(const char* value)
|
||||
ErrorOr<void> add(bool value)
|
||||
{
|
||||
begin_item();
|
||||
(void)m_builder.append('"');
|
||||
(void)m_builder.append_escaped_for_json(value);
|
||||
(void)m_builder.append('"');
|
||||
TRY(begin_item());
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_append(value ? "true"sv : "false"sv));
|
||||
else
|
||||
TRY(m_builder.append(value ? "true"sv : "false"sv));
|
||||
return {};
|
||||
}
|
||||
|
||||
void add(bool value)
|
||||
ErrorOr<void> add(int value)
|
||||
{
|
||||
begin_item();
|
||||
(void)m_builder.append(value ? "true"sv : "false"sv);
|
||||
TRY(begin_item());
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
void add(int value)
|
||||
ErrorOr<void> add(unsigned value)
|
||||
{
|
||||
begin_item();
|
||||
(void)m_builder.appendff("{}", value);
|
||||
TRY(begin_item());
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
void add(unsigned value)
|
||||
ErrorOr<void> add(long value)
|
||||
{
|
||||
begin_item();
|
||||
(void)m_builder.appendff("{}", value);
|
||||
TRY(begin_item());
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
void add(long value)
|
||||
ErrorOr<void> add(long unsigned value)
|
||||
{
|
||||
begin_item();
|
||||
(void)m_builder.appendff("{}", value);
|
||||
TRY(begin_item());
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
void add(long unsigned value)
|
||||
ErrorOr<void> add(long long value)
|
||||
{
|
||||
begin_item();
|
||||
(void)m_builder.appendff("{}", value);
|
||||
TRY(begin_item());
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
void add(long long value)
|
||||
ErrorOr<void> add(long long unsigned value)
|
||||
{
|
||||
begin_item();
|
||||
(void)m_builder.appendff("{}", value);
|
||||
TRY(begin_item());
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
void add(long long unsigned value)
|
||||
ErrorOr<JsonArraySerializer<Builder>> add_array()
|
||||
{
|
||||
begin_item();
|
||||
(void)m_builder.appendff("{}", value);
|
||||
}
|
||||
|
||||
JsonArraySerializer<Builder> add_array()
|
||||
{
|
||||
begin_item();
|
||||
return JsonArraySerializer(m_builder);
|
||||
TRY(begin_item());
|
||||
return JsonArraySerializer::try_create(m_builder);
|
||||
}
|
||||
|
||||
// Implemented in JsonObjectSerializer.h
|
||||
JsonObjectSerializer<Builder> add_object();
|
||||
ErrorOr<JsonObjectSerializer<Builder>> add_object();
|
||||
|
||||
void finish()
|
||||
ErrorOr<void> finish()
|
||||
{
|
||||
VERIFY(!m_finished);
|
||||
m_finished = true;
|
||||
(void)m_builder.append(']');
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_append(']'));
|
||||
else
|
||||
TRY(m_builder.append(']'));
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
void begin_item()
|
||||
explicit JsonArraySerializer(Builder& builder)
|
||||
: m_builder(builder)
|
||||
{
|
||||
if (!m_empty)
|
||||
(void)m_builder.append(',');
|
||||
}
|
||||
|
||||
ErrorOr<void> begin_item()
|
||||
{
|
||||
VERIFY(!m_finished);
|
||||
if (!m_empty) {
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_append(','));
|
||||
else
|
||||
TRY(m_builder.append(','));
|
||||
}
|
||||
m_empty = false;
|
||||
return {};
|
||||
}
|
||||
|
||||
Builder& m_builder;
|
||||
|
@ -134,6 +218,16 @@ private:
|
|||
bool m_finished { false };
|
||||
};
|
||||
|
||||
// Template magic to allow for JsonArraySerializer<>::try_create(...) - Blame CxByte
|
||||
template<>
|
||||
struct JsonArraySerializer<void> {
|
||||
template<typename Builder>
|
||||
static ErrorOr<JsonArraySerializer<Builder>> try_create(Builder& builder)
|
||||
{
|
||||
return JsonArraySerializer<Builder>::try_create(builder);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::JsonArraySerializer;
|
||||
|
|
|
@ -162,10 +162,11 @@ private:
|
|||
template<typename Builder>
|
||||
inline void JsonObject::serialize(Builder& builder) const
|
||||
{
|
||||
JsonObjectSerializer serializer { builder };
|
||||
auto serializer = MUST(JsonObjectSerializer<>::try_create(builder));
|
||||
for_each_member([&](auto& key, auto& value) {
|
||||
serializer.add(key, value);
|
||||
MUST(serializer.add(key, value));
|
||||
});
|
||||
MUST(serializer.finish());
|
||||
}
|
||||
|
||||
template<typename Builder>
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
|
||||
* Copyright (c) 2022, Idan Horowitz <idan.horowitz@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Error.h>
|
||||
#include <AK/JsonArraySerializer.h>
|
||||
#include <AK/Try.h>
|
||||
|
||||
#ifndef KERNEL
|
||||
# include <AK/JsonValue.h>
|
||||
|
@ -17,132 +20,217 @@ namespace AK {
|
|||
template<typename Builder>
|
||||
class JsonObjectSerializer {
|
||||
public:
|
||||
explicit JsonObjectSerializer(Builder& builder)
|
||||
: m_builder(builder)
|
||||
static ErrorOr<JsonObjectSerializer> try_create(Builder& builder)
|
||||
{
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(builder.try_append('{'));
|
||||
else
|
||||
TRY(builder.append('{'));
|
||||
return JsonObjectSerializer { builder };
|
||||
}
|
||||
|
||||
JsonObjectSerializer(JsonObjectSerializer&& other)
|
||||
: m_builder(other.m_builder)
|
||||
, m_empty(other.m_empty)
|
||||
, m_finished(exchange(other.m_finished, true))
|
||||
{
|
||||
(void)m_builder.append('{');
|
||||
}
|
||||
|
||||
JsonObjectSerializer(const JsonObjectSerializer&) = delete;
|
||||
JsonObjectSerializer(JsonObjectSerializer&&) = delete;
|
||||
|
||||
~JsonObjectSerializer()
|
||||
{
|
||||
if (!m_finished)
|
||||
finish();
|
||||
VERIFY(m_finished);
|
||||
}
|
||||
|
||||
#ifndef KERNEL
|
||||
void add(StringView key, const JsonValue& value)
|
||||
ErrorOr<void> add(StringView key, const JsonValue& value)
|
||||
{
|
||||
begin_item(key);
|
||||
TRY(begin_item(key));
|
||||
value.serialize(m_builder);
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
void add(StringView key, StringView value)
|
||||
ErrorOr<void> add(StringView key, StringView value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.append('"');
|
||||
(void)m_builder.append_escaped_for_json(value);
|
||||
(void)m_builder.append('"');
|
||||
}
|
||||
|
||||
void add(StringView key, const String& value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.append('"');
|
||||
(void)m_builder.append_escaped_for_json(value);
|
||||
(void)m_builder.append('"');
|
||||
}
|
||||
|
||||
void add(StringView key, const char* value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.append('"');
|
||||
(void)m_builder.append_escaped_for_json(value);
|
||||
(void)m_builder.append('"');
|
||||
}
|
||||
|
||||
void add(StringView key, bool value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.append(value ? "true" : "false");
|
||||
}
|
||||
|
||||
void add(StringView key, int value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.appendff("{}", value);
|
||||
}
|
||||
|
||||
void add(StringView key, unsigned value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.appendff("{}", value);
|
||||
}
|
||||
|
||||
void add(StringView key, long value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.appendff("{}", value);
|
||||
}
|
||||
|
||||
void add(StringView key, long unsigned value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.appendff("{}", value);
|
||||
}
|
||||
|
||||
void add(StringView key, long long value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.appendff("{}", value);
|
||||
}
|
||||
|
||||
void add(StringView key, long long unsigned value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.appendff("{}", value);
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>) {
|
||||
TRY(m_builder.try_append('"'));
|
||||
TRY(m_builder.try_append_escaped_for_json(value));
|
||||
TRY(m_builder.try_append('"'));
|
||||
} else {
|
||||
TRY(m_builder.append('"'));
|
||||
TRY(m_builder.append_escaped_for_json(value));
|
||||
TRY(m_builder.append('"'));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifndef KERNEL
|
||||
void add(StringView key, double value)
|
||||
ErrorOr<void> add(StringView key, const String& value)
|
||||
{
|
||||
begin_item(key);
|
||||
(void)m_builder.appendff("{}", value);
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>) {
|
||||
TRY(m_builder.try_append('"'));
|
||||
TRY(m_builder.try_append_escaped_for_json(value));
|
||||
TRY(m_builder.try_append('"'));
|
||||
} else {
|
||||
TRY(m_builder.append('"'));
|
||||
TRY(m_builder.append_escaped_for_json(value));
|
||||
TRY(m_builder.append('"'));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
JsonArraySerializer<Builder> add_array(StringView key)
|
||||
ErrorOr<void> add(StringView key, const char* value)
|
||||
{
|
||||
begin_item(key);
|
||||
return JsonArraySerializer(m_builder);
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>) {
|
||||
TRY(m_builder.try_append('"'));
|
||||
TRY(m_builder.try_append_escaped_for_json(value));
|
||||
TRY(m_builder.try_append('"'));
|
||||
} else {
|
||||
TRY(m_builder.append('"'));
|
||||
TRY(m_builder.append_escaped_for_json(value));
|
||||
TRY(m_builder.append('"'));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
JsonObjectSerializer<Builder> add_object(StringView key)
|
||||
ErrorOr<void> add(StringView key, bool value)
|
||||
{
|
||||
begin_item(key);
|
||||
return JsonObjectSerializer(m_builder);
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_append(value ? "true" : "false"));
|
||||
else
|
||||
TRY(m_builder.append(value ? "true" : "false"));
|
||||
return {};
|
||||
}
|
||||
|
||||
void finish()
|
||||
ErrorOr<void> add(StringView key, int value)
|
||||
{
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> add(StringView key, unsigned value)
|
||||
{
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> add(StringView key, long value)
|
||||
{
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> add(StringView key, long unsigned value)
|
||||
{
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> add(StringView key, long long value)
|
||||
{
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> add(StringView key, long long unsigned value)
|
||||
{
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifndef KERNEL
|
||||
ErrorOr<void> add(StringView key, double value)
|
||||
{
|
||||
TRY(begin_item(key));
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_appendff("{}", value));
|
||||
else
|
||||
TRY(m_builder.appendff("{}", value));
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
ErrorOr<JsonArraySerializer<Builder>> add_array(StringView key)
|
||||
{
|
||||
TRY(begin_item(key));
|
||||
return JsonArraySerializer<Builder>::try_create(m_builder);
|
||||
}
|
||||
|
||||
ErrorOr<JsonObjectSerializer<Builder>> add_object(StringView key)
|
||||
{
|
||||
TRY(begin_item(key));
|
||||
return JsonObjectSerializer::try_create(m_builder);
|
||||
}
|
||||
|
||||
ErrorOr<void> finish()
|
||||
{
|
||||
VERIFY(!m_finished);
|
||||
m_finished = true;
|
||||
(void)m_builder.append('}');
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_append('}'));
|
||||
else
|
||||
TRY(m_builder.append('}'));
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
void begin_item(StringView key)
|
||||
explicit JsonObjectSerializer(Builder& builder)
|
||||
: m_builder(builder)
|
||||
{
|
||||
if (!m_empty)
|
||||
(void)m_builder.append(',');
|
||||
}
|
||||
|
||||
ErrorOr<void> begin_item(StringView key)
|
||||
{
|
||||
VERIFY(!m_finished);
|
||||
if (!m_empty) {
|
||||
if constexpr (IsLegacyBuilder<Builder>)
|
||||
TRY(m_builder.try_append(','));
|
||||
else
|
||||
TRY(m_builder.append(','));
|
||||
}
|
||||
m_empty = false;
|
||||
|
||||
(void)m_builder.append('"');
|
||||
(void)m_builder.append_escaped_for_json(key);
|
||||
(void)m_builder.append("\":");
|
||||
if constexpr (IsLegacyBuilder<Builder>) {
|
||||
TRY(m_builder.try_append('"'));
|
||||
TRY(m_builder.try_append_escaped_for_json(key));
|
||||
TRY(m_builder.try_append("\":"));
|
||||
} else {
|
||||
TRY(m_builder.append('"'));
|
||||
TRY(m_builder.append_escaped_for_json(key));
|
||||
TRY(m_builder.append("\":"));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Builder& m_builder;
|
||||
|
@ -150,11 +238,21 @@ private:
|
|||
bool m_finished { false };
|
||||
};
|
||||
|
||||
// Template magic to allow for JsonObjectSerializer<>::try_create(...) - Blame CxByte
|
||||
template<>
|
||||
struct JsonObjectSerializer<void> {
|
||||
template<typename Builder>
|
||||
static ErrorOr<JsonObjectSerializer<Builder>> try_create(Builder& builder)
|
||||
{
|
||||
return JsonObjectSerializer<Builder>::try_create(builder);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Builder>
|
||||
JsonObjectSerializer<Builder> JsonArraySerializer<Builder>::add_object()
|
||||
ErrorOr<JsonObjectSerializer<Builder>> JsonArraySerializer<Builder>::add_object()
|
||||
{
|
||||
begin_item();
|
||||
return JsonObjectSerializer(m_builder);
|
||||
TRY(begin_item());
|
||||
return JsonObjectSerializer<Builder>::try_create(m_builder);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,24 +27,24 @@ SysFSUSBDeviceInformation::~SysFSUSBDeviceInformation()
|
|||
ErrorOr<void> SysFSUSBDeviceInformation::try_generate(KBufferBuilder& builder)
|
||||
{
|
||||
VERIFY(m_lock.is_locked());
|
||||
JsonArraySerializer array { builder };
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
|
||||
auto obj = array.add_object();
|
||||
obj.add("device_address", m_device->address());
|
||||
obj.add("usb_spec_compliance_bcd", m_device->device_descriptor().usb_spec_compliance_bcd);
|
||||
obj.add("device_class", m_device->device_descriptor().device_class);
|
||||
obj.add("device_sub_class", m_device->device_descriptor().device_sub_class);
|
||||
obj.add("device_protocol", m_device->device_descriptor().device_protocol);
|
||||
obj.add("max_packet_size", m_device->device_descriptor().max_packet_size);
|
||||
obj.add("vendor_id", m_device->device_descriptor().vendor_id);
|
||||
obj.add("product_id", m_device->device_descriptor().product_id);
|
||||
obj.add("device_release_bcd", m_device->device_descriptor().device_release_bcd);
|
||||
obj.add("manufacturer_id_descriptor_index", m_device->device_descriptor().manufacturer_id_descriptor_index);
|
||||
obj.add("product_string_descriptor_index", m_device->device_descriptor().product_string_descriptor_index);
|
||||
obj.add("serial_number_descriptor_index", m_device->device_descriptor().serial_number_descriptor_index);
|
||||
obj.add("num_configurations", m_device->device_descriptor().num_configurations);
|
||||
obj.finish();
|
||||
array.finish();
|
||||
auto obj = TRY(array.add_object());
|
||||
TRY(obj.add("device_address", m_device->address()));
|
||||
TRY(obj.add("usb_spec_compliance_bcd", m_device->device_descriptor().usb_spec_compliance_bcd));
|
||||
TRY(obj.add("device_class", m_device->device_descriptor().device_class));
|
||||
TRY(obj.add("device_sub_class", m_device->device_descriptor().device_sub_class));
|
||||
TRY(obj.add("device_protocol", m_device->device_descriptor().device_protocol));
|
||||
TRY(obj.add("max_packet_size", m_device->device_descriptor().max_packet_size));
|
||||
TRY(obj.add("vendor_id", m_device->device_descriptor().vendor_id));
|
||||
TRY(obj.add("product_id", m_device->device_descriptor().product_id));
|
||||
TRY(obj.add("device_release_bcd", m_device->device_descriptor().device_release_bcd));
|
||||
TRY(obj.add("manufacturer_id_descriptor_index", m_device->device_descriptor().manufacturer_id_descriptor_index));
|
||||
TRY(obj.add("product_string_descriptor_index", m_device->device_descriptor().product_string_descriptor_index));
|
||||
TRY(obj.add("serial_number_descriptor_index", m_device->device_descriptor().serial_number_descriptor_index));
|
||||
TRY(obj.add("num_configurations", m_device->device_descriptor().num_configurations));
|
||||
TRY(obj.finish());
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -220,22 +220,26 @@ ErrorOr<void> Coredump::create_notes_process_data(auto& builder) const
|
|||
TRY(builder.append_bytes(ReadonlyBytes { (void*)&info, sizeof(info) }));
|
||||
|
||||
{
|
||||
JsonObjectSerializer process_obj { builder };
|
||||
process_obj.add("pid"sv, m_process->pid().value());
|
||||
process_obj.add("termination_signal"sv, m_process->termination_signal());
|
||||
process_obj.add("executable_path"sv, m_process->executable() ? TRY(m_process->executable()->try_serialize_absolute_path())->view() : ""sv);
|
||||
auto process_obj = TRY(JsonObjectSerializer<>::try_create(builder));
|
||||
TRY(process_obj.add("pid"sv, m_process->pid().value()));
|
||||
TRY(process_obj.add("termination_signal"sv, m_process->termination_signal()));
|
||||
TRY(process_obj.add("executable_path"sv, m_process->executable() ? TRY(m_process->executable()->try_serialize_absolute_path())->view() : ""sv));
|
||||
|
||||
{
|
||||
auto arguments_array = process_obj.add_array("arguments"sv);
|
||||
auto arguments_array = TRY(process_obj.add_array("arguments"sv));
|
||||
for (auto const& argument : m_process->arguments())
|
||||
arguments_array.add(argument.view());
|
||||
TRY(arguments_array.add(argument.view()));
|
||||
TRY(arguments_array.finish());
|
||||
}
|
||||
|
||||
{
|
||||
auto environment_array = process_obj.add_array("environment"sv);
|
||||
auto environment_array = TRY(process_obj.add_array("environment"sv));
|
||||
for (auto const& variable : m_process->environment())
|
||||
environment_array.add(variable.view());
|
||||
TRY(environment_array.add(variable.view()));
|
||||
TRY(environment_array.finish());
|
||||
}
|
||||
|
||||
TRY(process_obj.finish());
|
||||
}
|
||||
|
||||
TRY(builder.append('\0'));
|
||||
|
@ -296,10 +300,12 @@ ErrorOr<void> Coredump::create_notes_metadata_data(auto& builder) const
|
|||
TRY(builder.append_bytes(ReadonlyBytes { (void*)&metadata, sizeof(metadata) }));
|
||||
|
||||
{
|
||||
JsonObjectSerializer metadata_obj { builder };
|
||||
m_process->for_each_coredump_property([&](auto& key, auto& value) {
|
||||
metadata_obj.add(key.view(), value.view());
|
||||
});
|
||||
auto metadata_obj = TRY(JsonObjectSerializer<>::try_create(builder));
|
||||
TRY(m_process->for_each_coredump_property([&](auto& key, auto& value) -> ErrorOr<void> {
|
||||
TRY(metadata_obj.add(key.view(), value.view()));
|
||||
return {};
|
||||
}));
|
||||
TRY(metadata_obj.finish());
|
||||
}
|
||||
TRY(builder.append('\0'));
|
||||
return {};
|
||||
|
|
|
@ -725,13 +725,12 @@ ErrorOr<void> VirtualFileSystem::rmdir(StringView path, Custody& base)
|
|||
return parent_inode.remove_child(KLexicalPath::basename(path));
|
||||
}
|
||||
|
||||
void VirtualFileSystem::for_each_mount(Function<IterationDecision(Mount const&)> callback) const
|
||||
ErrorOr<void> VirtualFileSystem::for_each_mount(Function<ErrorOr<void>(Mount const&)> callback) const
|
||||
{
|
||||
m_mounts.with([&](auto& mounts) {
|
||||
for (auto& mount : mounts) {
|
||||
if (callback(mount) == IterationDecision::Break)
|
||||
break;
|
||||
}
|
||||
return m_mounts.with([&](auto& mounts) -> ErrorOr<void> {
|
||||
for (auto& mount : mounts)
|
||||
TRY(callback(mount));
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
ErrorOr<void> mknod(StringView path, mode_t, dev_t, Custody& base);
|
||||
ErrorOr<NonnullRefPtr<Custody>> open_directory(StringView path, Custody& base);
|
||||
|
||||
void for_each_mount(Function<IterationDecision(const Mount&)>) const;
|
||||
ErrorOr<void> for_each_mount(Function<ErrorOr<void>(const Mount&)>) const;
|
||||
|
||||
InodeIdentifier root_inode_id() const;
|
||||
|
||||
|
|
|
@ -40,33 +40,35 @@ private:
|
|||
ProcFSAdapters();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
NetworkingManagement::the().for_each([&array](auto& adapter) {
|
||||
auto obj = array.add_object();
|
||||
obj.add("name", adapter.name());
|
||||
obj.add("class_name", adapter.class_name());
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
TRY(NetworkingManagement::the().try_for_each([&array](auto& adapter) -> ErrorOr<void> {
|
||||
auto obj = TRY(array.add_object());
|
||||
TRY(obj.add("name", adapter.name()));
|
||||
TRY(obj.add("class_name", adapter.class_name()));
|
||||
auto mac_address = adapter.mac_address().to_string().release_value_but_fixme_should_propagate_errors();
|
||||
obj.add("mac_address", mac_address->view());
|
||||
TRY(obj.add("mac_address", mac_address->view()));
|
||||
if (!adapter.ipv4_address().is_zero()) {
|
||||
auto ipv4_address = adapter.ipv4_address().to_string().release_value_but_fixme_should_propagate_errors();
|
||||
obj.add("ipv4_address", ipv4_address->view());
|
||||
TRY(obj.add("ipv4_address", ipv4_address->view()));
|
||||
auto ipv4_netmask = adapter.ipv4_netmask().to_string().release_value_but_fixme_should_propagate_errors();
|
||||
obj.add("ipv4_netmask", ipv4_netmask->view());
|
||||
TRY(obj.add("ipv4_netmask", ipv4_netmask->view()));
|
||||
}
|
||||
if (!adapter.ipv4_gateway().is_zero()) {
|
||||
auto ipv4_gateway = adapter.ipv4_gateway().to_string().release_value_but_fixme_should_propagate_errors();
|
||||
obj.add("ipv4_gateway", ipv4_gateway->view());
|
||||
TRY(obj.add("ipv4_gateway", ipv4_gateway->view()));
|
||||
}
|
||||
obj.add("packets_in", adapter.packets_in());
|
||||
obj.add("bytes_in", adapter.bytes_in());
|
||||
obj.add("packets_out", adapter.packets_out());
|
||||
obj.add("bytes_out", adapter.bytes_out());
|
||||
obj.add("link_up", adapter.link_up());
|
||||
obj.add("link_speed", adapter.link_speed());
|
||||
obj.add("link_full_duplex", adapter.link_full_duplex());
|
||||
obj.add("mtu", adapter.mtu());
|
||||
});
|
||||
array.finish();
|
||||
TRY(obj.add("packets_in", adapter.packets_in()));
|
||||
TRY(obj.add("bytes_in", adapter.bytes_in()));
|
||||
TRY(obj.add("packets_out", adapter.packets_out()));
|
||||
TRY(obj.add("bytes_out", adapter.bytes_out()));
|
||||
TRY(obj.add("link_up", adapter.link_up()));
|
||||
TRY(obj.add("link_speed", adapter.link_speed()));
|
||||
TRY(obj.add("link_full_duplex", adapter.link_full_duplex()));
|
||||
TRY(obj.add("mtu", adapter.mtu()));
|
||||
TRY(obj.finish());
|
||||
return {};
|
||||
}));
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -79,15 +81,19 @@ private:
|
|||
ProcFSARP();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
arp_table().for_each([&](const auto& it) {
|
||||
auto obj = array.add_object();
|
||||
auto mac_address = it.value.to_string().release_value_but_fixme_should_propagate_errors();
|
||||
obj.add("mac_address", mac_address->view());
|
||||
auto ip_address = it.key.to_string().release_value_but_fixme_should_propagate_errors();
|
||||
obj.add("ip_address", ip_address->view());
|
||||
});
|
||||
array.finish();
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
TRY(arp_table().with([&](const auto& table) -> ErrorOr<void> {
|
||||
for (auto& it : table) {
|
||||
auto obj = TRY(array.add_object());
|
||||
auto mac_address = it.value.to_string().release_value_but_fixme_should_propagate_errors();
|
||||
TRY(obj.add("mac_address", mac_address->view()));
|
||||
auto ip_address = it.key.to_string().release_value_but_fixme_should_propagate_errors();
|
||||
TRY(obj.add("ip_address", ip_address->view()));
|
||||
TRY(obj.finish());
|
||||
}
|
||||
return {};
|
||||
}));
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -100,29 +106,31 @@ private:
|
|||
ProcFSTCP();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
TCPSocket::for_each([&array](auto& socket) {
|
||||
auto obj = array.add_object();
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
TRY(TCPSocket::try_for_each([&array](auto& socket) -> ErrorOr<void> {
|
||||
auto obj = TRY(array.add_object());
|
||||
auto local_address = socket.local_address().to_string().release_value_but_fixme_should_propagate_errors();
|
||||
obj.add("local_address", local_address->view());
|
||||
obj.add("local_port", socket.local_port());
|
||||
TRY(obj.add("local_address", local_address->view()));
|
||||
TRY(obj.add("local_port", socket.local_port()));
|
||||
auto peer_address = socket.peer_address().to_string().release_value_but_fixme_should_propagate_errors();
|
||||
obj.add("peer_address", peer_address->view());
|
||||
obj.add("peer_port", socket.peer_port());
|
||||
obj.add("state", TCPSocket::to_string(socket.state()));
|
||||
obj.add("ack_number", socket.ack_number());
|
||||
obj.add("sequence_number", socket.sequence_number());
|
||||
obj.add("packets_in", socket.packets_in());
|
||||
obj.add("bytes_in", socket.bytes_in());
|
||||
obj.add("packets_out", socket.packets_out());
|
||||
obj.add("bytes_out", socket.bytes_out());
|
||||
TRY(obj.add("peer_address", peer_address->view()));
|
||||
TRY(obj.add("peer_port", socket.peer_port()));
|
||||
TRY(obj.add("state", TCPSocket::to_string(socket.state())));
|
||||
TRY(obj.add("ack_number", socket.ack_number()));
|
||||
TRY(obj.add("sequence_number", socket.sequence_number()));
|
||||
TRY(obj.add("packets_in", socket.packets_in()));
|
||||
TRY(obj.add("bytes_in", socket.bytes_in()));
|
||||
TRY(obj.add("packets_out", socket.packets_out()));
|
||||
TRY(obj.add("bytes_out", socket.bytes_out()));
|
||||
if (Process::current().is_superuser() || Process::current().uid() == socket.origin_uid()) {
|
||||
obj.add("origin_pid", socket.origin_pid().value());
|
||||
obj.add("origin_uid", socket.origin_uid().value());
|
||||
obj.add("origin_gid", socket.origin_gid().value());
|
||||
TRY(obj.add("origin_pid", socket.origin_pid().value()));
|
||||
TRY(obj.add("origin_uid", socket.origin_uid().value()));
|
||||
TRY(obj.add("origin_gid", socket.origin_gid().value()));
|
||||
}
|
||||
});
|
||||
array.finish();
|
||||
TRY(obj.finish());
|
||||
return {};
|
||||
}));
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -135,18 +143,20 @@ private:
|
|||
ProcFSLocalNet();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
LocalSocket::for_each([&array](auto& socket) {
|
||||
auto obj = array.add_object();
|
||||
obj.add("path", socket.socket_path());
|
||||
obj.add("origin_pid", socket.origin_pid().value());
|
||||
obj.add("origin_uid", socket.origin_uid().value());
|
||||
obj.add("origin_gid", socket.origin_gid().value());
|
||||
obj.add("acceptor_pid", socket.acceptor_pid().value());
|
||||
obj.add("acceptor_uid", socket.acceptor_uid().value());
|
||||
obj.add("acceptor_gid", socket.acceptor_gid().value());
|
||||
});
|
||||
array.finish();
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
TRY(LocalSocket::try_for_each([&array](auto& socket) -> ErrorOr<void> {
|
||||
auto obj = TRY(array.add_object());
|
||||
TRY(obj.add("path", socket.socket_path()));
|
||||
TRY(obj.add("origin_pid", socket.origin_pid().value()));
|
||||
TRY(obj.add("origin_uid", socket.origin_uid().value()));
|
||||
TRY(obj.add("origin_gid", socket.origin_gid().value()));
|
||||
TRY(obj.add("acceptor_pid", socket.acceptor_pid().value()));
|
||||
TRY(obj.add("acceptor_uid", socket.acceptor_uid().value()));
|
||||
TRY(obj.add("acceptor_gid", socket.acceptor_gid().value()));
|
||||
TRY(obj.finish());
|
||||
return {};
|
||||
}));
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -159,22 +169,24 @@ private:
|
|||
ProcFSUDP();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
UDPSocket::for_each([&array](auto& socket) {
|
||||
auto obj = array.add_object();
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
TRY(UDPSocket::try_for_each([&array](auto& socket) -> ErrorOr<void> {
|
||||
auto obj = TRY(array.add_object());
|
||||
auto local_address = socket.local_address().to_string().release_value_but_fixme_should_propagate_errors();
|
||||
obj.add("local_address", local_address->view());
|
||||
obj.add("local_port", socket.local_port());
|
||||
TRY(obj.add("local_address", local_address->view()));
|
||||
TRY(obj.add("local_port", socket.local_port()));
|
||||
auto peer_address = socket.peer_address().to_string().release_value_but_fixme_should_propagate_errors();
|
||||
obj.add("peer_address", peer_address->view());
|
||||
obj.add("peer_port", socket.peer_port());
|
||||
TRY(obj.add("peer_address", peer_address->view()));
|
||||
TRY(obj.add("peer_port", socket.peer_port()));
|
||||
if (Process::current().is_superuser() || Process::current().uid() == socket.origin_uid()) {
|
||||
obj.add("origin_pid", socket.origin_pid().value());
|
||||
obj.add("origin_uid", socket.origin_uid().value());
|
||||
obj.add("origin_gid", socket.origin_gid().value());
|
||||
TRY(obj.add("origin_pid", socket.origin_pid().value()));
|
||||
TRY(obj.add("origin_uid", socket.origin_uid().value()));
|
||||
TRY(obj.add("origin_gid", socket.origin_gid().value()));
|
||||
}
|
||||
});
|
||||
array.finish();
|
||||
TRY(obj.finish());
|
||||
return {};
|
||||
}));
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -349,43 +361,33 @@ private:
|
|||
ProcFSDiskUsage();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
ErrorOr<void> result;
|
||||
VirtualFileSystem::the().for_each_mount([&array, &result](auto& mount) {
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
TRY(VirtualFileSystem::the().for_each_mount([&array](auto& mount) -> ErrorOr<void> {
|
||||
auto& fs = mount.guest_fs();
|
||||
auto fs_object = array.add_object();
|
||||
fs_object.add("class_name", fs.class_name());
|
||||
fs_object.add("total_block_count", fs.total_block_count());
|
||||
fs_object.add("free_block_count", fs.free_block_count());
|
||||
fs_object.add("total_inode_count", fs.total_inode_count());
|
||||
fs_object.add("free_inode_count", fs.free_inode_count());
|
||||
auto mount_point_or_error = mount.absolute_path();
|
||||
if (mount_point_or_error.is_error()) {
|
||||
result = mount_point_or_error.release_error();
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
fs_object.add("mount_point", mount_point_or_error.value()->view());
|
||||
fs_object.add("block_size", static_cast<u64>(fs.block_size()));
|
||||
fs_object.add("readonly", fs.is_readonly());
|
||||
fs_object.add("mount_flags", mount.flags());
|
||||
auto fs_object = TRY(array.add_object());
|
||||
TRY(fs_object.add("class_name", fs.class_name()));
|
||||
TRY(fs_object.add("total_block_count", fs.total_block_count()));
|
||||
TRY(fs_object.add("free_block_count", fs.free_block_count()));
|
||||
TRY(fs_object.add("total_inode_count", fs.total_inode_count()));
|
||||
TRY(fs_object.add("free_inode_count", fs.free_inode_count()));
|
||||
auto mount_point = TRY(mount.absolute_path());
|
||||
TRY(fs_object.add("mount_point", mount_point->view()));
|
||||
TRY(fs_object.add("block_size", static_cast<u64>(fs.block_size())));
|
||||
TRY(fs_object.add("readonly", fs.is_readonly()));
|
||||
TRY(fs_object.add("mount_flags", mount.flags()));
|
||||
|
||||
if (fs.is_file_backed()) {
|
||||
auto pseudo_path_or_error = static_cast<const FileBackedFileSystem&>(fs).file_description().pseudo_path();
|
||||
if (pseudo_path_or_error.is_error()) {
|
||||
// We're probably out of memory and should not attempt to continue.
|
||||
result = pseudo_path_or_error.release_error();
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
fs_object.add("source", pseudo_path_or_error.value()->view());
|
||||
auto pseudo_path = TRY(static_cast<const FileBackedFileSystem&>(fs).file_description().pseudo_path());
|
||||
TRY(fs_object.add("source", pseudo_path->view()));
|
||||
} else {
|
||||
fs_object.add("source", "none");
|
||||
TRY(fs_object.add("source", "none"));
|
||||
}
|
||||
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
if (!result.is_error())
|
||||
array.finish();
|
||||
return result;
|
||||
TRY(fs_object.finish());
|
||||
return {};
|
||||
}));
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -404,18 +406,18 @@ private:
|
|||
|
||||
auto system_memory = MM.get_system_memory_info();
|
||||
|
||||
JsonObjectSerializer<KBufferBuilder> json { builder };
|
||||
json.add("kmalloc_allocated", stats.bytes_allocated);
|
||||
json.add("kmalloc_available", stats.bytes_free);
|
||||
json.add("user_physical_allocated", system_memory.user_physical_pages_used);
|
||||
json.add("user_physical_available", system_memory.user_physical_pages - system_memory.user_physical_pages_used);
|
||||
json.add("user_physical_committed", system_memory.user_physical_pages_committed);
|
||||
json.add("user_physical_uncommitted", system_memory.user_physical_pages_uncommitted);
|
||||
json.add("super_physical_allocated", system_memory.super_physical_pages_used);
|
||||
json.add("super_physical_available", system_memory.super_physical_pages - system_memory.super_physical_pages_used);
|
||||
json.add("kmalloc_call_count", stats.kmalloc_call_count);
|
||||
json.add("kfree_call_count", stats.kfree_call_count);
|
||||
json.finish();
|
||||
auto json = TRY(JsonObjectSerializer<>::try_create(builder));
|
||||
TRY(json.add("kmalloc_allocated", stats.bytes_allocated));
|
||||
TRY(json.add("kmalloc_available", stats.bytes_free));
|
||||
TRY(json.add("user_physical_allocated", system_memory.user_physical_pages_used));
|
||||
TRY(json.add("user_physical_available", system_memory.user_physical_pages - system_memory.user_physical_pages_used));
|
||||
TRY(json.add("user_physical_committed", system_memory.user_physical_pages_committed));
|
||||
TRY(json.add("user_physical_uncommitted", system_memory.user_physical_pages_uncommitted));
|
||||
TRY(json.add("super_physical_allocated", system_memory.super_physical_pages_used));
|
||||
TRY(json.add("super_physical_available", system_memory.super_physical_pages - system_memory.super_physical_pages_used));
|
||||
TRY(json.add("kmalloc_call_count", stats.kmalloc_call_count));
|
||||
TRY(json.add("kfree_call_count", stats.kfree_call_count));
|
||||
TRY(json.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -428,17 +430,17 @@ private:
|
|||
ProcFSSystemStatistics();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonObjectSerializer<KBufferBuilder> json { builder };
|
||||
auto json = TRY(JsonObjectSerializer<>::try_create(builder));
|
||||
auto total_time_scheduled = Scheduler::get_total_time_scheduled();
|
||||
json.add("total_time", total_time_scheduled.total);
|
||||
json.add("kernel_time", total_time_scheduled.total_kernel);
|
||||
json.add("user_time", total_time_scheduled.total - total_time_scheduled.total_kernel);
|
||||
TRY(json.add("total_time", total_time_scheduled.total));
|
||||
TRY(json.add("kernel_time", total_time_scheduled.total_kernel));
|
||||
TRY(json.add("user_time", total_time_scheduled.total - total_time_scheduled.total_kernel));
|
||||
u64 idle_time = 0;
|
||||
Processor::for_each([&](Processor& processor) {
|
||||
idle_time += processor.time_spent_idle();
|
||||
});
|
||||
json.add("idle_time", idle_time);
|
||||
json.finish();
|
||||
TRY(json.add("idle_time", idle_time));
|
||||
TRY(json.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -451,11 +453,11 @@ private:
|
|||
ProcFSOverallProcesses();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonObjectSerializer<KBufferBuilder> json { builder };
|
||||
auto json = TRY(JsonObjectSerializer<>::try_create(builder));
|
||||
|
||||
// Keep this in sync with CProcessStatistics.
|
||||
auto build_process = [&](JsonArraySerializer<KBufferBuilder>& array, const Process& process) -> ErrorOr<void> {
|
||||
auto process_object = array.add_object();
|
||||
auto process_object = TRY(array.add_object());
|
||||
|
||||
if (process.is_user_process()) {
|
||||
StringBuilder pledge_builder;
|
||||
|
@ -466,90 +468,96 @@ private:
|
|||
ENUMERATE_PLEDGE_PROMISES
|
||||
#undef __ENUMERATE_PLEDGE_PROMISE
|
||||
|
||||
process_object.add("pledge", pledge_builder.string_view());
|
||||
TRY(process_object.add("pledge", pledge_builder.string_view()));
|
||||
|
||||
switch (process.veil_state()) {
|
||||
case VeilState::None:
|
||||
process_object.add("veil", "None");
|
||||
TRY(process_object.add("veil", "None"));
|
||||
break;
|
||||
case VeilState::Dropped:
|
||||
process_object.add("veil", "Dropped");
|
||||
TRY(process_object.add("veil", "Dropped"));
|
||||
break;
|
||||
case VeilState::Locked:
|
||||
process_object.add("veil", "Locked");
|
||||
TRY(process_object.add("veil", "Locked"));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
process_object.add("pledge", ""sv);
|
||||
process_object.add("veil", ""sv);
|
||||
TRY(process_object.add("pledge", ""sv));
|
||||
TRY(process_object.add("veil", ""sv));
|
||||
}
|
||||
|
||||
process_object.add("pid", process.pid().value());
|
||||
process_object.add("pgid", process.tty() ? process.tty()->pgid().value() : 0);
|
||||
process_object.add("pgp", process.pgid().value());
|
||||
process_object.add("sid", process.sid().value());
|
||||
process_object.add("uid", process.uid().value());
|
||||
process_object.add("gid", process.gid().value());
|
||||
process_object.add("ppid", process.ppid().value());
|
||||
process_object.add("nfds", process.fds().with_shared([](auto& fds) { return fds.open_count(); }));
|
||||
process_object.add("name", process.name());
|
||||
process_object.add("executable", process.executable() ? TRY(process.executable()->try_serialize_absolute_path())->view() : ""sv);
|
||||
process_object.add("tty", process.tty() ? process.tty()->tty_name().view() : "notty"sv);
|
||||
process_object.add("amount_virtual", process.address_space().amount_virtual());
|
||||
process_object.add("amount_resident", process.address_space().amount_resident());
|
||||
process_object.add("amount_dirty_private", process.address_space().amount_dirty_private());
|
||||
process_object.add("amount_clean_inode", TRY(process.address_space().amount_clean_inode()));
|
||||
process_object.add("amount_shared", process.address_space().amount_shared());
|
||||
process_object.add("amount_purgeable_volatile", process.address_space().amount_purgeable_volatile());
|
||||
process_object.add("amount_purgeable_nonvolatile", process.address_space().amount_purgeable_nonvolatile());
|
||||
process_object.add("dumpable", process.is_dumpable());
|
||||
process_object.add("kernel", process.is_kernel_process());
|
||||
auto thread_array = process_object.add_array("threads");
|
||||
process.for_each_thread([&](const Thread& thread) {
|
||||
TRY(process_object.add("pid", process.pid().value()));
|
||||
TRY(process_object.add("pgid", process.tty() ? process.tty()->pgid().value() : 0));
|
||||
TRY(process_object.add("pgp", process.pgid().value()));
|
||||
TRY(process_object.add("sid", process.sid().value()));
|
||||
TRY(process_object.add("uid", process.uid().value()));
|
||||
TRY(process_object.add("gid", process.gid().value()));
|
||||
TRY(process_object.add("ppid", process.ppid().value()));
|
||||
TRY(process_object.add("nfds", process.fds().with_shared([](auto& fds) { return fds.open_count(); })));
|
||||
TRY(process_object.add("name", process.name()));
|
||||
TRY(process_object.add("executable", process.executable() ? TRY(process.executable()->try_serialize_absolute_path())->view() : ""sv));
|
||||
TRY(process_object.add("tty", process.tty() ? process.tty()->tty_name().view() : "notty"sv));
|
||||
TRY(process_object.add("amount_virtual", process.address_space().amount_virtual()));
|
||||
TRY(process_object.add("amount_resident", process.address_space().amount_resident()));
|
||||
TRY(process_object.add("amount_dirty_private", process.address_space().amount_dirty_private()));
|
||||
TRY(process_object.add("amount_clean_inode", TRY(process.address_space().amount_clean_inode())));
|
||||
TRY(process_object.add("amount_shared", process.address_space().amount_shared()));
|
||||
TRY(process_object.add("amount_purgeable_volatile", process.address_space().amount_purgeable_volatile()));
|
||||
TRY(process_object.add("amount_purgeable_nonvolatile", process.address_space().amount_purgeable_nonvolatile()));
|
||||
TRY(process_object.add("dumpable", process.is_dumpable()));
|
||||
TRY(process_object.add("kernel", process.is_kernel_process()));
|
||||
auto thread_array = TRY(process_object.add_array("threads"));
|
||||
TRY(process.try_for_each_thread([&](const Thread& thread) -> ErrorOr<void> {
|
||||
SpinlockLocker locker(thread.get_lock());
|
||||
auto thread_object = thread_array.add_object();
|
||||
auto thread_object = TRY(thread_array.add_object());
|
||||
#if LOCK_DEBUG
|
||||
thread_object.add("lock_count", thread.lock_count());
|
||||
TRY(thread_object.add("lock_count", thread.lock_count()));
|
||||
#endif
|
||||
thread_object.add("tid", thread.tid().value());
|
||||
thread_object.add("name", thread.name());
|
||||
thread_object.add("times_scheduled", thread.times_scheduled());
|
||||
thread_object.add("time_user", thread.time_in_user());
|
||||
thread_object.add("time_kernel", thread.time_in_kernel());
|
||||
thread_object.add("state", thread.state_string());
|
||||
thread_object.add("cpu", thread.cpu());
|
||||
thread_object.add("priority", thread.priority());
|
||||
thread_object.add("syscall_count", thread.syscall_count());
|
||||
thread_object.add("inode_faults", thread.inode_faults());
|
||||
thread_object.add("zero_faults", thread.zero_faults());
|
||||
thread_object.add("cow_faults", thread.cow_faults());
|
||||
thread_object.add("file_read_bytes", thread.file_read_bytes());
|
||||
thread_object.add("file_write_bytes", thread.file_write_bytes());
|
||||
thread_object.add("unix_socket_read_bytes", thread.unix_socket_read_bytes());
|
||||
thread_object.add("unix_socket_write_bytes", thread.unix_socket_write_bytes());
|
||||
thread_object.add("ipv4_socket_read_bytes", thread.ipv4_socket_read_bytes());
|
||||
thread_object.add("ipv4_socket_write_bytes", thread.ipv4_socket_write_bytes());
|
||||
});
|
||||
TRY(thread_object.add("tid", thread.tid().value()));
|
||||
TRY(thread_object.add("name", thread.name()));
|
||||
TRY(thread_object.add("times_scheduled", thread.times_scheduled()));
|
||||
TRY(thread_object.add("time_user", thread.time_in_user()));
|
||||
TRY(thread_object.add("time_kernel", thread.time_in_kernel()));
|
||||
TRY(thread_object.add("state", thread.state_string()));
|
||||
TRY(thread_object.add("cpu", thread.cpu()));
|
||||
TRY(thread_object.add("priority", thread.priority()));
|
||||
TRY(thread_object.add("syscall_count", thread.syscall_count()));
|
||||
TRY(thread_object.add("inode_faults", thread.inode_faults()));
|
||||
TRY(thread_object.add("zero_faults", thread.zero_faults()));
|
||||
TRY(thread_object.add("cow_faults", thread.cow_faults()));
|
||||
TRY(thread_object.add("file_read_bytes", thread.file_read_bytes()));
|
||||
TRY(thread_object.add("file_write_bytes", thread.file_write_bytes()));
|
||||
TRY(thread_object.add("unix_socket_read_bytes", thread.unix_socket_read_bytes()));
|
||||
TRY(thread_object.add("unix_socket_write_bytes", thread.unix_socket_write_bytes()));
|
||||
TRY(thread_object.add("ipv4_socket_read_bytes", thread.ipv4_socket_read_bytes()));
|
||||
TRY(thread_object.add("ipv4_socket_write_bytes", thread.ipv4_socket_write_bytes()));
|
||||
|
||||
TRY(thread_object.finish());
|
||||
return {};
|
||||
}));
|
||||
TRY(thread_array.finish());
|
||||
TRY(process_object.finish());
|
||||
return {};
|
||||
};
|
||||
|
||||
SpinlockLocker lock(g_scheduler_lock);
|
||||
{
|
||||
{
|
||||
auto array = json.add_array("processes");
|
||||
auto array = TRY(json.add_array("processes"));
|
||||
TRY(build_process(array, *Scheduler::colonel()));
|
||||
TRY(Process::all_instances().with([&](auto& processes) -> ErrorOr<void> {
|
||||
for (auto& process : processes)
|
||||
TRY(build_process(array, process));
|
||||
return {};
|
||||
}));
|
||||
TRY(array.finish());
|
||||
}
|
||||
|
||||
auto total_time_scheduled = Scheduler::get_total_time_scheduled();
|
||||
json.add("total_time", total_time_scheduled.total);
|
||||
json.add("total_time_kernel", total_time_scheduled.total_kernel);
|
||||
TRY(json.add("total_time", total_time_scheduled.total));
|
||||
TRY(json.add("total_time_kernel", total_time_scheduled.total_kernel));
|
||||
}
|
||||
TRY(json.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -561,28 +569,37 @@ private:
|
|||
ProcFSCPUInformation();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
Processor::for_each(
|
||||
[&](Processor& proc) {
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
TRY(Processor::try_for_each(
|
||||
[&](Processor& proc) -> ErrorOr<void> {
|
||||
auto& info = proc.info();
|
||||
auto obj = array.add_object();
|
||||
obj.add("processor", proc.id());
|
||||
obj.add("cpuid", info.cpuid());
|
||||
obj.add("family", info.display_family());
|
||||
auto obj = TRY(array.add_object());
|
||||
TRY(obj.add("processor", proc.id()));
|
||||
TRY(obj.add("cpuid", info.cpuid()));
|
||||
TRY(obj.add("family", info.display_family()));
|
||||
|
||||
auto features_array = obj.add_array("features");
|
||||
auto features_array = TRY(obj.add_array("features"));
|
||||
auto keep_empty = false;
|
||||
info.features().for_each_split_view(' ', keep_empty, [&](StringView feature) {
|
||||
features_array.add(feature);
|
||||
});
|
||||
features_array.finish();
|
||||
|
||||
obj.add("model", info.display_model());
|
||||
obj.add("stepping", info.stepping());
|
||||
obj.add("type", info.type());
|
||||
obj.add("brand", info.brand());
|
||||
});
|
||||
array.finish();
|
||||
ErrorOr<void> result; // FIXME: Make this nicer
|
||||
info.features().for_each_split_view(' ', keep_empty, [&](StringView feature) {
|
||||
if (result.is_error())
|
||||
return;
|
||||
result = features_array.add(feature);
|
||||
});
|
||||
TRY(result);
|
||||
|
||||
TRY(features_array.finish());
|
||||
|
||||
TRY(obj.add("model", info.display_model()));
|
||||
TRY(obj.add("stepping", info.stepping()));
|
||||
TRY(obj.add("type", info.type()));
|
||||
TRY(obj.add("brand", info.brand()));
|
||||
|
||||
TRY(obj.finish());
|
||||
return {};
|
||||
}));
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -612,17 +629,25 @@ private:
|
|||
ProcFSInterrupts();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
InterruptManagement::the().enumerate_interrupt_handlers([&array](GenericInterruptHandler& handler) {
|
||||
auto obj = array.add_object();
|
||||
obj.add("purpose", handler.purpose());
|
||||
obj.add("interrupt_line", handler.interrupt_number());
|
||||
obj.add("controller", handler.controller());
|
||||
obj.add("cpu_handler", 0); // FIXME: Determine the responsible CPU for each interrupt handler.
|
||||
obj.add("device_sharing", (unsigned)handler.sharing_devices_count());
|
||||
obj.add("call_count", (unsigned)handler.get_invoking_count());
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
ErrorOr<void> result; // FIXME: Make this nicer
|
||||
InterruptManagement::the().enumerate_interrupt_handlers([&array, &result](GenericInterruptHandler& handler) {
|
||||
if (result.is_error())
|
||||
return;
|
||||
result = ([&]() -> ErrorOr<void> {
|
||||
auto obj = TRY(array.add_object());
|
||||
TRY(obj.add("purpose", handler.purpose()));
|
||||
TRY(obj.add("interrupt_line", handler.interrupt_number()));
|
||||
TRY(obj.add("controller", handler.controller()));
|
||||
TRY(obj.add("cpu_handler", 0)); // FIXME: Determine the responsible CPU for each interrupt handler.
|
||||
TRY(obj.add("device_sharing", (unsigned)handler.sharing_devices_count()));
|
||||
TRY(obj.add("call_count", (unsigned)handler.get_invoking_count()));
|
||||
TRY(obj.finish());
|
||||
return {};
|
||||
})();
|
||||
});
|
||||
array.finish();
|
||||
TRY(result);
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -634,9 +659,9 @@ private:
|
|||
ProcFSKeymap();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonObjectSerializer<KBufferBuilder> json { builder };
|
||||
json.add("keymap", HIDManagement::the().keymap_name());
|
||||
json.finish();
|
||||
auto json = TRY(JsonObjectSerializer<>::try_create(builder));
|
||||
TRY(json.add("keymap", HIDManagement::the().keymap_name()));
|
||||
TRY(json.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -650,22 +675,30 @@ private:
|
|||
ProcFSPCI();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
PCI::enumerate([&array](PCI::DeviceIdentifier const& device_identifier) {
|
||||
auto obj = array.add_object();
|
||||
obj.add("domain", device_identifier.address().domain());
|
||||
obj.add("bus", device_identifier.address().bus());
|
||||
obj.add("device", device_identifier.address().device());
|
||||
obj.add("function", device_identifier.address().function());
|
||||
obj.add("vendor_id", device_identifier.hardware_id().vendor_id);
|
||||
obj.add("device_id", device_identifier.hardware_id().device_id);
|
||||
obj.add("revision_id", device_identifier.revision_id().value());
|
||||
obj.add("subclass", device_identifier.subclass_code().value());
|
||||
obj.add("class", device_identifier.class_code().value());
|
||||
obj.add("subsystem_id", device_identifier.subsystem_id().value());
|
||||
obj.add("subsystem_vendor_id", device_identifier.subsystem_vendor_id().value());
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
ErrorOr<void> result; // FIXME: Make this nicer
|
||||
PCI::enumerate([&array, &result](PCI::DeviceIdentifier const& device_identifier) {
|
||||
if (result.is_error())
|
||||
return;
|
||||
result = ([&]() -> ErrorOr<void> {
|
||||
auto obj = TRY(array.add_object());
|
||||
TRY(obj.add("domain", device_identifier.address().domain()));
|
||||
TRY(obj.add("bus", device_identifier.address().bus()));
|
||||
TRY(obj.add("device", device_identifier.address().device()));
|
||||
TRY(obj.add("function", device_identifier.address().function()));
|
||||
TRY(obj.add("vendor_id", device_identifier.hardware_id().vendor_id));
|
||||
TRY(obj.add("device_id", device_identifier.hardware_id().device_id));
|
||||
TRY(obj.add("revision_id", device_identifier.revision_id().value()));
|
||||
TRY(obj.add("subclass", device_identifier.subclass_code().value()));
|
||||
TRY(obj.add("class", device_identifier.class_code().value()));
|
||||
TRY(obj.add("subsystem_id", device_identifier.subsystem_id().value()));
|
||||
TRY(obj.add("subsystem_vendor_id", device_identifier.subsystem_vendor_id().value()));
|
||||
TRY(obj.finish());
|
||||
return {};
|
||||
})();
|
||||
});
|
||||
array.finish();
|
||||
TRY(result);
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
@ -678,21 +711,23 @@ private:
|
|||
ProcFSDevices();
|
||||
virtual ErrorOr<void> try_generate(KBufferBuilder& builder) override
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
DeviceManagement::the().for_each([&array](auto& device) {
|
||||
auto obj = array.add_object();
|
||||
obj.add("major", device.major().value());
|
||||
obj.add("minor", device.minor().value());
|
||||
obj.add("class_name", device.class_name());
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
TRY(DeviceManagement::the().try_for_each([&array](auto& device) -> ErrorOr<void> {
|
||||
auto obj = TRY(array.add_object());
|
||||
TRY(obj.add("major", device.major().value()));
|
||||
TRY(obj.add("minor", device.minor().value()));
|
||||
TRY(obj.add("class_name", device.class_name()));
|
||||
|
||||
if (device.is_block_device())
|
||||
obj.add("type", "block");
|
||||
TRY(obj.add("type", "block"));
|
||||
else if (device.is_character_device())
|
||||
obj.add("type", "character");
|
||||
TRY(obj.add("type", "character"));
|
||||
else
|
||||
VERIFY_NOT_REACHED();
|
||||
});
|
||||
array.finish();
|
||||
TRY(obj.finish());
|
||||
return {};
|
||||
}));
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -198,14 +198,14 @@ template<typename Serializer>
|
|||
ErrorOr<void> PerformanceEventBuffer::to_json_impl(Serializer& object) const
|
||||
{
|
||||
{
|
||||
auto strings = object.add_array("strings");
|
||||
for (auto const& it : m_strings) {
|
||||
strings.add(it->view());
|
||||
}
|
||||
auto strings = TRY(object.add_array("strings"));
|
||||
for (auto const& it : m_strings)
|
||||
TRY(strings.add(it->view()));
|
||||
TRY(strings.finish());
|
||||
}
|
||||
|
||||
bool show_kernel_addresses = Process::current().is_superuser();
|
||||
auto array = object.add_array("events");
|
||||
auto array = TRY(object.add_array("events"));
|
||||
bool seen_first_sample = false;
|
||||
for (size_t i = 0; i < m_count; ++i) {
|
||||
auto const& event = at(i);
|
||||
|
@ -215,109 +215,109 @@ ErrorOr<void> PerformanceEventBuffer::to_json_impl(Serializer& object) const
|
|||
continue;
|
||||
}
|
||||
|
||||
auto event_object = array.add_object();
|
||||
auto event_object = TRY(array.add_object());
|
||||
switch (event.type) {
|
||||
case PERF_EVENT_SAMPLE:
|
||||
event_object.add("type", "sample");
|
||||
TRY(event_object.add("type", "sample"));
|
||||
break;
|
||||
case PERF_EVENT_MALLOC:
|
||||
event_object.add("type", "malloc");
|
||||
event_object.add("ptr", static_cast<u64>(event.data.malloc.ptr));
|
||||
event_object.add("size", static_cast<u64>(event.data.malloc.size));
|
||||
TRY(event_object.add("type", "malloc"));
|
||||
TRY(event_object.add("ptr", static_cast<u64>(event.data.malloc.ptr)));
|
||||
TRY(event_object.add("size", static_cast<u64>(event.data.malloc.size)));
|
||||
break;
|
||||
case PERF_EVENT_FREE:
|
||||
event_object.add("type", "free");
|
||||
event_object.add("ptr", static_cast<u64>(event.data.free.ptr));
|
||||
TRY(event_object.add("type", "free"));
|
||||
TRY(event_object.add("ptr", static_cast<u64>(event.data.free.ptr)));
|
||||
break;
|
||||
case PERF_EVENT_MMAP:
|
||||
event_object.add("type", "mmap");
|
||||
event_object.add("ptr", static_cast<u64>(event.data.mmap.ptr));
|
||||
event_object.add("size", static_cast<u64>(event.data.mmap.size));
|
||||
event_object.add("name", event.data.mmap.name);
|
||||
TRY(event_object.add("type", "mmap"));
|
||||
TRY(event_object.add("ptr", static_cast<u64>(event.data.mmap.ptr)));
|
||||
TRY(event_object.add("size", static_cast<u64>(event.data.mmap.size)));
|
||||
TRY(event_object.add("name", event.data.mmap.name));
|
||||
break;
|
||||
case PERF_EVENT_MUNMAP:
|
||||
event_object.add("type", "munmap");
|
||||
event_object.add("ptr", static_cast<u64>(event.data.munmap.ptr));
|
||||
event_object.add("size", static_cast<u64>(event.data.munmap.size));
|
||||
TRY(event_object.add("type", "munmap"));
|
||||
TRY(event_object.add("ptr", static_cast<u64>(event.data.munmap.ptr)));
|
||||
TRY(event_object.add("size", static_cast<u64>(event.data.munmap.size)));
|
||||
break;
|
||||
case PERF_EVENT_PROCESS_CREATE:
|
||||
event_object.add("type", "process_create");
|
||||
event_object.add("parent_pid", static_cast<u64>(event.data.process_create.parent_pid));
|
||||
event_object.add("executable", event.data.process_create.executable);
|
||||
TRY(event_object.add("type", "process_create"));
|
||||
TRY(event_object.add("parent_pid", static_cast<u64>(event.data.process_create.parent_pid)));
|
||||
TRY(event_object.add("executable", event.data.process_create.executable));
|
||||
break;
|
||||
case PERF_EVENT_PROCESS_EXEC:
|
||||
event_object.add("type", "process_exec");
|
||||
event_object.add("executable", event.data.process_exec.executable);
|
||||
TRY(event_object.add("type", "process_exec"));
|
||||
TRY(event_object.add("executable", event.data.process_exec.executable));
|
||||
break;
|
||||
case PERF_EVENT_PROCESS_EXIT:
|
||||
event_object.add("type", "process_exit");
|
||||
TRY(event_object.add("type", "process_exit"));
|
||||
break;
|
||||
case PERF_EVENT_THREAD_CREATE:
|
||||
event_object.add("type", "thread_create");
|
||||
event_object.add("parent_tid", static_cast<u64>(event.data.thread_create.parent_tid));
|
||||
TRY(event_object.add("type", "thread_create"));
|
||||
TRY(event_object.add("parent_tid", static_cast<u64>(event.data.thread_create.parent_tid)));
|
||||
break;
|
||||
case PERF_EVENT_THREAD_EXIT:
|
||||
event_object.add("type", "thread_exit");
|
||||
TRY(event_object.add("type", "thread_exit"));
|
||||
break;
|
||||
case PERF_EVENT_CONTEXT_SWITCH:
|
||||
event_object.add("type", "context_switch");
|
||||
event_object.add("next_pid", static_cast<u64>(event.data.context_switch.next_pid));
|
||||
event_object.add("next_tid", static_cast<u64>(event.data.context_switch.next_tid));
|
||||
TRY(event_object.add("type", "context_switch"));
|
||||
TRY(event_object.add("next_pid", static_cast<u64>(event.data.context_switch.next_pid)));
|
||||
TRY(event_object.add("next_tid", static_cast<u64>(event.data.context_switch.next_tid)));
|
||||
break;
|
||||
case PERF_EVENT_KMALLOC:
|
||||
event_object.add("type", "kmalloc");
|
||||
event_object.add("ptr", static_cast<u64>(event.data.kmalloc.ptr));
|
||||
event_object.add("size", static_cast<u64>(event.data.kmalloc.size));
|
||||
TRY(event_object.add("type", "kmalloc"));
|
||||
TRY(event_object.add("ptr", static_cast<u64>(event.data.kmalloc.ptr)));
|
||||
TRY(event_object.add("size", static_cast<u64>(event.data.kmalloc.size)));
|
||||
break;
|
||||
case PERF_EVENT_KFREE:
|
||||
event_object.add("type", "kfree");
|
||||
event_object.add("ptr", static_cast<u64>(event.data.kfree.ptr));
|
||||
event_object.add("size", static_cast<u64>(event.data.kfree.size));
|
||||
TRY(event_object.add("type", "kfree"));
|
||||
TRY(event_object.add("ptr", static_cast<u64>(event.data.kfree.ptr)));
|
||||
TRY(event_object.add("size", static_cast<u64>(event.data.kfree.size)));
|
||||
break;
|
||||
case PERF_EVENT_PAGE_FAULT:
|
||||
event_object.add("type", "page_fault");
|
||||
TRY(event_object.add("type", "page_fault"));
|
||||
break;
|
||||
case PERF_EVENT_SYSCALL:
|
||||
event_object.add("type", "syscall");
|
||||
TRY(event_object.add("type", "syscall"));
|
||||
break;
|
||||
case PERF_EVENT_SIGNPOST:
|
||||
event_object.add("type"sv, "signpost"sv);
|
||||
event_object.add("arg1"sv, event.data.signpost.arg1);
|
||||
event_object.add("arg2"sv, event.data.signpost.arg2);
|
||||
TRY(event_object.add("type"sv, "signpost"sv));
|
||||
TRY(event_object.add("arg1"sv, event.data.signpost.arg1));
|
||||
TRY(event_object.add("arg2"sv, event.data.signpost.arg2));
|
||||
break;
|
||||
case PERF_EVENT_READ:
|
||||
event_object.add("type", "read");
|
||||
event_object.add("fd", event.data.read.fd);
|
||||
event_object.add("size"sv, event.data.read.size);
|
||||
event_object.add("filename_index"sv, event.data.read.filename_index);
|
||||
event_object.add("start_timestamp"sv, event.data.read.start_timestamp);
|
||||
event_object.add("success"sv, event.data.read.success);
|
||||
TRY(event_object.add("type", "read"));
|
||||
TRY(event_object.add("fd", event.data.read.fd));
|
||||
TRY(event_object.add("size"sv, event.data.read.size));
|
||||
TRY(event_object.add("filename_index"sv, event.data.read.filename_index));
|
||||
TRY(event_object.add("start_timestamp"sv, event.data.read.start_timestamp));
|
||||
TRY(event_object.add("success"sv, event.data.read.success));
|
||||
break;
|
||||
}
|
||||
event_object.add("pid", event.pid);
|
||||
event_object.add("tid", event.tid);
|
||||
event_object.add("timestamp", event.timestamp);
|
||||
event_object.add("lost_samples", seen_first_sample ? event.lost_samples : 0);
|
||||
TRY(event_object.add("pid", event.pid));
|
||||
TRY(event_object.add("tid", event.tid));
|
||||
TRY(event_object.add("timestamp", event.timestamp));
|
||||
TRY(event_object.add("lost_samples", seen_first_sample ? event.lost_samples : 0));
|
||||
if (event.type == PERF_EVENT_SAMPLE)
|
||||
seen_first_sample = true;
|
||||
auto stack_array = event_object.add_array("stack");
|
||||
auto stack_array = TRY(event_object.add_array("stack"));
|
||||
for (size_t j = 0; j < event.stack_size; ++j) {
|
||||
auto address = event.stack[j];
|
||||
if (!show_kernel_addresses && !Memory::is_user_address(VirtualAddress { address }))
|
||||
address = 0xdeadc0de;
|
||||
stack_array.add(address);
|
||||
TRY(stack_array.add(address));
|
||||
}
|
||||
stack_array.finish();
|
||||
event_object.finish();
|
||||
TRY(stack_array.finish());
|
||||
TRY(event_object.finish());
|
||||
}
|
||||
array.finish();
|
||||
object.finish();
|
||||
TRY(array.finish());
|
||||
TRY(object.finish());
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> PerformanceEventBuffer::to_json(KBufferBuilder& builder) const
|
||||
{
|
||||
JsonObjectSerializer object(builder);
|
||||
auto object = TRY(JsonObjectSerializer<>::try_create(builder));
|
||||
return to_json_impl(object);
|
||||
}
|
||||
|
||||
|
|
|
@ -488,12 +488,13 @@ public:
|
|||
Thread::WaitBlockerSet& wait_blocker_set() { return m_wait_blocker_set; }
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_coredump_property(Callback callback) const
|
||||
ErrorOr<void> for_each_coredump_property(Callback callback) const
|
||||
{
|
||||
for (auto const& property : m_coredump_properties) {
|
||||
if (property.key && property.value)
|
||||
callback(*property.key, *property.value);
|
||||
TRY(callback(*property.key, *property.value));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> set_coredump_property(NonnullOwnPtr<KString> key, NonnullOwnPtr<KString> value);
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Kernel {
|
|||
|
||||
ErrorOr<void> Process::procfs_get_thread_stack(ThreadID thread_id, KBufferBuilder& builder) const
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
auto thread = Thread::from_tid(thread_id);
|
||||
if (!thread)
|
||||
return ESRCH;
|
||||
|
@ -34,10 +34,10 @@ ErrorOr<void> Process::procfs_get_thread_stack(ThreadID thread_id, KBufferBuilde
|
|||
address = 0xdeadc0de;
|
||||
kernel_address_added = true;
|
||||
}
|
||||
array.add(address);
|
||||
TRY(array.add(address));
|
||||
}
|
||||
|
||||
array.finish();
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -125,31 +125,31 @@ ErrorOr<NonnullRefPtr<Inode>> Process::lookup_file_descriptions_directory(const
|
|||
|
||||
ErrorOr<void> Process::procfs_get_pledge_stats(KBufferBuilder& builder) const
|
||||
{
|
||||
JsonObjectSerializer obj { builder };
|
||||
#define __ENUMERATE_PLEDGE_PROMISE(x) \
|
||||
if (has_promised(Pledge::x)) { \
|
||||
if (!builder.is_empty()) \
|
||||
TRY(builder.try_append(' ')); \
|
||||
TRY(builder.try_append(#x)); \
|
||||
auto obj = TRY(JsonObjectSerializer<>::try_create(builder));
|
||||
#define __ENUMERATE_PLEDGE_PROMISE(x) \
|
||||
if (has_promised(Pledge::x)) { \
|
||||
if (!promises_builder.is_empty()) \
|
||||
TRY(promises_builder.try_append(' ')); \
|
||||
TRY(promises_builder.try_append(#x)); \
|
||||
}
|
||||
if (has_promises()) {
|
||||
StringBuilder builder;
|
||||
StringBuilder promises_builder;
|
||||
ENUMERATE_PLEDGE_PROMISES
|
||||
obj.add("promises", builder.string_view());
|
||||
TRY(obj.add("promises", promises_builder.string_view()));
|
||||
}
|
||||
#undef __ENUMERATE_PLEDGE_PROMISE
|
||||
obj.finish();
|
||||
TRY(obj.finish());
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> Process::procfs_get_unveil_stats(KBufferBuilder& builder) const
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
TRY(unveiled_paths().for_each_node_in_tree_order([&](auto const& unveiled_path) {
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
TRY(unveiled_paths().for_each_node_in_tree_order([&](auto const& unveiled_path) -> ErrorOr<IterationDecision> {
|
||||
if (!unveiled_path.was_explicitly_unveiled())
|
||||
return;
|
||||
auto obj = array.add_object();
|
||||
obj.add("path", unveiled_path.path());
|
||||
return IterationDecision::Continue;
|
||||
auto obj = TRY(array.add_object());
|
||||
TRY(obj.add("path", unveiled_path.path()));
|
||||
StringBuilder permissions_builder;
|
||||
if (unveiled_path.permissions() & UnveilAccess::Read)
|
||||
permissions_builder.append('r');
|
||||
|
@ -161,9 +161,11 @@ ErrorOr<void> Process::procfs_get_unveil_stats(KBufferBuilder& builder) const
|
|||
permissions_builder.append('c');
|
||||
if (unveiled_path.permissions() & UnveilAccess::Browse)
|
||||
permissions_builder.append('b');
|
||||
obj.add("permissions", permissions_builder.string_view());
|
||||
TRY(obj.add("permissions", permissions_builder.string_view()));
|
||||
TRY(obj.finish());
|
||||
return IterationDecision::Continue;
|
||||
}));
|
||||
array.finish();
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -179,76 +181,78 @@ ErrorOr<void> Process::procfs_get_perf_events(KBufferBuilder& builder) const
|
|||
|
||||
ErrorOr<void> Process::procfs_get_fds_stats(KBufferBuilder& builder) const
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
|
||||
return fds().with_shared([&](auto& fds) -> ErrorOr<void> {
|
||||
if (fds.open_count() == 0) {
|
||||
array.finish();
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
fds.enumerate([&](auto& file_description_metadata) {
|
||||
TRY(fds.try_enumerate([&](auto& file_description_metadata) -> ErrorOr<void> {
|
||||
if (!file_description_metadata.is_valid()) {
|
||||
count++;
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
bool cloexec = file_description_metadata.flags() & FD_CLOEXEC;
|
||||
RefPtr<OpenFileDescription> description = file_description_metadata.description();
|
||||
auto description_object = array.add_object();
|
||||
description_object.add("fd", count);
|
||||
auto description_object = TRY(array.add_object());
|
||||
TRY(description_object.add("fd", count));
|
||||
// TODO: Better OOM handling.
|
||||
auto pseudo_path_or_error = description->pseudo_path();
|
||||
description_object.add("absolute_path", pseudo_path_or_error.is_error() ? "???"sv : pseudo_path_or_error.value()->view());
|
||||
description_object.add("seekable", description->file().is_seekable());
|
||||
description_object.add("class", description->file().class_name());
|
||||
description_object.add("offset", description->offset());
|
||||
description_object.add("cloexec", cloexec);
|
||||
description_object.add("blocking", description->is_blocking());
|
||||
description_object.add("can_read", description->can_read());
|
||||
description_object.add("can_write", description->can_write());
|
||||
TRY(description_object.add("absolute_path", pseudo_path_or_error.is_error() ? "???"sv : pseudo_path_or_error.value()->view()));
|
||||
TRY(description_object.add("seekable", description->file().is_seekable()));
|
||||
TRY(description_object.add("class", description->file().class_name()));
|
||||
TRY(description_object.add("offset", description->offset()));
|
||||
TRY(description_object.add("cloexec", cloexec));
|
||||
TRY(description_object.add("blocking", description->is_blocking()));
|
||||
TRY(description_object.add("can_read", description->can_read()));
|
||||
TRY(description_object.add("can_write", description->can_write()));
|
||||
Inode* inode = description->inode();
|
||||
if (inode != nullptr) {
|
||||
auto inode_object = description_object.add_object("inode");
|
||||
inode_object.add("fsid", inode->fsid().value());
|
||||
inode_object.add("index", inode->index().value());
|
||||
inode_object.finish();
|
||||
auto inode_object = TRY(description_object.add_object("inode"));
|
||||
TRY(inode_object.add("fsid", inode->fsid().value()));
|
||||
TRY(inode_object.add("index", inode->index().value()));
|
||||
TRY(inode_object.finish());
|
||||
}
|
||||
TRY(description_object.finish());
|
||||
count++;
|
||||
});
|
||||
return {};
|
||||
}));
|
||||
|
||||
array.finish();
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<void> Process::procfs_get_virtual_memory_stats(KBufferBuilder& builder) const
|
||||
{
|
||||
JsonArraySerializer array { builder };
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
{
|
||||
SpinlockLocker lock(address_space().get_lock());
|
||||
for (auto const& region : address_space().regions()) {
|
||||
if (!region->is_user() && !Process::current().is_superuser())
|
||||
continue;
|
||||
auto region_object = array.add_object();
|
||||
region_object.add("readable", region->is_readable());
|
||||
region_object.add("writable", region->is_writable());
|
||||
region_object.add("executable", region->is_executable());
|
||||
region_object.add("stack", region->is_stack());
|
||||
region_object.add("shared", region->is_shared());
|
||||
region_object.add("syscall", region->is_syscall_region());
|
||||
region_object.add("purgeable", region->vmobject().is_anonymous());
|
||||
auto region_object = TRY(array.add_object());
|
||||
TRY(region_object.add("readable", region->is_readable()));
|
||||
TRY(region_object.add("writable", region->is_writable()));
|
||||
TRY(region_object.add("executable", region->is_executable()));
|
||||
TRY(region_object.add("stack", region->is_stack()));
|
||||
TRY(region_object.add("shared", region->is_shared()));
|
||||
TRY(region_object.add("syscall", region->is_syscall_region()));
|
||||
TRY(region_object.add("purgeable", region->vmobject().is_anonymous()));
|
||||
if (region->vmobject().is_anonymous()) {
|
||||
region_object.add("volatile", static_cast<Memory::AnonymousVMObject const&>(region->vmobject()).is_volatile());
|
||||
TRY(region_object.add("volatile", static_cast<Memory::AnonymousVMObject const&>(region->vmobject()).is_volatile()));
|
||||
}
|
||||
region_object.add("cacheable", region->is_cacheable());
|
||||
region_object.add("address", region->vaddr().get());
|
||||
region_object.add("size", region->size());
|
||||
region_object.add("amount_resident", region->amount_resident());
|
||||
region_object.add("amount_dirty", region->amount_dirty());
|
||||
region_object.add("cow_pages", region->cow_pages());
|
||||
region_object.add("name", region->name());
|
||||
region_object.add("vmobject", region->vmobject().class_name());
|
||||
TRY(region_object.add("cacheable", region->is_cacheable()));
|
||||
TRY(region_object.add("address", region->vaddr().get()));
|
||||
TRY(region_object.add("size", region->size()));
|
||||
TRY(region_object.add("amount_resident", region->amount_resident()));
|
||||
TRY(region_object.add("amount_dirty", region->amount_dirty()));
|
||||
TRY(region_object.add("cow_pages", region->cow_pages()));
|
||||
TRY(region_object.add("name", region->name()));
|
||||
TRY(region_object.add("vmobject", region->vmobject().class_name()));
|
||||
|
||||
StringBuilder pagemap_builder;
|
||||
for (size_t i = 0; i < region->page_count(); ++i) {
|
||||
|
@ -260,10 +264,11 @@ ErrorOr<void> Process::procfs_get_virtual_memory_stats(KBufferBuilder& builder)
|
|||
else
|
||||
pagemap_builder.append('P');
|
||||
}
|
||||
region_object.add("pagemap", pagemap_builder.string_view());
|
||||
TRY(region_object.add("pagemap", pagemap_builder.string_view()));
|
||||
TRY(region_object.finish());
|
||||
}
|
||||
}
|
||||
array.finish();
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -111,22 +111,22 @@ ErrorOr<NonnullRefPtr<Image>> Image::try_create_from_pixel_paint_json(JsonObject
|
|||
|
||||
void Image::serialize_as_json(JsonObjectSerializer<StringBuilder>& json) const
|
||||
{
|
||||
json.add("width", m_size.width());
|
||||
json.add("height", m_size.height());
|
||||
MUST(json.add("width", m_size.width()));
|
||||
MUST(json.add("height", m_size.height()));
|
||||
{
|
||||
auto json_layers = json.add_array("layers");
|
||||
auto json_layers = MUST(json.add_array("layers"));
|
||||
for (const auto& layer : m_layers) {
|
||||
Gfx::BMPWriter bmp_dumber;
|
||||
auto json_layer = json_layers.add_object();
|
||||
json_layer.add("width", layer.size().width());
|
||||
json_layer.add("height", layer.size().height());
|
||||
json_layer.add("name", layer.name());
|
||||
json_layer.add("locationx", layer.location().x());
|
||||
json_layer.add("locationy", layer.location().y());
|
||||
json_layer.add("opacity_percent", layer.opacity_percent());
|
||||
json_layer.add("visible", layer.is_visible());
|
||||
json_layer.add("selected", layer.is_selected());
|
||||
json_layer.add("bitmap", encode_base64(bmp_dumber.dump(layer.bitmap())));
|
||||
auto json_layer = MUST(json_layers.add_object());
|
||||
MUST(json_layer.add("width", layer.size().width()));
|
||||
MUST(json_layer.add("height", layer.size().height()));
|
||||
MUST(json_layer.add("name", layer.name()));
|
||||
MUST(json_layer.add("locationx", layer.location().x()));
|
||||
MUST(json_layer.add("locationy", layer.location().y()));
|
||||
MUST(json_layer.add("opacity_percent", layer.opacity_percent()));
|
||||
MUST(json_layer.add("visible", layer.is_visible()));
|
||||
MUST(json_layer.add("selected", layer.is_selected()));
|
||||
MUST(json_layer.add("bitmap", encode_base64(bmp_dumber.dump(layer.bitmap()))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,9 +134,9 @@ void Image::serialize_as_json(JsonObjectSerializer<StringBuilder>& json) const
|
|||
ErrorOr<void> Image::write_to_file(const String& file_path) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
JsonObjectSerializer json(builder);
|
||||
auto json = MUST(JsonObjectSerializer<>::try_create(builder));
|
||||
serialize_as_json(json);
|
||||
json.finish();
|
||||
MUST(json.finish());
|
||||
|
||||
auto file = TRY(Core::File::open(file_path, (Core::OpenMode)(Core::OpenMode::WriteOnly | Core::OpenMode::Truncate)));
|
||||
if (!file->write(builder.string_view()))
|
||||
|
|
|
@ -602,20 +602,20 @@ void ImageEditor::save_project_as()
|
|||
Result<void, String> ImageEditor::save_project_to_file(Core::File& file) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
JsonObjectSerializer json(builder);
|
||||
auto json = MUST(JsonObjectSerializer<>::try_create(builder));
|
||||
m_image->serialize_as_json(json);
|
||||
auto json_guides = json.add_array("guides");
|
||||
auto json_guides = MUST(json.add_array("guides"));
|
||||
for (const auto& guide : m_guides) {
|
||||
auto json_guide = json_guides.add_object();
|
||||
json_guide.add("offset"sv, (double)guide.offset());
|
||||
auto json_guide = MUST(json_guides.add_object());
|
||||
MUST(json_guide.add("offset"sv, (double)guide.offset()));
|
||||
if (guide.orientation() == Guide::Orientation::Vertical)
|
||||
json_guide.add("orientation", "vertical");
|
||||
MUST(json_guide.add("orientation", "vertical"));
|
||||
else if (guide.orientation() == Guide::Orientation::Horizontal)
|
||||
json_guide.add("orientation", "horizontal");
|
||||
json_guide.finish();
|
||||
MUST(json_guide.add("orientation", "horizontal"));
|
||||
MUST(json_guide.finish());
|
||||
}
|
||||
json_guides.finish();
|
||||
json.finish();
|
||||
MUST(json_guides.finish());
|
||||
MUST(json.finish());
|
||||
|
||||
if (!file.write(builder.string_view()))
|
||||
return String { file.error_string() };
|
||||
|
|
|
@ -1185,10 +1185,10 @@ void Document::set_cookie(String const& cookie_string, Cookie::Source source)
|
|||
String Document::dump_dom_tree_as_json() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
JsonObjectSerializer json(builder);
|
||||
auto json = MUST(JsonObjectSerializer<>::try_create(builder));
|
||||
serialize_tree_as_json(json);
|
||||
|
||||
json.finish();
|
||||
MUST(json.finish());
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
|
|
|
@ -723,47 +723,52 @@ bool Node::is_uninteresting_whitespace_node() const
|
|||
|
||||
void Node::serialize_tree_as_json(JsonObjectSerializer<StringBuilder>& object) const
|
||||
{
|
||||
object.add("name", node_name().view());
|
||||
object.add("id", id());
|
||||
MUST(object.add("name", node_name().view()));
|
||||
MUST(object.add("id", id()));
|
||||
if (is_document()) {
|
||||
object.add("type", "document");
|
||||
MUST(object.add("type", "document"));
|
||||
} else if (is_element()) {
|
||||
object.add("type", "element");
|
||||
MUST(object.add("type", "element"));
|
||||
|
||||
auto const* element = static_cast<DOM::Element const*>(this);
|
||||
if (element->has_attributes()) {
|
||||
auto attributes = object.add_object("attributes");
|
||||
auto attributes = MUST(object.add_object("attributes"));
|
||||
element->for_each_attribute([&attributes](auto& name, auto& value) {
|
||||
attributes.add(name, value);
|
||||
MUST(attributes.add(name, value));
|
||||
});
|
||||
MUST(attributes.finish());
|
||||
}
|
||||
|
||||
if (element->is_browsing_context_container()) {
|
||||
auto const* container = static_cast<HTML::BrowsingContextContainer const*>(element);
|
||||
if (auto const* content_document = container->content_document()) {
|
||||
auto children = object.add_array("children");
|
||||
JsonObjectSerializer<StringBuilder> content_document_object = children.add_object();
|
||||
auto children = MUST(object.add_array("children"));
|
||||
JsonObjectSerializer<StringBuilder> content_document_object = MUST(children.add_object());
|
||||
content_document->serialize_tree_as_json(content_document_object);
|
||||
MUST(content_document_object.finish());
|
||||
MUST(children.finish());
|
||||
}
|
||||
}
|
||||
} else if (is_text()) {
|
||||
object.add("type", "text");
|
||||
MUST(object.add("type", "text"));
|
||||
|
||||
auto text_node = static_cast<DOM::Text const*>(this);
|
||||
object.add("text", text_node->data());
|
||||
MUST(object.add("text", text_node->data()));
|
||||
} else if (is_comment()) {
|
||||
object.add("type"sv, "comment"sv);
|
||||
object.add("data"sv, static_cast<DOM::Comment const&>(*this).data());
|
||||
MUST(object.add("type"sv, "comment"sv));
|
||||
MUST(object.add("data"sv, static_cast<DOM::Comment const&>(*this).data()));
|
||||
}
|
||||
|
||||
if (has_child_nodes()) {
|
||||
auto children = object.add_array("children");
|
||||
auto children = MUST(object.add_array("children"));
|
||||
for_each_child([&children](DOM::Node& child) {
|
||||
if (child.is_uninteresting_whitespace_node())
|
||||
return;
|
||||
JsonObjectSerializer<StringBuilder> child_object = children.add_object();
|
||||
JsonObjectSerializer<StringBuilder> child_object = MUST(children.add_object());
|
||||
child.serialize_tree_as_json(child_object);
|
||||
MUST(child_object.finish());
|
||||
});
|
||||
MUST(children.finish());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,23 +45,23 @@ void Handler::from_executable(Type handler_type, const String& executable)
|
|||
String Handler::to_details_str() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
JsonObjectSerializer obj { builder };
|
||||
obj.add("executable", executable);
|
||||
obj.add("name", name);
|
||||
auto obj = MUST(JsonObjectSerializer<>::try_create(builder));
|
||||
MUST(obj.add("executable", executable));
|
||||
MUST(obj.add("name", name));
|
||||
switch (handler_type) {
|
||||
case Type::Application:
|
||||
obj.add("type", "app");
|
||||
MUST(obj.add("type", "app"));
|
||||
break;
|
||||
case Type::UserDefault:
|
||||
obj.add("type", "userdefault");
|
||||
MUST(obj.add("type", "userdefault"));
|
||||
break;
|
||||
case Type::UserPreferred:
|
||||
obj.add("type", "userpreferred");
|
||||
MUST(obj.add("type", "userpreferred"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
obj.finish();
|
||||
MUST(obj.finish());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -271,18 +271,18 @@ Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect
|
|||
auto serialize_json = [](Web::CSS::StyleProperties const& properties) -> String {
|
||||
StringBuilder builder;
|
||||
|
||||
JsonObjectSerializer serializer(builder);
|
||||
auto serializer = MUST(JsonObjectSerializer<>::try_create(builder));
|
||||
properties.for_each_property([&](auto property_id, auto& value) {
|
||||
serializer.add(Web::CSS::string_from_property_id(property_id), value.to_string());
|
||||
MUST(serializer.add(Web::CSS::string_from_property_id(property_id), value.to_string()));
|
||||
});
|
||||
serializer.finish();
|
||||
MUST(serializer.finish());
|
||||
|
||||
return builder.to_string();
|
||||
};
|
||||
|
||||
auto serialize_custom_properties_json = [](Web::DOM::Element const& element) -> String {
|
||||
StringBuilder builder;
|
||||
JsonObjectSerializer serializer(builder);
|
||||
auto serializer = MUST(JsonObjectSerializer<>::try_create(builder));
|
||||
HashTable<String> seen_properties;
|
||||
|
||||
auto const* element_to_check = &element;
|
||||
|
@ -290,14 +290,14 @@ Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect
|
|||
for (auto const& property : element_to_check->custom_properties()) {
|
||||
if (!seen_properties.contains(property.key)) {
|
||||
seen_properties.set(property.key);
|
||||
serializer.add(property.key, property.value.value->to_string());
|
||||
MUST(serializer.add(property.key, property.value.value->to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
element_to_check = element_to_check->parent_element();
|
||||
}
|
||||
|
||||
serializer.finish();
|
||||
MUST(serializer.finish());
|
||||
|
||||
return builder.to_string();
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue