From: Stephen D. <sd...@us...> - 2005-04-12 06:21:36
|
Update of /cvsroot/naviserver/naviserver/nsd In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22726/nsd Modified Files: conn.c fastpath.c info.c nsd.h pathname.c proc.c return.c server.c tclcmds.c Log Message: * include/ns.h: * nsd/nsd.h: * nsd/info.c: * nsd/proc.c: * nsd/return.c: * nsd/server.c: * nsd/fastpath.c: * nsd/pathname.c: New concept: server root. Callback can be registered to create the server root, defaults to statically assigned 'serverroot' from config, or host-based if enabled. Many virtual hosting options added. (RFE #1159471) * nsd/conn.c: Add callback to generate current location. If none registered, uses host-header and falls back to driver's location. Add new Ns_ConnAppendLocation() as preferred method of access, depreciated Ns_ConnLocation(). * nsd/tclcmds.c: Add vhost related Tcl commands: ns_serverpath ns_pagepath ns_hashpath ns_serverrootproc ns_locationproc. * ns_pagepath.test: * ns_conn_host.test: * ns_serverpath.test: * ns_hashpath.test: * tests/test.nscfg: Add tests for vhost related commands. More location tests needed... Index: return.c =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/return.c,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** return.c 18 Mar 2005 08:21:06 -0000 1.2 --- return.c 12 Apr 2005 06:21:23 -0000 1.3 *************** *** 697,705 **** */ if (servPtr->opts.noticedetail) { ! Ns_DStringVarAppend(&ds, "<P ALIGN=RIGHT><SMALL><I>", ! Ns_InfoServerName(), "/", ! Ns_InfoServerVersion(), " on ", ! Ns_ConnLocation(conn), "</I></SMALL></P>\n", ! NULL); } --- 697,706 ---- */ if (servPtr->opts.noticedetail) { ! Ns_DStringVarAppend(&ds, "<P ALIGN=RIGHT><SMALL><I>", ! Ns_InfoServerName(), "/", ! Ns_InfoServerVersion(), " on ", ! NULL); ! Ns_ConnLocationAppend(conn, &ds); ! Ns_DStringAppend(&ds, "</I></SMALL></P>\n"); } *************** *** 950,965 **** if (url != NULL) { if (*url == '/') { ! Ns_DStringAppend(&ds, Ns_ConnLocation(conn)); } Ns_DStringAppend(&ds, url); Ns_ConnSetHeaders(conn, "Location", ds.string); ! Ns_DStringVarAppend(&msg, "<A HREF=\"", ds.string, ! "\">The requested URL has moved here.</A>", NULL); ! result = Ns_ConnReturnNotice(conn, 302, "Redirection", msg.string); } else { ! result = Ns_ConnReturnNotice(conn, 204, "No Content", msg.string); } Ns_DStringFree(&msg); Ns_DStringFree(&ds); return result; } --- 951,967 ---- if (url != NULL) { if (*url == '/') { ! Ns_ConnLocationAppend(conn, &ds); } Ns_DStringAppend(&ds, url); Ns_ConnSetHeaders(conn, "Location", ds.string); ! Ns_DStringVarAppend(&msg, "<A HREF=\"", ds.string, ! "\">The requested URL has moved here.</A>", NULL); ! result = Ns_ConnReturnNotice(conn, 302, "Redirection", msg.string); } else { ! result = Ns_ConnReturnNotice(conn, 204, "No Content", msg.string); } Ns_DStringFree(&msg); Ns_DStringFree(&ds); + return result; } Index: nsd.h =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/nsd.h,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** nsd.h 8 Apr 2005 19:59:16 -0000 1.10 --- nsd.h 12 Apr 2005 06:21:23 -0000 1.11 *************** *** 133,136 **** --- 133,139 ---- #define LOG_USEC 32 + #define NSD_STRIP_WWW 0x01 + #define NSD_STRIP_PORT 0x02 + /* * The following is the default text/html content type *************** *** 508,512 **** typedef struct NsServer { char *server; - Ns_LocationProc *locationProc; /* --- 511,514 ---- *************** *** 559,563 **** struct { ! char *pageroot; char **dirv; int dirc; --- 561,567 ---- struct { ! char *serverdir; /* virtual server files path */ ! char *pagedir; /* path to public pages */ ! char *pageroot; /* absolute path to public pages */ char **dirv; int dirc; *************** *** 571,574 **** --- 575,594 ---- /* + * The following struct maintains virtual host config. + */ + + struct { + bool enabled; + int opts; /* NSD_STRIP_WWW | NSD_STRIP_PORT */ + char *hostprefix; + int hosthashlevel; + Ns_ServerRootProc *serverRootProc; + void *serverRootArg; + Ns_ConnLocationProc *connLocationProc; + void *connLocationArg; + Ns_LocationProc *locationProc; /* depreciated */ + } vhost; + + /* * The following struct maintains request tables. */ *************** *** 827,835 **** --- 847,859 ---- extern int NsUrlToFile(Ns_DString *dsPtr, NsServer *servPtr, char *url); + extern char *NsPageRoot(Ns_DString *dest, NsServer *servPtr, char *host); + /* * External callback functions. */ + extern Ns_ConnLocationProc NsTclConnLocation; extern Ns_SchedProc NsTclSchedProc; + extern Ns_ServerRootProc NsTclServerRoot; extern Ns_ThreadProc NsTclThread; extern Ns_ArgProc NsTclThreadArgProc; Index: conn.c =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/conn.c,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** conn.c 18 Mar 2005 08:12:56 -0000 1.6 --- conn.c 12 Apr 2005 06:21:23 -0000 1.7 *************** *** 364,386 **** * Ns_SetConnLocationProc -- * ! * Set pointer to custom routine that acts like Ns_ConnLocation(); * * Results: ! * None. * * Side effects: ! * None. * *---------------------------------------------------------------------- */ ! void ! Ns_SetConnLocationProc(Ns_LocationProc *procPtr) { NsServer *servPtr = NsGetInitServer(); ! if (servPtr != NULL) { ! servPtr->locationProc = procPtr; } } --- 364,392 ---- * Ns_SetConnLocationProc -- * ! * Set pointer to custom routine that acts like ! * Ns_ConnLocationAppend(); * * Results: ! * NS_OK or NS_ERROR. * * Side effects: ! * Overrides an old-style Ns_LocationProc. * *---------------------------------------------------------------------- */ ! int ! Ns_SetConnLocationProc(Ns_ConnLocationProc *proc, void *arg) { NsServer *servPtr = NsGetInitServer(); ! if (servPtr == NULL) { ! Ns_Log(Error, "Ns_SetConnLocationProc: no initializing server"); ! return NS_ERROR; } + servPtr->vhost.connLocationProc = proc; + servPtr->vhost.connLocationArg = arg; + + return NS_OK; } *************** *** 392,395 **** --- 398,404 ---- * Set pointer to custom routine that acts like Ns_ConnLocation(); * + * Depreciated: Use Ns_SetConnLocationProc() which is virtual host + * aware. + * * Results: * None. *************** *** 402,411 **** void ! Ns_SetLocationProc(char *server, Ns_LocationProc *procPtr) { NsServer *servPtr = NsGetServer(server); if (servPtr != NULL) { ! servPtr->locationProc = procPtr; } } --- 411,420 ---- void ! Ns_SetLocationProc(char *server, Ns_LocationProc *proc) { NsServer *servPtr = NsGetServer(server); if (servPtr != NULL) { ! servPtr->vhost.locationProc = proc; } } *************** *** 417,428 **** * Ns_ConnLocation -- * ! * Get the location of this connection. It is of the form ! * METHOD://HOSTNAME:PORT * * Results: ! * a string URL, not including path * * Side effects: ! * None. * *---------------------------------------------------------------------- --- 426,440 ---- * Ns_ConnLocation -- * ! * Get the location according to the driver for this connection. ! * It is of the form SCHEME://HOSTNAME:PORT ! * ! * Depreciated: Use Ns_ConnLocationAppend() which is virtual host ! * aware. * * Results: ! * a string URL, not including path * * Side effects: ! * None. * *---------------------------------------------------------------------- *************** *** 432,444 **** Ns_ConnLocation(Ns_Conn *conn) { ! Conn *connPtr = (Conn *) conn; NsServer *servPtr = connPtr->servPtr; ! char *location; - if (servPtr->locationProc != NULL) { - location = (*servPtr->locationProc)(conn); } else { ! location = connPtr->location; } return location; } --- 444,552 ---- Ns_ConnLocation(Ns_Conn *conn) { ! Conn *connPtr = (Conn *) conn; NsServer *servPtr = connPtr->servPtr; ! char *location = NULL; ! ! if (servPtr->vhost.locationProc != NULL) { ! location = (*servPtr->vhost.locationProc)(conn); ! } ! if (location == NULL) { ! location = connPtr->location; ! } ! ! return location; ! } ! ! ! /* ! *---------------------------------------------------------------------- ! * ! * Ns_ConnLocationAppend -- ! * ! * Append the location of this connection to dest. It is of the ! * form SCHEME://HOSTNAME:PORT ! * ! * Results: ! * dest->string. ! * ! * Side effects: ! * None. ! * ! *---------------------------------------------------------------------- ! */ ! ! char * ! Ns_ConnLocationAppend(Ns_Conn *conn, Ns_DString *dest) ! { ! Conn *connPtr = (Conn *) conn; ! NsServer *servPtr = connPtr->servPtr; ! Ns_Set *headers; ! char *location, *host, *p; ! ! if (servPtr->vhost.connLocationProc != NULL) { ! ! /* ! * Prefer the new style Ns_ConnLocationProc. ! */ ! ! location = (*servPtr->vhost.connLocationProc) ! (conn, dest, servPtr->vhost.connLocationArg); ! if (location == NULL) { ! goto deflocation; ! } ! ! } else if (servPtr->vhost.locationProc != NULL) { ! ! /* ! * Fall back to old style Ns_LocationProc. ! */ ! ! location = (*servPtr->vhost.locationProc)(conn); ! if (location == NULL) { ! goto deflocation; ! } ! location = Ns_DStringAppend(dest, location); ! ! } else if (servPtr->vhost.enabled ! && (headers = Ns_ConnHeaders(conn)) ! && (host = Ns_SetIGet(headers, "Host")) ! && *host != '\0') { ! ! /* ! * Construct a location string from the HTTP host header. ! * ! * We do not trust the contents of the Host header, so we scan ! * it for new lines which may be a reponse splitting attack when ! * used as the target of a redirect reponse, and the HTML open ! * tag character which may be a cross-site scripting attack when ! * embedded within HTML. ! */ ! ! for (p = host; *p != '\0'; ++p) { ! if (*p == '\n' || *p == '\r' || *p == '<') { ! return NULL; ! } ! } ! ! Ns_DStringAppend(dest, connPtr->location); ! location = strstr(dest->string, "://"); ! if (location != NULL) { ! Ns_DStringTrunc(dest, (location - dest->string) + 3); ! } else { ! /* server missconfiguration, should begin: SCHEME:// */ ! Ns_DStringAppend(dest, "http://"); ! } ! location = Ns_DStringAppend(dest, host); } else { ! ! /* ! * If all else fails, append the static driver location. ! */ ! ! deflocation: ! location = Ns_DStringAppend(dest, connPtr->location); } + return location; } *************** *** 833,836 **** --- 941,945 ---- Tcl_HashSearch search; FormFile *filePtr; + Ns_DString ds; int idx, off, len; *************** *** 1118,1122 **** case CLocationIdx: ! Tcl_SetResult(interp, Ns_ConnLocation(conn), TCL_STATIC); break; --- 1227,1233 ---- case CLocationIdx: ! Ns_DStringInit(&ds); ! Ns_ConnLocationAppend(conn, &ds); ! Tcl_DStringResult(interp, &ds); break; *************** *** 1178,1181 **** --- 1289,1330 ---- *---------------------------------------------------------------------- * + * NsTclLocationProcObjCmd -- + * + * Implements ns_locationproc as obj command. + * + * Results: + * Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + int + NsTclLocationProcObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) + { + NsServer *servPtr = NsGetInitServer(); + Ns_TclCallback *cbPtr; + + if (objc != 2 && objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "script ?arg?"); + return TCL_ERROR; + } + if (servPtr == NULL) { + Tcl_AppendResult(interp, "no initializing server", TCL_STATIC); + return TCL_ERROR; + } + cbPtr = Ns_TclNewCallbackObj(interp, NsTclConnLocation, + objv[1], (objc > 2) ? objv[2] : NULL); + Ns_SetConnLocationProc(NsTclConnLocation, cbPtr); + + return TCL_OK; + } + + + /* + *---------------------------------------------------------------------- + * * NsTclWriteContentObjCmd -- * *************** *** 1327,1330 **** --- 1476,1507 ---- } + + /* + *---------------------------------------------------------------------- + * + * NsTclConnLocation -- + * + * Tcl callback to construct location string. + * + * Results: + * dest->string or NULL on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + char * + NsTclConnLocation(Ns_Conn *conn, Ns_DString *dest, void *arg) + { + Ns_TclCallback *cbPtr = arg; + Tcl_Interp *interp = Ns_GetConnInterp(conn); + + if (Ns_TclEvalCallback(interp, cbPtr, dest, NULL) != NS_OK) { + return NULL; + } + return Ns_DStringValue(dest); + } Index: pathname.c =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/pathname.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** pathname.c 16 Feb 2005 08:40:22 -0000 1.1.1.1 --- pathname.c 12 Apr 2005 06:21:23 -0000 1.2 *************** *** 45,49 **** --- 45,53 ---- */ + static int PathObjCmd(ClientData arg, Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[], int cmd); static char *MakePath(Ns_DString *dest, va_list *pap); + static char *ServerRoot(Ns_DString *dest, NsServer *servPtr, char *host); + *************** *** 202,205 **** --- 206,258 ---- *---------------------------------------------------------------------- * + * Ns_HashPath -- + * + * Hash the leading characters of string into a path, skipping + * periods and slashes. If string contains less characters than + * levels requested, '_' characters are used as padding. + * + * For example, given the string 'foo' and the levels 2, 3, 4: + * + * foo, 2 -> /f/o + * foo, 3 -> /f/o/o + * foo, 4 -> /f/o/o/_ + * + * Results: + * dest->string + * + * Side effects: + * Will append to dest. + * + *---------------------------------------------------------------------- + */ + + char * + Ns_HashPath(Ns_DString *dest, char *string, int levels) + { + char *p = string; + int i; + + for (i = 0; i < levels; ++i) { + if (dest->string[dest->length] != '/') { + Ns_DStringNAppend(dest, "/", 1); + } + while (*p == '.' || isslash(*p)) { + ++p; + } + if (*p != '\0') { + Ns_DStringNAppend(dest, p, 1); + p++; + } else { + Ns_DStringNAppend(dest, "_", 1); + } + } + + return Ns_DStringValue(dest); + } + + + /* + *---------------------------------------------------------------------- + * * Ns_LibPath -- * *************** *** 266,269 **** --- 319,394 ---- *---------------------------------------------------------------------- * + * Ns_ServerPath -- + * + * Build a path relative to the server root dir. + * + * Results: + * dest->string or NULL on error. + * + * Side effects: + * See ServerRoot(). + * + *---------------------------------------------------------------------- + */ + + char * + Ns_ServerPath(Ns_DString *dest, char *server, ...) + { + NsServer *servPtr; + va_list ap; + char *path; + + servPtr = NsGetServer(server); + if (servPtr == NULL) { + return NULL; + } + ServerRoot(dest, servPtr, NULL); + va_start(ap, server); + path = MakePath(dest, &ap); + va_end(ap); + + return path; + } + + + /* + *---------------------------------------------------------------------- + * + * Ns_PagePath -- + * + * Build a path relative to the server pages dir. + * + * Results: + * dest->string or NULL on error. + * + * Side effects: + * See ServerRoot(). + * + *---------------------------------------------------------------------- + */ + + char * + Ns_PagePath(Ns_DString *dest, char *server, ...) + { + NsServer *servPtr; + va_list ap; + char *path; + + servPtr = NsGetServer(server); + if (servPtr == NULL) { + return NULL; + } + NsPageRoot(dest, servPtr, NULL); + va_start(ap, server); + path = MakePath(dest, &ap); + va_end(ap); + + return path; + } + + + /* + *---------------------------------------------------------------------- + * * Ns_ModulePath -- * *************** *** 304,307 **** --- 429,539 ---- *---------------------------------------------------------------------- * + * Ns_SetServerRootProc -- + * + * Set pointer to custom procedure that returns the root dir path + * for a server. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + int + Ns_SetServerRootProc(Ns_ServerRootProc *proc, void *arg) + { + NsServer *servPtr = NsGetInitServer(); + + if (servPtr == NULL) { + Ns_Log(Error, "Ns_SetServerRootProc: no initializing server"); + return NS_ERROR; + } + servPtr->vhost.serverRootProc = proc; + servPtr->vhost.serverRootArg = arg; + + return NS_OK; + } + + + /* + *---------------------------------------------------------------------- + * + * NsPageRoot -- + * + * Return the path to the server pages directory. + * + * Results: + * dest->string. + * + * Side effects: + * See ServerRoot(). + * + *---------------------------------------------------------------------- + */ + + char * + NsPageRoot(Ns_DString *dest, NsServer *servPtr, char *host) + { + char *path; + + if (Ns_PathIsAbsolute(servPtr->fastpath.pagedir)) { + path = Ns_DStringAppend(dest, servPtr->fastpath.pagedir); + } else { + ServerRoot(dest, servPtr, host); + path = Ns_MakePath(dest, servPtr->fastpath.pagedir, NULL); + } + + return path; + } + + + /* + *---------------------------------------------------------------------- + * + * NsTclHashPathObjCmd -- + * + * Implements ns_hashpath obj command; a wrapper for Ns_HashPath. + * + * Results: + * Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + + int + NsTclHashPathObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) + { + Ns_DString path; + int levels; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "string levels"); + return TCL_ERROR; + } + if (Tcl_GetIntFromObj(interp, objv[2], &levels) != TCL_OK + || levels <= 0) { + + Tcl_SetResult(interp, "levels must be an interger greater than zero", + TCL_STATIC); + return TCL_ERROR; + } + Ns_DStringInit(&path); + Ns_HashPath(&path, Tcl_GetString(objv[1]), levels); + Tcl_DStringResult(interp, &path); + + return TCL_OK; + } + + + /* + *---------------------------------------------------------------------- + * * NsTclModulePathObjCmd -- * *************** *** 345,348 **** --- 577,719 ---- *---------------------------------------------------------------------- * + * NsTclServerPathObjCmd, NsTclPagePathObjCmd -- + * + * Implements ns_serverpath, ns_pagepath commands. + * + * Results: + * Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + + int + NsTclServerPathObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) + { + return PathObjCmd(arg, interp, objc, objv, 's'); + } + + int + NsTclPagePathObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) + { + return PathObjCmd(arg, interp, objc, objv, 'p'); + } + + static int + PathObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int cmd) + { + NsInterp *itPtr = arg; + NsServer *servPtr; + Ns_DString ds; + char *path, *host = NULL; + int i, npaths = 0; + + Ns_ObjvSpec opts[] = { + {"-host", Ns_ObjvString, &host, NULL}, + {"--", Ns_ObjvBreak, NULL, NULL}, + {NULL, NULL, NULL, NULL} + }; + Ns_ObjvSpec args[] = { + {"?path", Ns_ObjvArgs, &npaths, NULL}, + {NULL, NULL, NULL, NULL} + }; + if (Ns_ParseObjv(opts, args, interp, 1, objc, objv) != NS_OK) { + return TCL_ERROR; + } + + if ((servPtr = itPtr->servPtr) == NULL + && (servPtr = NsGetInitServer()) == NULL) { + + Tcl_SetResult(interp, "no server available", TCL_STATIC); + return TCL_ERROR; + } + + Ns_DStringInit(&ds); + if (cmd == 'p') { + path = NsPageRoot(&ds, itPtr->servPtr, host); + } else { + path = ServerRoot(&ds, itPtr->servPtr, host); + } + for (i = objc - npaths; i < objc; ++i) { + Ns_MakePath(&ds, Tcl_GetString(objv[i]), NULL); + } + Tcl_DStringResult(interp, &ds); + + return TCL_OK; + } + + + /* + *---------------------------------------------------------------------- + * + * NsTclServerRootProcObjCmd -- + * + * Implements the ns_serverrootproc command. + * + * Results: + * Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + int + NsTclServerRootProcObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) + { + NsServer *servPtr = NsGetInitServer(); + Ns_TclCallback *cbPtr; + + if (objc != 2 && objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "script ?arg?"); + return TCL_ERROR; + } + if (servPtr == NULL) { + Tcl_AppendResult(interp, "no initializing server", TCL_STATIC); + return TCL_ERROR; + } + cbPtr = Ns_TclNewCallbackObj(interp, NsTclServerRoot, + objv[1], (objc > 2) ? objv[2] : NULL); + Ns_SetServerRootProc(NsTclServerRoot, cbPtr); + + return TCL_OK; + } + + + /* + *---------------------------------------------------------------------- + * + * NsTclServerRoot -- + * + * Tcl callback to build a path to the server root dir. + * + * Results: + * dest->string or NULL on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + char * + NsTclServerRoot(Ns_DString *dest, char *host, void *arg) + { + Ns_TclCallback *cbPtr = arg; + + if (Ns_TclEvalCallback(NULL, cbPtr, dest, host, NULL) != NS_OK) { + return NULL; + } + return Ns_DStringValue(dest); + } + + + /* + *---------------------------------------------------------------------- + * * MakePath -- * *************** *** 389,390 **** --- 760,853 ---- return dest->string; } + + + /* + *---------------------------------------------------------------------- + * ServerRoot -- + * + * Return the path to the server root directory. If virtual + * hosting is enabled then the host header is used to construct the + * path. If host is given it overides the Host header of the + * current connection. + * + * Results: + * dest->string. + * + * Side effects: + * Value of Host header may be bashed to lower case. + * Depends on registered Ns_ServerRootProc, if any. + * + *---------------------------------------------------------------------- + */ + + static char * + ServerRoot(Ns_DString *dest, NsServer *servPtr, char *host) + { + char *p, *path, *port = NULL; + Ns_Conn *conn; + Ns_Set *headers; + + if (servPtr->vhost.serverRootProc != NULL) { + + /* + * Prefer to run a user-registered Ns_ServerRootProc. + */ + + path = (servPtr->vhost.serverRootProc)(dest, host, servPtr->vhost.serverRootArg); + if (path == NULL) { + goto defpath; + } + + } else if (servPtr->vhost.enabled + && (host != NULL + || ((conn = Ns_GetConn()) != NULL + && (headers = Ns_ConnHeaders(conn)) != NULL + && (host = Ns_SetIGet(headers, "Host")) != NULL)) + && *host != '\0') { + + /* + * Bail out if there are suspicious characters. + */ + + for (p = host; *p != '\0'; p++) { + if (isslash(*p) || isspace(*p) || (p[0] == '.' && p[1] == '.')) { + goto defpath; + } + } + host = Ns_StrToLower(host); + + path = Ns_MakePath(dest, servPtr->fastpath.serverdir, + servPtr->vhost.hostprefix, NULL); + + if (servPtr->vhost.opts & NSD_STRIP_WWW) { + if (strncmp(host, "www.", 4) == 0) { + host = &host[4]; + } + } + if (servPtr->vhost.opts & NSD_STRIP_PORT) { + if ((port = strrchr(host, ':')) != NULL) { + *port = '\0'; + } + } + + if (servPtr->vhost.hosthashlevel > 0) { + Ns_HashPath(dest, host, servPtr->vhost.hosthashlevel); + } + Ns_NormalizePath(dest, host); + + if (port != NULL) { + *port = ':'; + } + + } else { + + /* + * Default to static server root. + */ + + defpath: + path = Ns_MakePath(dest, servPtr->fastpath.serverdir, NULL); + } + + return path; + } Index: fastpath.c =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/fastpath.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** fastpath.c 16 Feb 2005 08:39:42 -0000 1.1.1.1 --- fastpath.c 12 Apr 2005 06:21:23 -0000 1.2 *************** *** 147,150 **** --- 147,151 ---- * * Return path name of the server pages directory. + * Depreciated: Use Ns_PagePath() which is virtual host aware. * * Results: *************** *** 161,166 **** { NsServer *servPtr = NsGetServer(server); ! ! return servPtr->fastpath.pageroot; } --- 162,170 ---- { NsServer *servPtr = NsGetServer(server); ! ! if (servPtr != NULL) { ! return servPtr->fastpath.pageroot; ! } ! return NULL; } *************** *** 629,634 **** status = (*servPtr->fastpath.url2file)(dsPtr, servPtr->server, url); } else { ! Ns_MakePath(dsPtr, servPtr->fastpath.pageroot, url, NULL); ! status = NS_OK; } if (status == NS_OK) { --- 633,639 ---- status = (*servPtr->fastpath.url2file)(dsPtr, servPtr->server, url); } else { ! NsPageRoot(dsPtr, servPtr, NULL); ! Ns_MakePath(dsPtr, url, NULL); ! status = NS_OK; } if (status == NS_OK) { Index: server.c =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/server.c,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** server.c 18 Mar 2005 08:21:06 -0000 1.2 --- server.c 12 Apr 2005 06:21:23 -0000 1.3 *************** *** 377,387 **** } } ! servPtr->fastpath.pageroot = Ns_ConfigGetValue(path, "pageroot"); ! if (servPtr->fastpath.pageroot == NULL) { ! servPtr->fastpath.pageroot = Ns_ConfigGetValue(spath, "pageroot"); ! if (servPtr->fastpath.pageroot == NULL) { ! Ns_ModulePath(&ds, server, NULL, "pages", NULL); ! servPtr->fastpath.pageroot = Ns_DStringExport(&ds); ! } } p = Ns_ConfigGetValue(path, "directorylisting"); --- 377,398 ---- } } ! servPtr->fastpath.serverdir = Ns_ConfigGetValue(path, "serverdir"); ! if (servPtr->fastpath.serverdir == NULL) { ! Ns_MakePath(&ds, Ns_InfoHomePath(), "servers", server, NULL); ! servPtr->fastpath.serverdir = Ns_DStringExport(&ds); ! } else if (!Ns_PathIsAbsolute(servPtr->fastpath.serverdir)) { ! Ns_MakePath(&ds, Ns_InfoHomePath(), servPtr->fastpath.serverdir, NULL); ! servPtr->fastpath.serverdir = Ns_DStringExport(&ds); ! } ! servPtr->fastpath.pagedir = Ns_ConfigGetValue(path, "pagedir"); ! if (servPtr->fastpath.pagedir == NULL) { ! servPtr->fastpath.pagedir = "pages"; ! } ! if (Ns_PathIsAbsolute(servPtr->fastpath.pagedir)) { ! servPtr->fastpath.pageroot = servPtr->fastpath.pagedir; ! } else { ! Ns_MakePath(&ds, servPtr->fastpath.serverdir, ! servPtr->fastpath.pagedir, NULL); ! servPtr->fastpath.pageroot = Ns_DStringExport(&ds); } p = Ns_ConfigGetValue(path, "directorylisting"); *************** *** 396,399 **** --- 407,444 ---- /* + * Initialize virtual hosting. + */ + + path = Ns_ConfigGetPath(server, NULL, "vhost", NULL); + Ns_ConfigGetBool(path, "enabled", &servPtr->vhost.enabled); + if (servPtr->vhost.enabled + && Ns_PathIsAbsolute(servPtr->fastpath.pagedir)) { + + Ns_Log(Error, "virtual hosting disabled, pagedir not relative: %s", + servPtr->fastpath.pagedir); + servPtr->vhost.enabled = NS_FALSE; + } + if (!Ns_ConfigGetBool(path, "stripwww", &i) || i) { + servPtr->vhost.opts |= NSD_STRIP_WWW; + } + if (!Ns_ConfigGetBool(path, "stripport", &i) || i) { + servPtr->vhost.opts |= NSD_STRIP_PORT; + } + servPtr->vhost.hostprefix = Ns_ConfigGetValue(path, "hostprefix"); + Ns_ConfigGetInt(path, "hosthashlevel", &servPtr->vhost.hosthashlevel); + if (servPtr->vhost.hosthashlevel < 0) { + servPtr->vhost.hosthashlevel = 0; + } + if (servPtr->vhost.hosthashlevel > 5) { + servPtr->vhost.hosthashlevel = 5; + } + if (servPtr->vhost.enabled) { + NsPageRoot(&ds, servPtr, ns_strdup("www.example.com:80")); + Ns_Log(Notice, "vhost[%s]: www.example.com:80 -> %s", + server, ds.string); + Ns_DStringTrunc(&ds, 0); + } + + /* * Configure the url, proxy and redirect requests. */ Index: tclcmds.c =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/tclcmds.c,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** tclcmds.c 2 Apr 2005 20:31:59 -0000 1.8 --- tclcmds.c 12 Apr 2005 06:21:23 -0000 1.9 *************** *** 89,92 **** --- 89,93 ---- NsTclGmTimeObjCmd, NsTclGuessTypeObjCmd, + NsTclHashPathObjCmd, NsTclHTUUDecodeObjCmd, NsTclHTUUEncodeObjCmd, *************** *** 100,103 **** --- 101,105 ---- NsTclLinkObjCmd, NsTclLocalTimeObjCmd, + NsTclLocationProcObjCmd, NsTclLogObjCmd, NsTclLogCtlObjCmd, *************** *** 117,120 **** --- 119,123 ---- NsTclNsvSetObjCmd, NsTclNsvUnsetObjCmd, + NsTclPagePathObjCmd, NsTclParseArgsObjCmd, NsTclParseHttpTimeObjCmd, *************** *** 149,152 **** --- 152,157 ---- NsTclSemaObjCmd, NsTclServerObjCmd, + NsTclServerPathObjCmd, + NsTclServerRootProcObjCmd, NsTclSetCookieObjCmd, NsTclSetObjCmd, *************** *** 246,250 **** --- 251,262 ---- {"ns_info", NULL, NsTclInfoObjCmd}, + + {"ns_hashpath", NULL, NsTclHashPathObjCmd}, {"ns_modulepath", NULL, NsTclModulePathObjCmd}, + {"ns_pagepath", NULL, NsTclPagePathObjCmd}, + {"ns_serverpath", NULL, NsTclServerPathObjCmd}, + + {"ns_serverrootproc", NULL, NsTclServerRootProcObjCmd}, + {"ns_locationproc", NULL, NsTclLocationProcObjCmd}, /* Index: proc.c =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/proc.c,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** proc.c 12 Apr 2005 05:09:42 -0000 1.4 --- proc.c 12 Apr 2005 06:21:23 -0000 1.5 *************** *** 63,67 **** static Tcl_HashTable info; ! struct proc { void *procAddr; char *desc; --- 63,67 ---- static Tcl_HashTable info; ! static struct proc { void *procAddr; char *desc; *************** *** 70,74 **** --- 70,76 ---- {(void *) NsTclThread, "ns:tclthread", NsTclThreadArgProc}, {(void *) Ns_TclCallbackProc, "ns:tclcallback", Ns_TclCallbackArgProc}, + {(void *) NsTclConnLocation, "ns:tclconnlocation", Ns_TclCallbackArgProc}, {(void *) NsTclSchedProc, "ns:tclschedproc", Ns_TclCallbackArgProc}, + {(void *) NsTclServerRoot, "ns:tclserverroot", Ns_TclCallbackArgProc}, {(void *) NsTclSockProc, "ns:tclsockcallback", NsTclSockArgProc}, {(void *) NsCachePurge, "ns:cachepurge", NsCacheArgProc}, Index: info.c =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/info.c,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** info.c 28 Mar 2005 17:02:07 -0000 1.2 --- info.c 12 Apr 2005 06:21:23 -0000 1.3 *************** *** 673,677 **** Tcl_SetResult(interp, itPtr->servPtr->tcl.library, TCL_STATIC); } else { ! Tcl_SetResult(interp, itPtr->servPtr->fastpath.pageroot, TCL_STATIC); } } --- 673,678 ---- Tcl_SetResult(interp, itPtr->servPtr->tcl.library, TCL_STATIC); } else { ! NsPageRoot(&ds, itPtr->servPtr, NULL); ! Tcl_DStringResult(interp, &ds); } } |