45 if (artifact_dir == NULL || artifact_dir[0] ==
'\0') {
49 fixtures_dir =
path_join(artifact_dir,
"fixtures");
50 if (fixtures_dir == NULL) {
53 result =
path_join(fixtures_dir,
"route-fixture.json");
70 char *filename = NULL;
74 if (artifact_dir == NULL || app_id == NULL || app_id[0] ==
'\0') {
78 dir =
path_join(artifact_dir,
"data/framework");
84 filename_len = strlen(
"framework-") + strlen(app_id) + strlen(
"-route-fixture-v1.json") + 1;
85 filename = (
char *)malloc(filename_len);
86 if (filename == NULL) {
90 snprintf(filename, filename_len,
"framework-%s-route-fixture-v1.json", app_id);
99 char *manifest_path = NULL;
100 char *manifest_text = NULL;
101 char *route_fixture = NULL;
102 char *app_root = NULL;
104 if (artifact_dir == NULL) {
109 manifest_path =
path_join(artifact_dir,
"pharos.app.json");
110 if (manifest_path == NULL || !
path_exists(manifest_path)) {
118 if (manifest_text != NULL) {
126 if (fixtures != NULL) {
129 if (route_fixture == NULL) {
137 if (route_fixture != NULL) {
140 if (route_fixture[0] !=
'/') {
141 resolved =
path_join(artifact_dir, route_fixture);
143 resolved = route_fixture;
144 route_fixture = NULL;
160 if (packaged_route_fixture != NULL &&
path_exists(packaged_route_fixture)) {
161 return packaged_route_fixture;
163 free(packaged_route_fixture);
172 if (framework_route_fixture != NULL &&
path_exists(framework_route_fixture)) {
173 return framework_route_fixture;
175 free(framework_route_fixture);
192 if (path == NULL || path[0] ==
'\0') {
197 if (*cursor ==
'/') {
200 while (*cursor !=
'\0') {
202 while (*cursor !=
'\0' && *cursor !=
'/') {
205 if (*cursor ==
'/') {
221 if (path == NULL || path[0] ==
'\0') {
226 if (*cursor ==
'/') {
230 while (*cursor !=
'\0' && current < index) {
231 while (*cursor !=
'\0' && *cursor !=
'/') {
234 if (*cursor ==
'/') {
240 if (current != index || *cursor ==
'\0') {
250 const char *end = start;
251 while (*end !=
'\0' && *end !=
'/') {
254 return (
size_t)(end - start);
270 int segment_count = 0;
274 if (pattern == NULL) {
279 for (index = 0; index < segment_count; index++) {
281 size_t segment_len = 0;
282 if (segment == NULL) {
287 if (segment_len == 1 && segment[0] ==
'*') {
290 if (segment_len > 0 && segment[0] ==
':') {
312 if (pattern == NULL || path == NULL) {
319 if (pat_segs != path_segs) {
323 for (i = 0; i < pat_segs; i++) {
329 if (pat_seg == NULL || path_seg == NULL) {
337 if (pat_len > 0 && pat_seg[0] ==
':') {
345 if (pat_len == 1 && pat_seg[0] ==
'*') {
350 if (pat_len != path_len) {
353 if (strncmp(pat_seg, path_seg, pat_len) != 0) {
366 const char *route_fixture_path,
376 const char *preferred_kind = NULL;
378 int fallback_score = -1;
382 if (match_out != NULL) {
386 if (route_fixture_path == NULL || path == NULL || match_out == NULL) {
390 if (method != NULL) {
391 if (strcmp(method,
"GET") == 0 || strcmp(method,
"HEAD") == 0 || strcmp(method,
"OPTIONS") == 0) {
392 preferred_kind =
"page";
393 }
else if (strcmp(method,
"POST") == 0 || strcmp(method,
"PUT") == 0 || strcmp(method,
"PATCH") == 0 || strcmp(method,
"DELETE") == 0) {
394 preferred_kind =
"action";
405 if (routes == NULL) {
411 for (i = 0; i < route_count; i++) {
413 char *route_path = NULL;
414 const char *route_id = NULL;
415 const char *kind = NULL;
424 if (route_path == NULL) {
444 match->
route_id = strdup(route_id != NULL ? route_id :
"");
445 match->
path = route_path;
446 match->
kind = strdup(kind != NULL ? kind :
"page");
455 if (preferred_kind == NULL || (kind != NULL && strcmp(kind, preferred_kind) == 0)) {
456 if (best_match == NULL || score > best_score) {
466 if (fallback_match == NULL || score > fallback_score) {
468 fallback_match = match;
469 fallback_score = score;
476 if (best_match != NULL) {
478 *match_out = best_match;
481 if (fallback_match != NULL) {
482 *match_out = fallback_match;
504 const char *artifact_dir,
521 const char *param_name
526 char param_marker[256];
528 if (pattern == NULL || path == NULL || param_name == NULL) {
533 if (snprintf(param_marker,
sizeof(param_marker),
":%s", param_name) >= (
int)
sizeof(param_marker)) {
540 if (pat_segs != path_segs) {
544 for (i = 0; i < pat_segs; i++) {
550 if (pat_seg == NULL || path_seg == NULL) {
557 if (pat_len > 0 && strncmp(pat_seg, param_marker, pat_len) == 0 && pat_len == strlen(param_marker)) {
char * native_dispatch_response_file_for_request(const char *root, const char *method, const char *path)
Resolves the response artifact file for one request using the dispatch table.
Declares dispatch-table request path helpers.
static int pattern_matches(const char *pattern, const char *path)
Tests whether a pattern matches a concrete path.
static const char * get_segment(const char *path, int index)
Extracts the N-th segment (0-indexed) from a path.
static int route_pattern_specificity_score(const char *pattern)
Scores a route pattern by match specificity.
static char * construct_direct_route_fixture_path(const char *artifact_dir, const char *app_id)
Builds the framework-data route fixture fallback path.
char * native_dynamic_dispatch_response_file(const char *artifact_dir, const char *method, const char *path)
Resolves the response artifact file for a matched page route.
int native_dynamic_dispatch_match(const char *route_fixture_path, const char *method, const char *path, NativeDynamicRouteMatch **match_out)
Matches a request path against the route fixture for an app.
static char * construct_packaged_route_fixture_path(const char *artifact_dir)
Attempts to locate the route fixture path from the artifact directory.
static size_t segment_length(const char *start)
Returns the length of a segment starting at start.
static char * resolve_route_fixture_path(const char *artifact_dir, const char *app_id)
char * native_dynamic_dispatch_resolve_route_fixture(const char *artifact_dir, const char *app_id)
Resolves the route fixture path from the artifact directory.
char * native_dynamic_dispatch_extract_param(const char *pattern, const char *path, const char *param_name)
Returns the URL path parameter value extracted from a matched route.
static int count_segments(const char *path)
Counts the number of path segments in a pattern or path.
void native_dynamic_dispatch_free_match(NativeDynamicRouteMatch *match)
Frees a route match returned by native_dynamic_dispatch_match().
Route dispatch for in-process dynamic-app request handling.
char * path_join(const char *left, const char *right)
Joins two path segments using the native path separator.
char * dup_range(const char *start, size_t len)
Duplicates a byte range into a newly allocated NUL-terminated string.
char * read_file_text(const char *path)
Reads an entire file into a newly allocated text buffer.
int path_exists(const char *path)
Tests whether a filesystem path currently exists.
Declares shared low-level support helpers used across the Pharos native runtime.
yyjson_doc * native_json_doc_load_file(const char *path)
Parses a JSON file into an owned yyjson document.
void native_json_doc_free(yyjson_doc *doc)
Releases a document returned by the native yyjson helpers.
yyjson_doc * native_json_doc_load_text(const char *text)
Parses JSON text into an owned yyjson document.
char * native_json_obj_get_string_dup(yyjson_val *obj, const char *key)
Duplicates a string-valued key from a JSON object.
yyjson_val * native_json_obj_get_array(yyjson_val *obj, const char *key)
Looks up an array-valued key from a JSON object value.
yyjson_val * native_json_obj_get(yyjson_val *obj, const char *key)
Looks up a key from a JSON object value.
Declares shared helper wrappers around vendored yyjson parsing and serialization APIs.
Describes one matched route from the route fixture.
yyjson_api_inline yyjson_val * yyjson_arr_get(const yyjson_val *arr, size_t idx)
yyjson_api_inline yyjson_val * yyjson_doc_get_root(const yyjson_doc *doc)
yyjson_api_inline size_t yyjson_arr_size(const yyjson_val *arr)
yyjson_api_inline const char * yyjson_get_str(const yyjson_val *val)