int http_router_bind(struct http_router *router, const char *path_string, enum http_method method, http_route_cb cb, void *cb_arg) { struct http_route *route; struct http_path *path; path = http_path_parse(path_string); if (!path) { c_set_error("invalid path: %s", c_get_error()); return -1; } route = http_route_new(); route->path_string = c_strdup(path_string); route->path = path; route->method = method; route->cb = cb; route->cb_arg = cb_arg; c_ptr_vector_append(router->routes, route); http_router_sort_routes(router); return 0; }
int http_route_base_find_route(struct http_route_base *base, enum http_method method, const char *path, const struct http_route **proute, enum http_route_match_result *p_match_result, struct http_named_parameter **p_named_parameters, size_t *p_nb_named_parameters) { struct http_route *route; struct http_named_parameter *named_parameters; size_t nb_named_parameters; enum http_route_match_result match_result; char **path_components; size_t nb_path_components, idx; if (!base->sorted) http_route_base_sort_routes(base); if (*path != '/') { *proute = NULL; *p_match_result = HTTP_ROUTE_MATCH_WRONG_PATH; return 0; } if (http_path_parse(path, &path_components, &nb_path_components) == -1) return -1; route = NULL; match_result = HTTP_ROUTE_MATCH_PATH_NOT_FOUND; for (size_t i = 0; i < base->nb_routes; i++) { enum http_route_match_result result; if (http_route_matches_request(base->routes[i], method, path_components, nb_path_components, &result)) { route = base->routes[i]; match_result = HTTP_ROUTE_MATCH_OK; break; } if (result == HTTP_ROUTE_MATCH_METHOD_NOT_FOUND) { match_result = HTTP_ROUTE_MATCH_METHOD_NOT_FOUND; } else if (result == HTTP_ROUTE_MATCH_PATH_NOT_FOUND && match_result != HTTP_ROUTE_MATCH_METHOD_NOT_FOUND) { match_result = HTTP_ROUTE_MATCH_PATH_NOT_FOUND; } } if (!route) { *proute = NULL; *p_match_result = match_result; http_path_free(path_components, nb_path_components); return 0; } if (route->nb_components != nb_path_components) { /* We made a mistake somewhere, it should not happen */ http_set_error("route/path size mismatch"); return -1; } /* Copy named parameters */ nb_named_parameters = 0; for (size_t i = 0; i < route->nb_components; i++) { if (route->components[i].type == HTTP_ROUTE_COMPONENT_NAMED) nb_named_parameters++; } if (p_named_parameters && nb_named_parameters > 0) { named_parameters = http_calloc(nb_named_parameters, sizeof(struct http_named_parameter)); idx = 0; for (size_t i = 0; i < route->nb_components; i++) { struct http_route_component *component; component = route->components + i; if (component->type != HTTP_ROUTE_COMPONENT_NAMED) continue; named_parameters[idx].name = http_strdup(component->value); named_parameters[idx].value = http_strdup(path_components[i]); idx++; } } else { named_parameters = NULL; } http_path_free(path_components, nb_path_components); *proute = route; *p_match_result = match_result; if (p_named_parameters) *p_named_parameters = named_parameters; if (p_nb_named_parameters) *p_nb_named_parameters = nb_named_parameters; return 0; }