/** * call-seq: * uc.resolve("/someuri") -> "/someuri", "", handler * uc.resolve("/someuri/pathinfo") -> "/someuri", "/pathinfo", handler * uc.resolve("/notfound/orhere") -> nil, nil, nil * uc.resolve("/") -> "/", "/", handler # if uc.register("/", handler) * uc.resolve("/path/from/root") -> "/", "/path/from/root", handler # if uc.register("/", handler) * * Attempts to resolve either the whole URI or at the longest prefix, returning * the prefix (as script_info), path (as path_info), and registered handler * (usually an HttpHandler). If it doesn't find a handler registered at the longest * match then it returns nil,nil,nil. * * Because the resolver uses a trie you are able to register a handler at *any* character * in the URI and it will be handled as long as it's the longest prefix. So, if you * registered handler #1 at "/something/lik", and #2 at "/something/like/that", then a * a search for "/something/like" would give you #1. A search for "/something/like/that/too" * would give you #2. * * This is very powerful since it means you can also attach handlers to parts of the ; * (semi-colon) separated path params, any part of the path, use off chars, anything really. * It also means that it's very efficient to do this only taking as long as the URI has * characters. * * A slight modification to the CGI 1.2 standard is given for handlers registered to "/". * CGI expects all CGI scripts to be at some script path, so it doesn't really say anything * about a script that handles the root. To make this work, the resolver will detect that * the requested handler is at "/", and return that for script_name, and then simply return * the full URI back as path_info. * * It expects strings with no embedded '\0' characters. Don't try other string-like stuff yet. */ VALUE URIClassifier_resolve(VALUE self, VALUE uri) { void *handler = NULL; int pref_len = 0; struct tst *tst = NULL; VALUE result; unsigned char *uri_str = NULL; unsigned char *script_name_str = NULL; DATA_GET(self, struct tst, tst); uri_str = (unsigned char *)StringValueCStr(uri); handler = tst_search(uri_str, tst, &pref_len); // setup for multiple return values result = rb_ary_new(); if(handler) { rb_ary_push(result, rb_str_substr (uri, 0, pref_len)); // compensate for a script_name="/" where we need to add the "/" to path_info to keep it consistent if(pref_len == 1 && uri_str[0] == '/') { // matches the root URI so we have to use the whole URI as the path_info rb_ary_push(result, uri); } else { // matches a script so process like normal rb_ary_push(result, rb_str_substr(uri, pref_len, RSTRING(uri)->len)); } rb_ary_push(result, (VALUE)handler); } else { // not found so push back nothing rb_ary_push(result, Qnil); rb_ary_push(result, Qnil); rb_ary_push(result, Qnil); } return result; }