diff --git a/doc/ns_info.n b/doc/ns_info.n index 4d407c9..916c6ae 100644 --- a/doc/ns_info.n +++ b/doc/ns_info.n @@ -88,6 +88,10 @@ Returns the server boot time in seconds. .RS Returns the configuration file name. .RE +\fBns_info filters\fR +.RS +Returns a list of registered filters added through ns_register_filter or Ns_RegisterFilter(). +.RE \fBns_info home\fR .RS Returns the directory where the AOLserver was installed. @@ -120,6 +124,10 @@ Returns the name of the AOLserver. It's usually "AOLserver." .RS Returns the name of the platform that the server is running on (e.g., Solaris). .RE +\fBns_info procs\fR +.RS +Returns a list of registered procs from maps defined at startup, or added through ns_register_proc or Ns_RegisterRequest(). +.RE \fBns_info\fR server .RS returns the name of this virtual server. diff --git a/include/ns.h b/include/ns.h index f9a92c3..e3e3566 100644 --- a/include/ns.h +++ b/include/ns.h @@ -750,6 +750,7 @@ NS_EXTERN void *Ns_RegisterFilter(char *server, char *method, char *URL, NS_EXTERN void *Ns_RegisterServerTrace(char *server, Ns_TraceProc *proc, void *arg); NS_EXTERN void *Ns_RegisterConnCleanup(char *server, Ns_TraceProc *proc, void *arg); NS_EXTERN void *Ns_RegisterCleanup(Ns_TraceProc *proc, void *arg); +NS_EXTERN void Ns_FilterList(Tcl_DString *dsPtr, char *server); /* * htuu.c @@ -964,6 +965,7 @@ NS_EXTERN void Ns_GetRequest(char *server, char *method, char *url, int *flagsPtr); NS_EXTERN void Ns_UnRegisterRequest(char *server, char *method, char *url, int inherit); +NS_EXTERN int Ns_WalkRequests(char *server, Tcl_DString *dsPtr); NS_EXTERN int Ns_ConnRunRequest(Ns_Conn *conn); NS_EXTERN int Ns_ConnRedirect(Ns_Conn *conn, char *url); @@ -1294,6 +1296,7 @@ NS_EXTERN void Ns_ServerSpecificSet(char *handle, int id, void *data, int flags, void (*deletefunc) (void *)); NS_EXTERN void *Ns_ServerSpecificGet(char *handle, int id); NS_EXTERN void *Ns_ServerSpecificDestroy(char *handle, int id, int flags); +NS_EXTERN int Ns_TrieWalk(int id, int (*callback) (const void *, void *), void *userdata); /* * fd.c: diff --git a/nsd/filter.c b/nsd/filter.c index 4c9f10f..81ee545 100644 --- a/nsd/filter.c +++ b/nsd/filter.c @@ -104,6 +104,47 @@ Ns_RegisterFilter(char *server, char *method, char *url, return (void *) fPtr; } + +/* + *---------------------------------------------------------------------- + * Ns_RegisterFilter -- + * + * Register a filter function to handle a method/URL combination. + * + * Results: + * Returns a pointer to an opaque object that contains the filter + * information. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Ns_FilterList(Tcl_DString *dsPtr, char *server) +{ + NsServer *servPtr = NsGetServer(server); + Filter *fPtr; + + if (servPtr == NULL) { + return; + } + fPtr = servPtr->filter.firstFilterPtr; + while (fPtr != NULL) { + char when[8]; + + Tcl_DStringStartSublist(dsPtr); + sprintf(when, "%d", fPtr->when); + Tcl_DStringAppendElement(dsPtr, when); + Tcl_DStringAppendElement(dsPtr, fPtr->method); + Tcl_DStringAppendElement(dsPtr, fPtr->url); + Ns_GetProcInfo(dsPtr, fPtr->proc, fPtr->arg); + Tcl_DStringEndSublist(dsPtr); + fPtr = fPtr->nextPtr; + } +} + /* *---------------------------------------------------------------------- diff --git a/nsd/info.c b/nsd/info.c index 669fb2d..efa230d 100644 --- a/nsd/info.c +++ b/nsd/info.c @@ -499,19 +499,19 @@ NsTclInfoObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) Tcl_DString ds; static CONST char *opts[] = { "address", "argv0", "boottime", "builddate", "callbacks", - "config", "home", "hostname", "label", "locks", "log", - "major", "minor", "name", "nsd", "pageroot", "patchlevel", - "pid", "platform", "pools", "scheduled", "server", "servers", - "sockcallbacks", "tag", "tcllib", "threads", "uptime", - "version", "winnt", NULL + "config", "filters", "home", "hostname", "label", "locks", + "log", "major", "minor", "name", "nsd", "pageroot", + "patchlevel", "pid", "platform", "pools", "procs", + "scheduled", "server", "servers", "sockcallbacks", "tag", + "tcllib", "threads", "uptime", "version", "winnt", NULL }; enum { IAddressIdx, IArgv0Idx, IBoottimeIdx, IBuilddateIdx, ICallbacksIdx, - IConfigIdx, IHomeIdx, hostINameIdx, ILabelIdx, ILocksIdx, ILogIdx, - IMajorIdx, IMinorIdx, INameIdx, INsdIdx, IPageRootIdx, IPatchLevelIdx, - IPidIdx, IPlatformIdx, IPoolsIdx, IScheduledIdx, IServerIdx, IServersIdx, - sockICallbacksIdx, ITagIdx, ITclLibIdx, IThreadsIdx, IUptimeIdx, - IVersionIdx, IWinntIdx, + IConfigIdx, IFiltersIdx, IHomeIdx, hostINameIdx, ILabelIdx, ILocksIdx, + ILogIdx, IMajorIdx, IMinorIdx, INameIdx, INsdIdx, IPageRootIdx, + IPatchLevelIdx, IPidIdx, IPlatformIdx, IPoolsIdx, IProcsIdx, + IScheduledIdx, IServerIdx, IServersIdx, sockICallbacksIdx, ITagIdx, + ITclLibIdx, IThreadsIdx, IUptimeIdx, IVersionIdx, IWinntIdx, } _nsmayalias opt; if (objc != 2) { @@ -573,6 +573,19 @@ NsTclInfoObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) #endif break; + case IFiltersIdx: + if (NsTclGetServer(itPtr, &server) != TCL_OK) { + return TCL_ERROR; + } + Ns_FilterList(&ds, itPtr->servPtr->server); + Tcl_DStringResult(interp, &ds); + break; + + case IProcsIdx: + (void) Ns_WalkRequests(NULL, &ds); + Tcl_DStringResult(interp, &ds); + break; + case ILogIdx: elog = Ns_InfoErrorLog(); Tcl_SetResult(interp, elog == NULL ? "STDOUT" : elog, TCL_STATIC); diff --git a/nsd/init.c b/nsd/init.c index c09b9c5..35a7e80 100644 --- a/nsd/init.c +++ b/nsd/init.c @@ -106,5 +106,6 @@ Ns_LibInit(void) NsInitSched(); NsInitServers(); NsInitTcl(); + NsInitTclRequests(); } } diff --git a/nsd/nsd.h b/nsd/nsd.h index fc5b3c6..ca9097f 100644 --- a/nsd/nsd.h +++ b/nsd/nsd.h @@ -904,6 +904,7 @@ extern void NsInitSched(void); extern void NsInitServers(void); extern void NsInitTcl(void); extern void NsInitTclCache(void); +extern void NsInitTclRequests(void); extern void NsInitUrlSpace(void); extern void NsInitRequests(void); extern char *NsFindVersion(char *request, unsigned int *majorPtr, @@ -946,6 +947,8 @@ extern Ns_SockProc NsTclSockProc; extern Ns_ArgProc NsTclSockArgProc; extern Ns_ThreadProc NsConnThread; extern Ns_ArgProc NsConnArgProc; +extern Ns_ArgProc NsProcArgProc; +extern Ns_ArgProc NsFilterArgProc; extern void NsGetCallbacks(Tcl_DString *dsPtr); extern void NsGetSockCallbacks(Tcl_DString *dsPtr); diff --git a/nsd/op.c b/nsd/op.c index f933922..b6c2729 100644 --- a/nsd/op.c +++ b/nsd/op.c @@ -50,6 +50,8 @@ typedef struct { int refcnt; Ns_OpProc *proc; Ns_Callback *delete; + char *method; + char *url; void *arg; unsigned int flags; } Req; @@ -59,6 +61,7 @@ typedef struct { */ static void FreeReq(void *arg); +static int RequestWalkCallback(const void *data, void *userdata); /* * Static variables defined in this file. @@ -120,6 +123,8 @@ Ns_RegisterRequest(char *server, char *method, char *url, Ns_OpProc *proc, reqPtr = ns_malloc(sizeof(Req)); reqPtr->proc = proc; reqPtr->delete = delete; + reqPtr->method = ns_strdup(method); + reqPtr->url = ns_strdup(url); reqPtr->arg = arg; reqPtr->flags = flags; reqPtr->refcnt = 1; @@ -195,6 +200,52 @@ Ns_UnRegisterRequest(char *server, char *method, char *url, int inherit) Ns_MutexUnlock(&ulock); } + +/* + *---------------------------------------------------------------------- + * + * Ns_WalkRequests -- + * + * Walk the url space of registered procs. + * + * Results: + * NS_OK, or callback return value if not NS_OK. + * + * Side effects: + * Depends on callback implementation. + * + *---------------------------------------------------------------------- + */ + +int +Ns_WalkRequests(char *server, Tcl_DString *dsPtr) +{ + int result; + + Ns_MutexLock(&ulock); + result = Ns_TrieWalk(uid, RequestWalkCallback, dsPtr); + Ns_MutexUnlock(&ulock); + + return result; +} + +static int +RequestWalkCallback(const void *data, void *userdata) +{ + Req *reqPtr = data; + Tcl_DString *dsPtr = userdata; + + if (reqPtr != NULL) { + Tcl_DStringStartSublist(dsPtr); + Tcl_DStringAppendElement(dsPtr, reqPtr->method); + Tcl_DStringAppendElement(dsPtr, reqPtr->url); + Ns_GetProcInfo(dsPtr, reqPtr->proc, reqPtr->arg); + Tcl_DStringEndSublist(dsPtr); + } + + return NS_OK; +} + /* *---------------------------------------------------------------------- @@ -481,6 +532,8 @@ FreeReq(void *arg) Req *reqPtr = (Req *) arg; if (--reqPtr->refcnt == 0) { + ns_free(reqPtr->method); + ns_free(reqPtr->url); if (reqPtr->delete != NULL) { (*reqPtr->delete) (reqPtr->arg); } diff --git a/nsd/proc.c b/nsd/proc.c index 48e0542..038ceef 100644 --- a/nsd/proc.c +++ b/nsd/proc.c @@ -64,6 +64,8 @@ struct proc { {(void *) NsTclSockProc, "ns:tclsockcallback", NsTclSockArgProc}, {(void *) NsCachePurge, "ns:cachepurge", NsCacheArgProc}, {(void *) NsConnThread, "ns:connthread", NsConnArgProc}, + {(void *) NsAdpProc, "ns:adp", NULL}, + {(void *) Ns_FastPathOp, "ns:fastpath", NULL}, {NULL, NULL, NULL} }; diff --git a/nsd/tclrequest.c b/nsd/tclrequest.c index 82bb98b..8dec683 100644 --- a/nsd/tclrequest.c +++ b/nsd/tclrequest.c @@ -64,6 +64,32 @@ static int RegisterFilterObj(NsInterp *itPtr, int when, int objc, Tcl_Obj *CONST objv[]); static int GetNumArgs(Tcl_Interp *interp, Proc *procPtr); + +/* + *---------------------------------------------------------------------- + * + * NsInitTclRequests -- + * + * Register Ns_OpProcs at startup. + * + * Results: + * None. + * + * Side effects: + * ProcInfo entries registered. + * + *---------------------------------------------------------------------- + */ + +void +NsInitTclRequests(void) +{ + Ns_RegisterProcInfo(ProcRequest, "ns:proc", NsProcArgProc); + Ns_RegisterProcInfo(AdpRequest, "ns:adp", NULL); + Ns_RegisterProcInfo(ProcFilter, "ns:filter", NsProcArgProc); + Ns_RegisterProcInfo(Ns_FastPathOp, "ns:fastpath", NULL); +} + /* *---------------------------------------------------------------------- @@ -708,3 +734,29 @@ FreeProc(void *arg) } ns_free(procPtr); } + + +/* + *---------------------------------------------------------------------- + * + * NsProcArgProc -- + * + * Proc info routine to copy registered proc args. + * + * Results: + * None. + * + * Side effects: + * Will copy script to given dstring. + * + *---------------------------------------------------------------------- + */ + +void +NsProcArgProc(Tcl_DString *dsPtr, void *arg) +{ + Proc *procPtr = arg; + + Tcl_DStringAppendElement(dsPtr, procPtr->name); + Tcl_DStringAppendElement(dsPtr, procPtr->args); +} diff --git a/nsd/urlspace.c b/nsd/urlspace.c index c8b4aee..7298982 100644 --- a/nsd/urlspace.c +++ b/nsd/urlspace.c @@ -161,6 +161,8 @@ static void TrieDestroy(Trie *triePtr); static int TrieBranchTrunc(Trie *triePtr, char *seq, int id); static void *TrieFind(Trie *triePtr, char *seq, int id, int *depthPtr); static void *TrieFindExact(Trie *triePtr, char *seq, int id, int flags); +static int TrieWalk(Trie *triePtr, int id, + int (*callback) (const void *, void *), void *userdata); static void *TrieDelete(Trie *triePtr, char *seq, int id, int flags); /* @@ -186,6 +188,8 @@ static void JunctionBranchTrunc(Junction *juncPtr, char *seq, int id); static void *JunctionFind(Junction *juncPtr, char *seq, int id, int fast); static void *JunctionFindExact(Junction *juncPtr, char *seq, int id, int flags, int fast); +static int JunctionWalk(Junction *juncPtr, int id, + int (*callback) (const void *, void *), void *userdata); static void *JunctionDelete(Junction *juncPtr, char *seq, int id, int flags); /* @@ -496,7 +500,6 @@ Ns_ServerSpecificGet(char *handle, int id) return Ns_UrlSpecificGet(handle, NULL, NULL, id); } - /* *---------------------------------------------------------------------- @@ -520,6 +523,35 @@ Ns_ServerSpecificDestroy(char *handle, int id, int flags) return Ns_UrlSpecificDestroy(handle, NULL, NULL, id, flags); } + +/* + *---------------------------------------------------------------------- + * + * Ns_TrieWalk -- + * + * Walk a url space trie. + * + * Results: + * NS_OK, or callback return value if not NS_OK. + * + * Side effects: + * Depends on callback implementation. + * + *---------------------------------------------------------------------- + */ + +int +Ns_TrieWalk(int id, int (*callback) (const void *, void *), void *userdata) +{ + int result; + + Ns_MutexLock(&lock); + result = JunctionWalk(&urlspace, id, callback, userdata); + Ns_MutexUnlock(&lock); + + return result; +} + /* *---------------------------------------------------------------------- @@ -1165,6 +1197,80 @@ TrieFindExact(Trie *triePtr, char *seq, int id, int flags) return data; } + +/* + *---------------------------------------------------------------------- + * + * TrieWalk -- + * + * Walk a trie, invoking a callback on each node. + * + * Results: + * NS_OK, or callback return value if not NS_OK. + * + * Side effects: + * Depends on callback implementation. + * + *---------------------------------------------------------------------- + */ + +static int +TrieWalk(Trie *triePtr, int id, int (*callback) (const void *, void *), void *userdata) +{ + int i, l; + int result = 0; + + if (triePtr->indexnode != NULL) { + Node *nodePtr; + + /* + * We've reached a trie with an indexnode, which means that our + * data may be here. (If node is null that means that there + * is data at this branch, but not with this particular ID). + */ + + nodePtr = Ns_IndexFind(triePtr->indexnode, (void *) id); + + if (nodePtr != NULL) { + if (nodePtr->dataNoInherit != NULL) { + result = callback((const void *) nodePtr->dataNoInherit, + userdata); + } else { + result = callback((const void *) nodePtr->dataInherit, + userdata); + } + } + + + /* + * Callback didn't return NS_OK, so we short circuit and stop. + */ + + if (result != NS_OK) { + return result; + } + } + + l = Ns_IndexCount(&triePtr->branches); + + for (i = 0; i < l; i++) { + Branch *branchPtr = Ns_IndexEl(&triePtr->branches, i); + + if (branchPtr != NULL) { + result = TrieWalk(&branchPtr->node, id, callback, userdata); + + /* + * Callback didn't return NS_OK, so we short circuit and stop. + */ + + if (result != NS_OK) { + return result; + } + } + } + + return NS_OK; +} /* *---------------------------------------------------------------------- @@ -1787,6 +1893,70 @@ JunctionFindExact(Junction *juncPtr, char *seq, int id, int flags, int fast) return data; } + +/* + *---------------------------------------------------------------------- + * + * JunctionWalk -- + * + * Walk an entire junction, invoking a callback on each node. + * + * Results: + * NS_OK, or callback return value if not NS_OK. + * + * Side effects: + * Depends on callback implementation. + * + *---------------------------------------------------------------------- + */ + +static int +JunctionWalk(Junction *juncPtr, int id, int (*callback) (const void *, void *), void *userdata) +{ + int i, l; + int result; + + /* + * Check filters from most restrictive to least restrictive + */ + +#ifndef __URLSPACE_OPTIMIZE__ + l = Ns_IndexCount(&juncPtr->byuse); +#else + l = Ns_IndexCount(&juncPtr->byname); +#endif + + /* + * For __URLSPACE_OPTIMIZE__ + * Basically if we use the optimize, let's reverse the order + * by which we search because the byname is in "almost" exact + * reverse lexicographical order. + * + * Loop over all the channels in the index. + */ + +#ifndef __URLSPACE_OPTIMIZE__ + for (i = 0; i < l; i++) { + Channel *channelPtr = Ns_IndexEl(&juncPtr->byuse, i); +#else + for (i = (l - 1); i >= 0; i--) { + Channel *channelPtr = Ns_IndexEl(&juncPtr->byname, i); +#endif + + result = TrieWalk(&channelPtr->trie, id, callback, userdata); + + if (result != NS_OK) { + /* + * Callback didn't return NS_OK, so we short circuit and stop. + */ + + return result; + } + } + + return NS_OK; +} + /* *----------------------------------------------------------------------