Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 29 additions & 17 deletions src/actions/action_default_v1.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,21 @@

class ActionDefault_v1 : public sourcemeta::one::Action {
public:
ActionDefault_v1(const std::filesystem::path &base,
const sourcemeta::core::URITemplateRouterView &router,
const sourcemeta::core::URITemplateRouter::Identifier)
: sourcemeta::one::Action{base, router.base_path()} {}
ActionDefault_v1(
const std::filesystem::path &base,
const sourcemeta::core::URITemplateRouterView &router,
const sourcemeta::core::URITemplateRouter::Identifier identifier)
: sourcemeta::one::Action{base, router.base_path()} {
// TODO: This implies the API is mounted
this->error_schema_ =
std::string{this->base_path()} + "/self/v1/schemas/api/error";

router.arguments(identifier, [this](const auto &key, const auto &value) {
if (key == "errorSchema") {
this->error_schema_ = std::get<std::string_view>(value);
}
});
}

auto run(const std::span<std::string_view>,
sourcemeta::one::HTTPRequest &request,
Expand All @@ -31,8 +42,7 @@ class ActionDefault_v1 : public sourcemeta::one::Action {
path[this->base_path().size()] != '/')) {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
"There is nothing at this URL",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
"There is nothing at this URL", this->error_schema_);
return;
}

Expand All @@ -48,27 +58,26 @@ class ActionDefault_v1 : public sourcemeta::one::Action {
ActionServeMetapackFile_v1::serve(
this->base() / "explorer" / "%" / "directory-html.metapack",
sourcemeta::one::STATUS_OK, false, {}, {}, request, response,
this->base_path());
this->error_schema_);
return;
} else if (request.method() == "get" || request.method() == "head") {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
"There is nothing at this URL",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
"There is nothing at this URL", this->error_schema_);
return;
} else {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED,
"method-not-allowed", "This HTTP method is invalid for this URL",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
this->error_schema_);
return;
}
}

if (path.ends_with(".json")) {
ActionJSONSchemaServe_v1::serve(this->base(),
path.substr(0, path.size() - 5), request,
response, this->base_path());
response, this->error_schema_);
return;
}

Expand All @@ -80,31 +89,34 @@ class ActionDefault_v1 : public sourcemeta::one::Action {
ActionServeMetapackFile_v1::serve(
explorer_path / "schema-html.metapack",
sourcemeta::one::STATUS_OK, false, {}, {}, request, response,
this->base_path());
this->error_schema_);
} else {
explorer_path /= "directory-html.metapack";
if (std::filesystem::exists(explorer_path)) {
ActionServeMetapackFile_v1::serve(
explorer_path, sourcemeta::one::STATUS_OK, false, {}, {},
request, response, this->base_path());
request, response, this->error_schema_);
} else {
ActionServeMetapackFile_v1::serve(
this->base() / "explorer" / "%" / "404.metapack",
sourcemeta::one::STATUS_NOT_FOUND, false, {}, {}, request,
response, this->base_path());
response, this->error_schema_);
}
}
} else {
ActionJSONSchemaServe_v1::serve(this->base(), path, request, response,
this->base_path());
this->error_schema_);
}
} else {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
"There is nothing at this URL",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
"There is nothing at this URL", this->error_schema_);
}
}

private:
// TODO: This should be a string view
std::string error_schema_;
};

#endif
20 changes: 15 additions & 5 deletions src/actions/action_health_check_v1.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,17 @@

class ActionHealthCheck_v1 : public sourcemeta::one::Action {
public:
ActionHealthCheck_v1(const std::filesystem::path &base,
const sourcemeta::core::URITemplateRouterView &router,
const sourcemeta::core::URITemplateRouter::Identifier)
: sourcemeta::one::Action{base, router.base_path()} {}
ActionHealthCheck_v1(
const std::filesystem::path &base,
const sourcemeta::core::URITemplateRouterView &router,
const sourcemeta::core::URITemplateRouter::Identifier identifier)
: sourcemeta::one::Action{base, router.base_path()} {
router.arguments(identifier, [this](const auto &key, const auto &value) {
if (key == "errorSchema") {
this->error_schema_ = std::get<std::string_view>(value);
}
});
}

auto run(const std::span<std::string_view>,
sourcemeta::one::HTTPRequest &request,
Expand All @@ -25,7 +32,7 @@ class ActionHealthCheck_v1 : public sourcemeta::one::Action {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED,
"method-not-allowed", "This HTTP method is invalid for this URL",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
this->error_schema_);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

src/actions/action_health_check_v1.h:35: error_schema_ is never defaulted, so if errorSchema isn't present in the route arguments (for example, an older routes.bin), json_error will emit an invalid Link: <>; rel="describedby" header. Consider ensuring a non-empty default (like the prior base_path()+"/self/v1/schemas/api/error") or validating before calling json_error.

Severity: medium

Other Locations
  • src/actions/action_not_found_v1.h:33
  • src/actions/action_schema_search_v1.h:45
  • src/actions/action_serve_static_v1.h:39
  • src/actions/action_jsonschema_serve_v1.h:85
  • src/actions/action_serve_schema_artifact_v1.h:41

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

return;
}

Expand All @@ -34,6 +41,9 @@ class ActionHealthCheck_v1 : public sourcemeta::one::Action {
sourcemeta::one::send_response(sourcemeta::one::STATUS_OK, request,
response);
}

private:
std::string_view error_schema_;
};

#endif
35 changes: 14 additions & 21 deletions src/actions/action_jsonschema_evaluate_v1.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
router.arguments(identifier, [this](const auto &key, const auto &value) {
if (key == "mode") {
this->mode_ = static_cast<EvaluateMode>(std::get<std::int64_t>(value));
} else if (key == "responseSchema") {
this->response_schema_ = std::get<std::string_view>(value);
} else if (key == "errorSchema") {
this->error_schema_ = std::get<std::string_view>(value);
}
});
}
Expand Down Expand Up @@ -64,12 +68,11 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED,
"no-template",
"This schema was not precompiled for schema evaluation",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
this->error_schema_);
} else {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
"There is nothing at this URL",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
"There is nothing at this URL", this->error_schema_);
}

return;
Expand All @@ -92,16 +95,14 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
sourcemeta::one::json_error(
callback_request, callback_response,
sourcemeta::one::STATUS_INTERNAL_SERVER_ERROR,
"uncaught-error", exception.what(),
std::string{this->base_path()} +
"/self/v1/schemas/api/error");
"uncaught-error", exception.what(), this->error_schema_);
}
});
} else {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED,
"method-not-allowed", "This HTTP method is invalid for this URL",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
this->error_schema_);
}
}

Expand Down Expand Up @@ -314,15 +315,14 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_PAYLOAD_TOO_LARGE,
"payload-too-large", "The request body is too large",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
this->error_schema_);
return;
}

if (body.empty()) {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_BAD_REQUEST, "no-instance",
"You must pass an instance to validate against",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
"You must pass an instance to validate against", this->error_schema_);
return;
}

Expand All @@ -331,15 +331,7 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
response.write_status(sourcemeta::one::STATUS_OK);
response.write_header("Content-Type", "application/json");
response.write_header("Access-Control-Allow-Origin", "*");
if (mode == EvaluateMode::Trace) {
sourcemeta::one::write_link_header(
response, std::string{this->base_path()} +
"/self/v1/schemas/api/schemas/trace/response");
} else {
sourcemeta::one::write_link_header(
response, std::string{this->base_path()} +
"/self/v1/schemas/api/schemas/evaluate/response");
}
sourcemeta::one::write_link_header(response, this->response_schema_);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

src/actions/action_jsonschema_evaluate_v1.h:334: write_link_header is now driven by response_schema_ from route arguments; if that argument is missing/empty, the response will include an invalid Link header and lose the previous mode-based schema selection. Consider ensuring responseSchema is always populated for both evaluate/trace routes (or falling back based on mode_).

Severity: medium

Other Locations
  • src/actions/action_schema_search_v1.h:143
  • src/actions/action_serve_explorer_artifact_v1.h:44
  • src/actions/action_serve_schema_artifact_v1.h:48

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.


std::ostringstream payload;
sourcemeta::core::prettify(result, payload);
Expand All @@ -349,12 +341,13 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
} catch (const std::exception &exception) {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_INTERNAL_SERVER_ERROR,
"evaluation-error", exception.what(),
std::string{this->base_path()} + "/self/v1/schemas/api/error");
"evaluation-error", exception.what(), this->error_schema_);
}
}

EvaluateMode mode_{EvaluateMode::Standard};
std::string_view response_schema_;
std::string_view error_schema_;
};

#endif
25 changes: 17 additions & 8 deletions src/actions/action_jsonschema_serve_v1.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@ class ActionJSONSchemaServe_v1 : public sourcemeta::one::Action {
ActionJSONSchemaServe_v1(
const std::filesystem::path &base,
const sourcemeta::core::URITemplateRouterView &router,
const sourcemeta::core::URITemplateRouter::Identifier)
: sourcemeta::one::Action{base, router.base_path()} {}
const sourcemeta::core::URITemplateRouter::Identifier identifier)
: sourcemeta::one::Action{base, router.base_path()} {
router.arguments(identifier, [this](const auto &key, const auto &value) {
if (key == "errorSchema") {
this->error_schema_ = std::get<std::string_view>(value);
}
});
}

static auto serve(const std::filesystem::path &base,
std::string_view schema_path,
sourcemeta::one::HTTPRequest &request,
sourcemeta::one::HTTPResponse &response,
std::string_view base_path = {}) -> void {
std::string_view error_schema) -> void {
// Otherwise we may get unexpected results in case-sensitive file-systems
std::string lowercase_path{schema_path};
std::ranges::transform(
Expand Down Expand Up @@ -56,28 +62,31 @@ class ActionJSONSchemaServe_v1 : public sourcemeta::one::Action {
!std::filesystem::exists(absolute_path)) {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
"There is nothing at this URL",
std::string{base_path} + "/self/v1/schemas/api/error");
"There is nothing at this URL", error_schema);
return;
}

if (is_deno) {
// For HTTP imports, as Deno won't like the `application/schema+json` one
ActionServeMetapackFile_v1::serve(
absolute_path, sourcemeta::one::STATUS_OK, true, "application/json",
{}, request, response, base_path);
{}, request, response, error_schema);
} else {
ActionServeMetapackFile_v1::serve(absolute_path,
sourcemeta::one::STATUS_OK, true, {},
{}, request, response, base_path);
{}, request, response, error_schema);
}
}

auto run(const std::span<std::string_view> matches,
sourcemeta::one::HTTPRequest &request,
sourcemeta::one::HTTPResponse &response) -> void override {
serve(this->base(), matches.front(), request, response, this->base_path());
serve(this->base(), matches.front(), request, response,
this->error_schema_);
}

private:
std::string_view error_schema_;
};

#endif
21 changes: 15 additions & 6 deletions src/actions/action_not_found_v1.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,28 @@

class ActionNotFound_v1 : public sourcemeta::one::Action {
public:
ActionNotFound_v1(const std::filesystem::path &base,
const sourcemeta::core::URITemplateRouterView &router,
const sourcemeta::core::URITemplateRouter::Identifier)
: sourcemeta::one::Action{base, router.base_path()} {}
ActionNotFound_v1(
const std::filesystem::path &base,
const sourcemeta::core::URITemplateRouterView &router,
const sourcemeta::core::URITemplateRouter::Identifier identifier)
: sourcemeta::one::Action{base, router.base_path()} {
router.arguments(identifier, [this](const auto &key, const auto &value) {
if (key == "errorSchema") {
this->error_schema_ = std::get<std::string_view>(value);
}
});
}

auto run(const std::span<std::string_view>,
sourcemeta::one::HTTPRequest &request,
sourcemeta::one::HTTPResponse &response) -> void override {
sourcemeta::one::json_error(
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
"There is nothing at this URL",
std::string{this->base_path()} + "/self/v1/schemas/api/error");
"There is nothing at this URL", this->error_schema_);
}

private:
std::string_view error_schema_;
};

#endif
Loading
Loading