Esempio n. 1
0
File: node.c Progetto: RickySu/r3
/**
 * Helper function for creating routes from request URI path and request method
 *
 * method (int): METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE ...
 */
route * r3_tree_insert_routel_ex(node *tree, int method, const char *path, int path_len, void *data, char **errstr) {
    route *r = r3_route_createl(path, path_len);
    CHECK_PTR(r);
    r->request_method = method; // ALLOW GET OR POST METHOD
    node * ret = r3_tree_insert_pathl_ex(tree, path, path_len, r, data, errstr);
    if (!ret) {
        // failed insert
        r3_route_free(r);
        return NULL;
    }
    return r;
}
Esempio n. 2
0
END_TEST



START_TEST (test_insert_pathl_fail)
{
    node * n = r3_tree_create(10);

    node * ret;

    char *errstr = NULL;
    ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"),  NULL, NULL, &errstr);
    ck_assert(ret == NULL);
    ck_assert(errstr != NULL);
    printf("%s\n", errstr); // Returns Incomplete slug pattern. PATTERN (16): '/foo/{name:\d{5}', OFFSET: 16, STATE: 1
    SAFE_FREE(errstr);

    errstr = NULL;
    r3_tree_compile(n, &errstr);
    ck_assert(errstr == NULL);

    r3_tree_free(n);
}
Esempio n. 3
0
File: node.c Progetto: RickySu/r3
/**
 * Return the last inserted node.
 */
node * r3_tree_insert_pathl_ex(node *tree, const char *path, int path_len, route * route, void * data, char **errstr)
{
    node * n = tree;

    // common edge
    edge * e = NULL;

    // If there is no path to insert at the node, we just increase the mount
    // point on the node and append the route.
    if (path_len == 0) {
        tree->endpoint++;
        if (route) {
            route->data = data;
            r3_node_append_route(tree, route);
        }
        return tree;
    }

    /* length of common prefix */
    int prefix_len = 0;
    char *err = NULL;
    e = r3_node_find_common_prefix(tree, path, path_len, &prefix_len, &err);
    if (err) {
        // copy the error message pointer
        if (errstr) *errstr = err;
        return NULL;
    }

    const char * subpath = path + prefix_len;
    const int    subpath_len = path_len - prefix_len;

    // common prefix not found, insert a new edge for this pattern
    if ( prefix_len == 0 ) {
        // there are two more slugs, we should break them into several parts
        int slug_cnt = r3_slug_count(path, path_len, errstr);
        if (slug_cnt == -1) {
            return NULL;
        }

        if ( slug_cnt > 1 ) {
            int   slug_len;
            char *p = r3_slug_find_placeholder(path, &slug_len);

#ifdef DEBUG
            assert(p);
#endif

            // find the next one '{', then break there
            if(p) {
                p = r3_slug_find_placeholder(p + slug_len + 1, NULL);
            }
#ifdef DEBUG
            assert(p);
#endif

            // insert the first one edge, and break at "p"
            node * child = r3_tree_create(3);
            CHECK_PTR(child);

            r3_node_connect(n, zstrndup(path, (int)(p - path)), child);

            // and insert the rest part to the child
            return r3_tree_insert_pathl_ex(child, p, path_len - (int)(p - path),  route, data, errstr);

        } else {
            if (slug_cnt == 1) {
                // there is one slug, let's see if it's optimiz-able by opcode
                int   slug_len = 0;
                char *slug_p = r3_slug_find_placeholder(path, &slug_len);
                int   slug_pattern_len = 0;
                char *slug_pattern = r3_slug_find_pattern(slug_p, &slug_pattern_len);

                int opcode = 0;
                // if there is a pattern defined.
                if (slug_pattern_len) {
                    char *cpattern = r3_slug_compile(slug_pattern, slug_pattern_len);
                    opcode = r3_pattern_to_opcode(cpattern, strlen(cpattern));
                    zfree(cpattern);
                } else {
                    opcode = OP_EXPECT_NOSLASH;
                }


                // if the slug starts after one+ charactor, for example foo{slug}
                node *c1;
                if (slug_p > path) {
                    c1 = r3_tree_create(3);
                    CHECK_PTR(c1);
                    r3_node_connectl(n, path, slug_p - path, 1, c1); // duplicate
                } else {
                    c1 = n;
                }

                node * c2 = r3_tree_create(3);
                CHECK_PTR(c2);

                edge * op_edge = r3_node_connectl(c1, slug_p, slug_len , 1, c2);
                if(opcode) {
                    op_edge->opcode = opcode;
                }

                int restlen = path_len - ((slug_p - path) + slug_len);

                if (restlen) {
                    return r3_tree_insert_pathl_ex(c2, slug_p + slug_len, restlen, route, data, errstr);
                }

                c2->data = data;
                c2->endpoint++;
                if (route) {
                    route->data = data;
                    r3_node_append_route(c2, route);
                }
                return c2;
            }
            // only one slug
            node * child = r3_tree_create(3);
            CHECK_PTR(child);
            child->endpoint++;
            if (data)
                child->data = data;

            r3_node_connectl(n, path, path_len, 1, child);
            if (route) {
                route->data = data;
                r3_node_append_route(child, route);
            }
            return child;
        }
    } else if ( prefix_len == e->pattern_len ) {    // fully-equal to the pattern of the edge

        // there are something more we can insert
        if ( subpath_len > 0 ) {
            return r3_tree_insert_pathl_ex(e->child, subpath, subpath_len, route, data, errstr);
        } else {
            // there are no more path to insert

            // see if there is an endpoint already, we should n't overwrite the data on child.
            // but we still need to append the route.

            if (route) {
                route->data = data;
                r3_node_append_route(e->child, route);
                e->child->endpoint++; // make it as an endpoint
                return e->child;
            }

            // insertion without route
            if (e->child->endpoint > 0) {
                // TODO: return an error code instead of NULL
                return NULL;
            }
            e->child->endpoint++; // make it as an endpoint
            e->child->data = data; // set data
            return e->child;
        }

    } else if ( prefix_len < e->pattern_len ) {
        /* it's partially matched with the pattern,
         * we should split the end point and make a branch here...
         */
        r3_edge_branch(e, prefix_len);
        return r3_tree_insert_pathl_ex(e->child, subpath, subpath_len, route , data, errstr);
    } else {
        fprintf(stderr, "unexpected route.");
        return NULL;
    }
    return n;
}