/**
* 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;
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;
}