| /* |
| * url.c -- url generation |
| * nca-073-9 |
| * |
| * Copyright (c) 1996-2000 by Netcetera AG. |
| * Copyright (c) 2001 by Apache Software Foundation. |
| * All rights reserved. |
| * |
| * See the file "license.terms" for information on usage and |
| * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
| * |
| * @(#) $Id$ |
| * |
| */ |
| |
| #include <tcl.h> |
| #include <time.h> |
| #include "url.h" |
| #include "paramlist.h" |
| #include "crypt.h" |
| #include "stdlib.h" /* getenv */ |
| #include "log.h" |
| #include "request.h" |
| |
| |
| |
| /* if direct is 1: don't try to get configured value, but the one |
| from the environment / requestData */ |
| #define WEB_URL_GETFROMREQDATA(scheme,key,direct) \ |
| if(!direct && urlData->scheme != NULL ) \ |
| scheme = urlData->scheme; \ |
| if( scheme == NULL ) \ |
| if( urlData->requestData != NULL ) \ |
| scheme = paramListGetObjectByString(interp,urlData->requestData->request,key); |
| |
| |
| static TCLCONST char *urlElementOpts[] = { |
| "-scheme", |
| "-host", |
| "-port", |
| "-scriptname", |
| "-pathinfo", |
| "-querystring", |
| NULL |
| }; |
| |
| /* to which flags the names above correspond */ |
| static int urlElementFlags[] = { |
| WEB_URL_WITH_SCHEME, |
| WEB_URL_WITH_HOST, |
| WEB_URL_WITH_PORT, |
| WEB_URL_WITH_SCRIPTNAME, |
| WEB_URL_WITH_PATHINFO, |
| WEB_URL_WITH_QUERYSTRING |
| }; |
| |
| enum urlElement |
| { |
| SCHEME, |
| HOST, |
| PORT, |
| SCRIPTNAME, |
| PATHINFO, |
| QUERYSTRING, |
| URLCFGRESET, |
| URLCFGURLFORMAT, |
| URLCFGEND |
| }; |
| |
| |
| /* ---------------------------------------------------------------------------- |
| * Init -- |
| * ------------------------------------------------------------------------- */ |
| int url_Init(Tcl_Interp * interp) |
| { |
| |
| UrlData *urlData; |
| |
| /* -------------------------------------------------------------------------- |
| * interpreter running ? |
| * ----------------------------------------------------------------------- */ |
| if (interp == NULL) |
| return TCL_ERROR; |
| |
| /* -------------------------------------------------------------------------- |
| * new data |
| * ----------------------------------------------------------------------- */ |
| urlData = createUrlData(); |
| |
| /* -------------------------------------------------------------------------- |
| * register commands |
| * ----------------------------------------------------------------------- */ |
| Tcl_CreateObjCommand(interp, "web::cmdurlcfg", |
| Web_CmdUrlCfg, (ClientData) urlData, NULL); |
| |
| Tcl_CreateObjCommand(interp, "web::cmdurl", |
| Web_CmdUrl, (ClientData) urlData, NULL); |
| |
| /* -------------------------------------------------------------------------- |
| * associate data with Interpreter |
| * ----------------------------------------------------------------------- */ |
| Tcl_SetAssocData(interp, WEB_URL_ASSOC_DATA, |
| destroyUrlData, (ClientData) urlData); |
| |
| /* -------------------------------------------------------------------------- |
| * done |
| * ----------------------------------------------------------------------- */ |
| return TCL_OK; |
| } |
| |
| |
| /* ---------------------------------------------------------------------------- |
| * create |
| * ------------------------------------------------------------------------- */ |
| UrlData *createUrlData() |
| { |
| |
| UrlData *urlData = NULL; |
| |
| urlData = WebAllocInternalData(UrlData); |
| |
| if (urlData != NULL) { |
| urlData->defaultscheme = NULL; |
| urlData->scheme = NULL; |
| /* we want to read port from request if available */ |
| /*WebNewStringObjFromStringIncr(urlData->port,WEB_DEFAULT_PORT); */ |
| urlData->port = NULL; |
| urlData->host = NULL; |
| urlData->scriptname = NULL; |
| urlData->pathinfo = NULL; |
| urlData->querystring = NULL; |
| |
| urlData->requestData = NULL; |
| |
| urlData->urlformat = WEB_URL_URLFORMAT; |
| } |
| |
| return urlData; |
| } |
| |
| /* ---------------------------------------------------------------------------- |
| * reset |
| * ------------------------------------------------------------------------- */ |
| int resetUrlData(Tcl_Interp * interp, UrlData * urlData) |
| { |
| if ((interp == NULL) || (urlData == NULL)) |
| return TCL_ERROR; |
| |
| WebDecrRefCountIfNotNullAndSetNull(urlData->defaultscheme); |
| WebDecrRefCountIfNotNullAndSetNull(urlData->scheme); |
| |
| WebDecrRefCountIfNotNullAndSetNull(urlData->port); |
| /* we want to read port from request if available */ |
| /*WebNewStringObjFromStringIncr(urlData->port,WEB_DEFAULT_PORT); */ |
| |
| WebDecrRefCountIfNotNullAndSetNull(urlData->host); |
| |
| WebDecrRefCountIfNotNullAndSetNull(urlData->scriptname); |
| |
| WebDecrRefCountIfNotNullAndSetNull(urlData->pathinfo); |
| |
| WebDecrRefCountIfNotNullAndSetNull(urlData->querystring); |
| |
| /* do not touch requestData */ |
| |
| urlData->urlformat = WEB_URL_URLFORMAT; |
| |
| return TCL_OK; |
| } |
| |
| /* ---------------------------------------------------------------------------- |
| * destroy |
| * ------------------------------------------------------------------------- */ |
| void destroyUrlData(ClientData clientData, Tcl_Interp * interp) |
| { |
| |
| UrlData *urlData = NULL; |
| |
| if (clientData != NULL) { |
| |
| urlData = (UrlData *) clientData; |
| |
| WebDecrRefCountIfNotNull(urlData->defaultscheme); |
| WebDecrRefCountIfNotNull(urlData->scheme); |
| WebDecrRefCountIfNotNull(urlData->port); |
| WebDecrRefCountIfNotNull(urlData->host); |
| WebDecrRefCountIfNotNull(urlData->scriptname); |
| WebDecrRefCountIfNotNull(urlData->pathinfo); |
| |
| WebFreeIfNotNull(urlData); |
| |
| } |
| } |
| |
| /* ---------------------------------------------------------------------------- |
| * parseUrlFormat -- parse the -with list and turn corresponding bits on, |
| * or 0 in case of error |
| * ------------------------------------------------------------------------- */ |
| int parseUrlFormat(Tcl_Interp * interp, Tcl_Obj * list) |
| { |
| |
| int objc = -1; |
| Tcl_Obj **objv = NULL; |
| int i = -1; |
| int res = 0; |
| |
| TCLCONST char *accepted[20]; |
| enum urlElement e; |
| |
| |
| /* -------------------------------------------------------------------------- |
| * minimal |
| * ----------------------------------------------------------------------- */ |
| if (list == NULL) { |
| LOG_MSG(interp, WRITE_LOG | SET_RESULT, |
| __FILE__, __LINE__, |
| "web::cmdurl -urlformat", WEBLOG_ERROR, |
| "cannot access list", NULL); |
| return 0; |
| } |
| |
| for (e = SCHEME; e <= QUERYSTRING; e++) |
| accepted[e] = &(urlElementOpts[e][1]); |
| accepted[e] = NULL; |
| |
| /* -------------------------------------------------------------------------- |
| * convert list to array of objs |
| * ----------------------------------------------------------------------- */ |
| if (Tcl_ListObjGetElements(interp, list, &objc, &objv) == TCL_ERROR) { |
| LOG_MSG(interp, WRITE_LOG | SET_RESULT, |
| __FILE__, __LINE__, |
| "web::cmdurl -urlformat", WEBLOG_ERROR, |
| "cannot convert \"", Tcl_GetString(list), "\" to list", NULL); |
| return 0; |
| } |
| |
| /* empty list */ |
| if (objc == 0) { |
| Tcl_SetResult(interp, "no url elements specified", TCL_STATIC); |
| return 0; |
| } |
| |
| /* -------------------------------------------------------------------------- |
| * now see what we got |
| * ----------------------------------------------------------------------- */ |
| for (i = 0; i < objc; i++) { |
| int idx = 0; |
| if (Tcl_GetIndexFromObj(interp, |
| objv[i], |
| accepted, |
| "url element", 0, &idx) == TCL_ERROR) |
| return 0; |
| else { |
| res |= urlElementFlags[idx]; |
| } |
| } |
| return res; |
| } |
| |
| |
| /* ---------------------------------------------------------------------------- |
| * mergeLists -- assume key-value paired list; take value from staticP if no |
| * key is found in cmdlineP |
| * ------------------------------------------------------------------------- */ |
| Tcl_Obj *mergeLists(Tcl_Interp * interp, Tcl_Obj * cmdlineP, |
| Tcl_Obj * staticP) |
| { |
| |
| int staticPLen = -1; |
| int cmdlinePLen = -1; |
| int i = -1; |
| int j = -1; |
| Tcl_Obj *res = NULL; |
| Tcl_Obj *key1 = NULL; |
| Tcl_Obj *key2 = NULL; |
| Tcl_Obj *val = NULL; |
| int keyOnCmdLine = TCL_ERROR; |
| |
| if ((staticP == NULL) || (cmdlineP == NULL)) |
| return NULL; |
| |
| staticPLen = tclGetListLength(interp, staticP); |
| cmdlinePLen = tclGetListLength(interp, cmdlineP); |
| |
| if ((staticPLen % 2) != 0) { |
| |
| LOG_MSG(interp, WRITE_LOG | SET_RESULT, __FILE__, __LINE__, |
| "web::cmdurl", WEBLOG_INFO, |
| "key-value list \"", Tcl_GetString(staticP), |
| "\" must be even-numbered", NULL); |
| return NULL; |
| } |
| |
| if ((cmdlinePLen % 2) != 0) { |
| |
| LOG_MSG(interp, WRITE_LOG | SET_RESULT, __FILE__, __LINE__, |
| "web::cmdurl", WEBLOG_INFO, |
| "key-value list \"", Tcl_GetString(cmdlineP), |
| "\" must be even-numbered", NULL); |
| return NULL; |
| } |
| |
| res = Tcl_NewObj(); |
| Tcl_IncrRefCount(res); |
| |
| for (i = 0; i < staticPLen; i += 2) { |
| |
| key1 = NULL; |
| key2 = NULL; |
| val = NULL; |
| |
| if (Tcl_ListObjIndex(interp, staticP, i, &key1) == TCL_ERROR) { |
| Tcl_DecrRefCount(res); |
| return NULL; |
| } |
| |
| keyOnCmdLine = TCL_ERROR; |
| |
| for (j = 0; j < cmdlinePLen; j += 2) { |
| |
| if (Tcl_ListObjIndex(interp, cmdlineP, j, &key2) == TCL_ERROR) { |
| Tcl_DecrRefCount(res); |
| return NULL; |
| } |
| |
| if (strcmp(Tcl_GetString(key1), Tcl_GetString(key2)) == 0) { |
| |
| keyOnCmdLine = TCL_OK; |
| break; |
| } |
| } |
| |
| if (keyOnCmdLine == TCL_ERROR) { |
| |
| if (Tcl_ListObjIndex(interp, staticP, i + 1, &val) == TCL_ERROR) { |
| Tcl_DecrRefCount(res); |
| return NULL; |
| } |
| |
| if (Tcl_ListObjAppendElement(interp, res, key1) == TCL_ERROR) { |
| Tcl_DecrRefCount(res); |
| return NULL; |
| } |
| |
| if (Tcl_ListObjAppendElement(interp, res, val) == TCL_ERROR) { |
| Tcl_DecrRefCount(res); |
| return NULL; |
| } |
| } |
| } |
| |
| return res; |
| } |
| |
| /* ---------------------------------------------------------------------------- |
| * createQueryList -- put elements of query_string together to form a list |
| * - cmd may be NULL. In this case it is ignored. |
| * - plist may be NULL. In this case it is ignored. |
| * ------------------------------------------------------------------------- */ |
| Tcl_Obj *createQueryList(Tcl_Interp * interp, Tcl_Obj * cmd, Tcl_Obj * plist, |
| UrlData * urlData, int flag) |
| { |
| |
| Tcl_Obj *qStr = NULL; |
| Tcl_Obj *tmp = NULL; |
| int errCnt = 0; |
| |
| if (urlData == NULL) |
| return NULL; |
| |
| errCnt = 0; |
| qStr = Tcl_NewObj(); |
| |
| if (qStr == NULL) |
| return NULL; |
| |
| Tcl_IncrRefCount(qStr); |
| |
| if (plist != NULL) |
| if (Tcl_ListObjAppendList(interp, qStr, plist) == TCL_ERROR) |
| errCnt++; |
| |
| /* .......................................................................... |
| * append static params |
| * ....................................................................... */ |
| if (urlData->requestData != NULL) { |
| |
| if (urlData->requestData->staticList != NULL) { |
| |
| tmp = paramListAsListObj(urlData->requestData->staticList); |
| |
| /* ---------------------------------------------------------------------- |
| * merge |
| * ------------------------------------------------------------------- */ |
| if (plist != NULL) { |
| |
| Tcl_Obj *tmp2 = NULL; |
| tmp2 = mergeLists(interp, plist, tmp); |
| |
| if (tmp2 == NULL) { |
| |
| LOG_MSG(interp, WRITE_LOG | SET_RESULT, __FILE__, |
| __LINE__, "web::cmdurl", WEBLOG_INFO, |
| "error mergings parameters from cmdline ", |
| "and static parameters. Details: ", |
| Tcl_GetStringResult(interp), NULL); |
| |
| Tcl_DecrRefCount(qStr); |
| return NULL; |
| } |
| |
| Tcl_DecrRefCount(tmp); |
| tmp = tmp2; |
| } |
| |
| if (Tcl_ListObjAppendList(interp, qStr, tmp) == TCL_ERROR) |
| errCnt++; |
| |
| Tcl_DecrRefCount(tmp); |
| |
| } |
| } |
| |
| /* After appending each element in elemListPtr, |
| * Tcl_ListObjAppendList increments the element's reference count |
| * since listPtr now also refers to it. For the same reason, |
| * Tcl_ListObjAppendElement increments objPtr's reference count. If |
| * no error occurs, the two procedures return TCL_OK after appending |
| * the objects. */ |
| |
| /* .......................................................................... |
| * append command tag |
| * ....................................................................... */ |
| if (cmd != NULL) { |
| if ((flag & WEB_URL_NOCMD) == 0) { |
| if (urlData->requestData != NULL) |
| if (urlData->requestData->cmdTag != NULL) |
| if (Tcl_ListObjAppendElement(interp, qStr, |
| urlData->requestData->cmdTag) |
| == TCL_ERROR) |
| errCnt++; |
| if (errCnt < 1) |
| if (Tcl_ListObjAppendElement(interp, qStr, cmd) == TCL_ERROR) |
| errCnt++; |
| } |
| } |
| |
| /* .......................................................................... |
| * append time |
| * ....................................................................... */ |
| if ((flag & WEB_URL_NOTIMESTAMP) == 0) { |
| if (urlData->requestData != NULL) |
| if (urlData->requestData->timeTag != NULL) |
| if (Tcl_ListObjAppendElement(interp, qStr, |
| urlData->requestData->timeTag) |
| == TCL_ERROR) |
| errCnt++; |
| if (errCnt < 1) |
| if (Tcl_ListObjAppendElement |
| (interp, qStr, Tcl_NewLongObj(time(NULL))) == TCL_ERROR) |
| errCnt++; |
| } |
| |
| /* .......................................................................... |
| * finish |
| * ....................................................................... */ |
| if (errCnt > 0) { |
| |
| Tcl_DecrRefCount(qStr); |
| return NULL; |
| } |
| |
| return qStr; |
| } |
| |
| |
| /* ---------------------------------------------------------------------------- |
| * Web_CmdUrl -- url generation |
| * ------------------------------------------------------------------------- */ |
| int Web_CmdUrl(ClientData clientData, |
| Tcl_Interp * interp, int objc, Tcl_Obj * CONST objv[]) |
| { |
| |
| static TCLCONST char *params[] = { "-urlformat", |
| "-notimestamp", NULL |
| }; |
| enum params |
| { URLFORMAT, |
| NOTIMESTAMP |
| }; |
| int Nparams[] = { 1, 0 }; |
| |
| int iCurArg = 0; |
| UrlData *urlData = NULL; |
| Tcl_Obj *plist = NULL; |
| Tcl_Obj *cmd = NULL; |
| Tcl_Obj *qStrList = NULL; |
| int plistLen = 0; |
| int i = 0; |
| int flag = 0; |
| int bool = 1; |
| int urlformat = 0; |
| Tcl_Obj *urlFmt = NULL; |
| Tcl_Obj *res = NULL; |
| |
| /* -------------------------------------------------------------------------- |
| * internal data ? |
| * ----------------------------------------------------------------------- */ |
| WebAssertData(interp, clientData, "Web_CmdUrl", TCL_ERROR) |
| urlData = (UrlData *) clientData; |
| |
| /* make sure we have request data */ |
| if (requestFillRequestValues(interp, urlData->requestData) == TCL_ERROR) |
| return TCL_ERROR; |
| |
| |
| /* -------------------------------------------------------------------------- |
| * first arg is cmd |
| * ----------------------------------------------------------------------- */ |
| iCurArg = argIndexOfFirstArg(objc, objv, params, Nparams); |
| if ((objc - iCurArg) < 1) { |
| Tcl_WrongNumArgs(interp, 1, objv, "cmdName"); |
| return TCL_ERROR; |
| } |
| if (Tcl_GetCharLength(objv[iCurArg]) > 0) { |
| cmd = objv[iCurArg]; |
| } |
| iCurArg++; |
| |
| /* -------------------------------------------------------------------------- |
| * any params we don't accept ? |
| * ----------------------------------------------------------------------- */ |
| WebAssertArgs(interp, objc, objv, params, i, -1); |
| |
| /* -------------------------------------------------------------------------- |
| * check for flags |
| * ----------------------------------------------------------------------- */ |
| urlformat = urlData->urlformat; |
| if ((urlFmt = argValueOfKey(objc, objv, (char *)params[URLFORMAT])) != NULL) { |
| |
| urlformat = parseUrlFormat(interp, urlFmt); |
| |
| if (urlformat == 0) |
| return TCL_ERROR; |
| } |
| |
| if (argIndexOfKey(objc, objv, (char *)params[NOTIMESTAMP]) > 0) |
| flag = (flag | WEB_URL_NOTIMESTAMP); |
| |
| Tcl_GetBooleanFromObj(interp, urlData->requestData->cmdUrlTimestamp, &bool); |
| if (bool == 0) |
| flag = (flag | WEB_URL_NOTIMESTAMP); |
| |
| /* -------------------------------------------------------------------------- |
| * do we need to create a querystring ? |
| * ----------------------------------------------------------------------- */ |
| if ((urlformat & WEB_URL_WITH_QUERYSTRING) != 0) { |
| |
| if (urlData->querystring != NULL) { |
| /* take the one which was configured in web::cmdurlcfg */ |
| qStrList = Tcl_DuplicateObj(urlData->querystring); |
| Tcl_IncrRefCount(qStrList); |
| |
| } |
| else { |
| /* create a new one */ |
| |
| /* --------------------------------------------------------------------- |
| * create query_string |
| * ------------------------------------------------------------------ */ |
| switch (objc - iCurArg) { |
| case 0: |
| /* ................................................................... |
| * web::cmdurl [options] cmd |
| * ................................................................ */ |
| qStrList = createQueryList(interp, cmd, NULL, urlData, flag); |
| break; |
| case 1: |
| /* ................................................................... |
| * web::cmdurl [options] cmd list |
| * ................................................................ */ |
| if ((plistLen = |
| tclGetListLength(interp, objv[iCurArg])) == -1) |
| return TCL_ERROR; |
| if ((plistLen % 2) != 0) { |
| LOG_MSG(interp, WRITE_LOG | SET_RESULT, __FILE__, |
| __LINE__, "web::cmdurl", WEBLOG_INFO, |
| "key-value list \"", Tcl_GetString(objv[iCurArg]), |
| "\" must be even-numbered", NULL); |
| return TCL_ERROR; |
| } |
| qStrList = |
| createQueryList(interp, cmd, objv[iCurArg], urlData, |
| flag); |
| break; |
| default: |
| /* ................................................................ |
| * web::cmdurl [options] "" k1 v1 ... kn vn |
| * ................................................................ */ |
| if (((objc - iCurArg) % 2) != 0) { |
| LOG_MSG(interp, WRITE_LOG | SET_RESULT, __FILE__, |
| __LINE__, "web::cmdurl", WEBLOG_INFO, |
| "key without the matching value (uneven list), starting at \"", |
| Tcl_GetString(objv[iCurArg]), "\"", NULL); |
| return TCL_ERROR; |
| } |
| plist = Tcl_NewObj(); |
| if (plist == NULL) |
| return TCL_ERROR; |
| Tcl_IncrRefCount(plist); |
| for (i = iCurArg; i < objc; i += 2) { |
| if (Tcl_ListObjAppendElement(interp, plist, objv[i]) == |
| TCL_ERROR) { |
| Tcl_DecrRefCount(plist); |
| return TCL_ERROR; |
| } |
| if (Tcl_ListObjAppendElement(interp, plist, objv[i + 1]) |
| == TCL_ERROR) { |
| Tcl_DecrRefCount(plist); |
| return TCL_ERROR; |
| } |
| } |
| qStrList = createQueryList(interp, cmd, plist, urlData, flag); |
| Tcl_DecrRefCount(plist); |
| } |
| |
| /* ------------------------------------------------------------------ |
| * crypt |
| * ------------------------------------------------------------------ */ |
| if (doencrypt(interp, qStrList, 1) != TCL_OK) { |
| |
| LOG_MSG(interp, WRITE_LOG, __FILE__, __LINE__, |
| "web::cmdurl", WEBLOG_ERROR, |
| "error encrypting \"", Tcl_GetString(qStrList), "\"", |
| NULL); |
| if (qStrList != NULL) |
| Tcl_DecrRefCount(qStrList); |
| return TCL_ERROR; |
| |
| } else { |
| |
| if (qStrList != NULL) |
| Tcl_DecrRefCount(qStrList); |
| qStrList = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); |
| Tcl_IncrRefCount(qStrList); |
| Tcl_ResetResult(interp); |
| } |
| } |
| } |
| |
| /* ========================================================================== |
| * url (stuff before query_string) |
| * ======================================================================= */ |
| res = Tcl_NewObj(); |
| Tcl_IncrRefCount(res); |
| |
| if ((urlformat & WEB_URL_WITH_SCHEME) != 0) { |
| if (urlData->defaultscheme != NULL) { |
| Tcl_AppendObjToObj(res, urlData->defaultscheme); |
| Tcl_AppendToObj(res, WEBURL_SCHEME_SEP, -1); |
| } else { |
| Tcl_Obj *schemeObj = NULL; |
| char *scheme = NULL; |
| if( urlData->requestData != NULL ) { |
| schemeObj = paramListGetObjectByString(interp, urlData->requestData->request, "HTTPS"); |
| if (schemeObj != NULL) { |
| Tcl_IncrRefCount(schemeObj); |
| scheme = Tcl_GetString(schemeObj); |
| } |
| } |
| /* scheme detection: HTTPS variable can be upper case too |
| (e.g. on Sunone) */ |
| if (scheme != NULL && !STRCASECMP(scheme, "on")) { |
| Tcl_AppendToObj(res, WEB_SECURE_SCHEME, -1); |
| Tcl_AppendToObj(res, WEBURL_SCHEME_SEP, -1); |
| } else { |
| Tcl_AppendToObj(res,WEB_DEFAULT_SCHEME, -1); |
| Tcl_AppendToObj(res, WEBURL_SCHEME_SEP, -1); |
| } |
| if (schemeObj != NULL) |
| Tcl_DecrRefCount(schemeObj); |
| } |
| } |
| |
| if ((urlformat & WEB_URL_WITH_HOST) != 0) { |
| Tcl_Obj *host = NULL; |
| /* try to get requested host */ |
| WEB_URL_GETFROMREQDATA(host, "HTTP_HOST", 0); |
| if (host == NULL) { |
| /* fall back use server name */ |
| WEB_URL_GETFROMREQDATA(host, "SERVER_NAME", 0); |
| } |
| if (host != NULL) { |
| char *hostname = Tcl_GetString(host); |
| char *colon = hostname; |
| size_t pos = 0; |
| size_t len = strlen(hostname); |
| Tcl_IncrRefCount(host); |
| |
| for (; pos < len; pos++) { |
| if (*colon++ == ':') { |
| break; |
| } |
| } |
| Tcl_AppendToObj(res, WEBURL_HOST_SEP, -1); |
| |
| if (pos < len) { |
| /* only insert up to colon */ |
| Tcl_AppendToObj(res, hostname, pos); |
| } else { |
| Tcl_AppendObjToObj(res, host); |
| /* reset colon */ |
| } |
| Tcl_DecrRefCount(host); |
| } |
| } |
| |
| if ((urlformat & WEB_URL_WITH_PORT) != 0) { |
| Tcl_Obj *port = NULL; |
| |
| /* To get the Port, try the following: |
| 1. Take port explicitly configured in Websh if available |
| 2. Take port from HTTP_HOST or SERVER_NAME if available |
| 3. Take port from SERVER_PORT if available |
| 4. Take default port (fallback) |
| */ |
| |
| if (urlData->port != NULL) { |
| port = urlData->port; |
| Tcl_IncrRefCount(port); |
| } |
| |
| if (port == NULL) { |
| /* nothign found yet */ |
| /* try to get requested host */ |
| Tcl_Obj *host = NULL; |
| WEB_URL_GETFROMREQDATA(host, "HTTP_HOST", 1); |
| if (host == NULL) { |
| /* fall back use server name */ |
| WEB_URL_GETFROMREQDATA(host, "SERVER_NAME", 1); |
| } |
| if (host != NULL) { |
| char *hostname = Tcl_GetString(host); |
| char *colon = hostname; |
| size_t pos = 0; |
| size_t len = strlen(hostname); |
| Tcl_IncrRefCount(host); |
| |
| for (; pos < len; pos++) { |
| if (*colon++ == ':') { |
| break; |
| } |
| } |
| |
| if (pos < len) { |
| /* colon points to port */ |
| port = Tcl_NewStringObj(colon, -1); |
| Tcl_IncrRefCount(port); |
| } |
| Tcl_DecrRefCount(host); |
| } |
| } |
| |
| if (port == NULL) { |
| /* still nothing found */ |
| WEB_URL_GETFROMREQDATA(port, "SERVER_PORT", 0); |
| if (port != NULL) { |
| Tcl_IncrRefCount(port); |
| } |
| } |
| |
| Tcl_AppendToObj(res, WEBURL_PORT_SEP, -1); |
| if (port != NULL) { |
| /* found one */ |
| Tcl_AppendObjToObj(res, port); |
| Tcl_DecrRefCount(port); |
| } else { |
| /* output the default port */ |
| Tcl_AppendToObj(res, WEB_DEFAULT_PORT, -1); |
| } |
| } |
| |
| if ((urlformat & WEB_URL_WITH_SCRIPTNAME) != 0) { |
| Tcl_Obj *scriptname = NULL; |
| WEB_URL_GETFROMREQDATA(scriptname, "SCRIPT_NAME", 0); |
| if (scriptname != NULL) { |
| Tcl_IncrRefCount(scriptname); |
| Tcl_AppendObjToObj(res, scriptname); |
| Tcl_DecrRefCount(scriptname); |
| } |
| } |
| |
| if ((urlformat & WEB_URL_WITH_PATHINFO) != 0) { |
| Tcl_Obj *pathinfo = NULL; |
| WEB_URL_GETFROMREQDATA(pathinfo, "PATH_INFO", 0); |
| if (pathinfo != NULL) { |
| Tcl_IncrRefCount(pathinfo); |
| Tcl_AppendObjToObj(res, pathinfo); |
| Tcl_DecrRefCount(pathinfo); |
| } |
| } |
| |
| if ((urlformat & WEB_URL_WITH_QUERYSTRING) != 0) { |
| if (qStrList != NULL) { |
| Tcl_AppendToObj(res, WEBURL_QUERY_STRING_SEP, -1); |
| Tcl_AppendObjToObj(res, qStrList); |
| } |
| } |
| if (qStrList != NULL) { |
| Tcl_DecrRefCount(qStrList); |
| } |
| |
| Tcl_SetObjResult(interp, res); |
| Tcl_DecrRefCount(res); |
| |
| return TCL_OK; |
| } |
| |
| /* ---------------------------------------------------------------------------- |
| * Web_CmdUrlCfg -- configuration of url generation |
| * syntax: web::cmdurlcfg get|set|add|delete tag|param [key] [value] [default] |
| * param -- manage static parameters which are appended to |
| * every query_string |
| * set - set entry with name "key" to "value", |
| * overwriting any existing |
| * add - append "value" to entry with name "key" (entry is a list) |
| * del - delete entry with name "key" |
| * get - return list from entry with name "key" |
| * or list of keys, if now key is given, or "default", if |
| * no entry with name "key" exists |
| * tag -- manage tags for special entries in query_string. Syntax as above, |
| * except that "add" is mapped to "set", since tags must be |
| * single-valued lists. |
| * For the same reason, "del" is not implemented. |
| * Needed tags are: session-id, command, time |
| * Defaults are: |
| * session-id: id |
| * command: cmd |
| * time: t |
| * ------------------------------------------------------------------------- */ |
| int Web_CmdUrlCfg(ClientData clientData, |
| Tcl_Interp * interp, int objc, Tcl_Obj * CONST objv[]) |
| { |
| |
| UrlData *urlData = NULL; |
| /* note: this could be dynamic, but 20 is enough ... */ |
| char *params[20]; |
| int i; |
| int res; |
| |
| for (i = SCHEME; i <= QUERYSTRING; i++) |
| params[i] = (char *) urlElementOpts[i]; |
| |
| params[URLCFGRESET] = "-reset"; |
| params[URLCFGURLFORMAT] = "-urlformat"; |
| params[URLCFGEND] = NULL; |
| |
| |
| /* -------------------------------------------------------------------------- |
| * |
| * ----------------------------------------------------------------------- */ |
| WebAssertData(interp, clientData, "Web_CmdUrlCfg", TCL_ERROR) |
| urlData = (UrlData *) clientData; |
| |
| /* -------------------------------------------------------------------------- |
| * |
| * ----------------------------------------------------------------------- */ |
| |
| res = paramGet((ParamList *) urlData->requestData->staticList, |
| interp, objc, objv, 1); |
| |
| if (res == TCL_CONTINUE) { |
| int opt; |
| Tcl_Obj *tmpObj = NULL; |
| |
| if (objc <= 1) { |
| Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?"); |
| return TCL_ERROR; |
| } |
| |
| if (paramGetIndexFromObj |
| (interp, objv[1], params, "subcommand", 0, &opt) == TCL_ERROR) |
| return TCL_ERROR; |
| |
| /* ---------------------------------------------------------------------- |
| * it is one of my options |
| * -------------------------------------------------------------------- */ |
| |
| /* ---------------------------------------------------------------------- |
| * web::cmdurlcfg -protocol value |
| * 0 1 2 |
| * ------------------------------------------------------------------- */ |
| if (objc == 3) |
| tmpObj = objv[2]; |
| else |
| tmpObj = NULL; |
| |
| switch ((enum urlElement) opt) { |
| case SCHEME: |
| WebAssertObjc(objc > 3, 2, "?value?"); |
| if (urlData->defaultscheme != NULL) { |
| Tcl_SetObjResult(interp, |
| Tcl_DuplicateObj(urlData->defaultscheme)); |
| if (tmpObj != NULL) { |
| Tcl_DecrRefCount(urlData->defaultscheme); |
| urlData->defaultscheme = Tcl_DuplicateObj(tmpObj); |
| Tcl_IncrRefCount(urlData->defaultscheme); |
| } |
| return TCL_OK; |
| } else { |
| Tcl_SetObjResult(interp, |
| Tcl_NewStringObj(WEB_DEFAULT_SCHEME, -1)); |
| if (tmpObj != NULL) { |
| if (strcmp(Tcl_GetString(tmpObj), "")) { |
| urlData->defaultscheme = Tcl_DuplicateObj(tmpObj); |
| Tcl_IncrRefCount(urlData->defaultscheme); |
| } |
| } |
| return TCL_OK; |
| } |
| break; |
| case HOST: |
| WebAssertObjc(objc > 3, 2, "?value?"); |
| return handleConfig(interp, &urlData->host, tmpObj, 1); |
| break; |
| case PORT: |
| WebAssertObjc(objc > 3, 2, "?value?"); |
| return handleConfig(interp, &urlData->port, tmpObj, 1); |
| break; |
| case SCRIPTNAME: |
| WebAssertObjc(objc > 3, 2, "?value?"); |
| return handleConfig(interp, &urlData->scriptname, tmpObj, 1); |
| break; |
| case PATHINFO: |
| WebAssertObjc(objc > 3, 2, "?value?"); |
| return handleConfig(interp, &urlData->pathinfo, tmpObj, 1); |
| break; |
| case QUERYSTRING: |
| WebAssertObjc(objc > 3, 2, "?value?"); |
| return handleConfig(interp, &urlData->querystring, tmpObj, 1); |
| break; |
| case URLCFGRESET: |
| WebAssertObjc(objc != 2, 2, NULL); |
| return resetUrlData(interp, urlData); |
| break; |
| case URLCFGURLFORMAT:{ |
| int urlformat = 0; |
| Tcl_Obj *res = NULL; |
| Tcl_Obj *tmpres = NULL; |
| enum urlElement i; |
| WebAssertObjc(objc > 3, 2, "?value?"); |
| /* format current */ |
| res = Tcl_NewObj(); |
| Tcl_IncrRefCount(res); |
| for (i = SCHEME; i <= QUERYSTRING; i++) { |
| if (((urlData->urlformat) & urlElementFlags[i]) != 0) { |
| tmpres = |
| Tcl_NewStringObj(&(urlElementOpts[i][1]), -1); |
| Tcl_ListObjAppendElement(interp, res, tmpres); |
| } |
| } |
| |
| if (tmpObj != NULL) { |
| /* we have to set it as well */ |
| urlformat = parseUrlFormat(interp, tmpObj); |
| if (urlformat == 0) { |
| /* cleanup */ |
| Tcl_DecrRefCount(res); |
| return TCL_ERROR; |
| } |
| urlData->urlformat = urlformat; |
| } |
| Tcl_SetObjResult(interp, res); |
| Tcl_DecrRefCount(res); |
| return TCL_OK; |
| break; |
| } |
| default: |
| LOG_MSG(interp, WRITE_LOG | SET_RESULT, __FILE__, __LINE__, |
| "web::cmdurl", WEBLOG_INFO, "unknown option", NULL); |
| return TCL_ERROR; |
| } |
| } |
| return res; |
| } |