int Web_CmdUrl()

in src/generic/url.c [480:817]


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