int RequestVars::getReqVar( HttpSession *pSession, int type, char * &pValue, int bufLen)
{
    HttpReq * pReq = pSession->getReq();
    int i;
    char *p;
    if ( type < REF_STRING )
    {
        pValue = (char *)pReq->getHeader( type );
        if ( *pValue )
            return pReq->getHeaderLen( type );
        else
            return 0;
    }
    switch( type )
    {
    case REF_REMOTE_HOST:
        //FIXME: use remote addr for now
    case REF_REMOTE_ADDR:
        pValue = (char *)pSession->getPeerAddrString();
        return pSession->getPeerAddrStrLen();
    case REF_REMOTE_PORT:
        return snprintf( pValue, bufLen, "%hu", pSession->getRemotePort() );
    case REF_REMOTE_USER:
        pValue = (char *)pReq->getAuthUser();
        return strlen( pValue );
    case REF_REMOTE_IDENT:
        //do not support;
        return 0;
    case REF_REQ_METHOD:
        i = pReq->getMethod();
        strcpy(pValue, HttpMethod::get( i ) );
        return HttpMethod::getLen( i );
    case REF_QUERY_STRING:
        pValue = (char *)pReq->getQueryString();
        return pReq->getQueryStringLen();
    case REF_AUTH_TYPE:
        //FIXME: hard code for now
        strncpy( pValue, "Basic", 6 );
        return 5;
    case REF_REQUST_FN:
    case REF_SCRIPTFILENAME:
    case REF_SCRIPT_BASENAME:
    case REF_REQ_BASENAME: 
    {
        const AutoStr2 * psTemp = pReq->getRealPath();
        if ( psTemp )
        {
            if (( type == REF_SCRIPT_BASENAME )||
                ( type == REF_REQ_BASENAME ))
            {
                const char * pEnd = psTemp->c_str() + psTemp->len();
                pValue = (char *)pEnd;
                while( pValue[-1] != '/' )
                    --pValue;
                return pEnd - pValue;
            }
            pValue = (char *)psTemp->c_str();
            return psTemp->len();
        }
        else
            return 0;
    }
    case REF_SCRIPT_UID:
    case REF_SCRIPT_GID:
    case REF_SCRIPT_USERNAME:
    case REF_SCRIPT_GRPNAME:
    case REF_SCRIPT_MODE:
    {
        const AutoStr2 * psTemp = pReq->getRealPath();
        if ( psTemp )
        {
            struct stat& st = pReq->getFileStat();
            if ( type == REF_SCRIPT_UID )
            {
                return snprintf( pValue, bufLen, "%d", st.st_uid );
            }
            else if ( type == REF_SCRIPT_GID )
            {
                return snprintf( pValue, bufLen, "%d", st.st_gid );
            }
            else if ( type == REF_SCRIPT_MODE )
            {
                return snprintf( pValue, bufLen, "%o", st.st_mode );
            }
            else if ( type == REF_SCRIPT_USERNAME )
            {
                struct passwd * pw = getpwuid( st.st_uid );
                if ( pw )
                    return snprintf( pValue, bufLen, "%s", pw->pw_name );
            }
            else
            {
                struct group * gr = getgrgid( st.st_gid );
                if ( gr )
                    return snprintf( pValue, bufLen, "%s", gr->gr_name );
            }
        }
        return 0;
    }
    case REF_PATH_INFO:
        pValue = (char *)pReq->getPathInfo();
        return pReq->getPathInfoLen();

    case REF_SCRIPT_NAME:
        pValue = (char *)pReq->getURI();
        return pReq->getScriptNameLen();
    case REF_SCRIPT_URI:
        p = pValue;
        if ( pSession->isSSL() )
        {
            strcpy( p, "https://" );
            p += 8;
        }
        else
        {
            strcpy( p, "http://" );
            p += 7;
        }
        i = pReq->getHeaderLen( HttpHeader::H_HOST );
        memmove( p, pReq->getHeader( HttpHeader::H_HOST ), 
                    i );
        p += i;

        i = pReq->getOrgURILen();
        memmove( p, pReq->getOrgURI(), i );
        p += i;
        return p - pValue;

    case REF_ORG_REQ_URI:
        pValue = (char *)pReq->getOrgReqURL();
        return pReq->getOrgReqURILen();
    case REF_DOCUMENT_URI:
        return pReq->getDecodedOrgReqURI( pValue );
    case REF_REQ_URI:
        pValue = (char *)pReq->getOrgReqURL();
        return pReq->getOrgReqURLLen();

    case REF_DOC_ROOT:
        pValue = (char *)pReq->getDocRoot()->c_str();
        return pReq->getDocRoot()->len()-1;

    case REF_SERVER_ADMIN:
        if ( pReq->getVHost() )
        {
            const AutoStr2 * pEmail = pReq->getVHost()->getAdminEmails();
            pValue = (char *)pEmail->c_str();
            return pEmail->len();
        }
        return 0;
    case REF_VH_CNAME:
        if ( pReq->getVHost() )
        {
            pValue = (char *)pReq->getVHost()->getVhName( i );
            return i;
        }
        return 0;

    case REF_SERVER_NAME:
        pValue = (char *)pReq->getHostStr();
        return pReq->getHostStrLen();
    case REF_SERVER_ADDR:
        pValue = (char *)pReq->getLocalAddrStr()->c_str();
        return pReq->getLocalAddrStr()->len();
    case REF_SERVER_PORT:
        pValue = (char *)pReq->getPortStr().c_str();
        return pReq->getPortStr().len();
    case REF_SERVER_PROTO:
        i = pReq->getVersion();
        pValue = (char *)HttpVer::getVersionString( i );
        return HttpVer::getVersionStringLen( i );
    case REF_SERVER_SOFT:
        pValue = (char *)HttpServerVersion::getVersion();
        return HttpServerVersion::getVersionLen();
    case REF_REQ_LINE:
        pValue = (char *)pReq->getOrgReqLine();
        return pReq->getOrgReqLineLen();
    case REF_IS_SUBREQ:
        strcpy( pValue, "false" );
        return 5;

    case REF_RESP_BYTES:
        i = StringTool::str_off_t( pValue, bufLen, pSession->getResp()->getBodySent() );
        return i;
    //case REF_COOKIE_VAL
    //case REF_STRFTIME        155
    //case REF_CONN_STATE:
    case REF_REQ_TIME_MS:
    {
        struct timeval tv;
        gettimeofday( &tv, NULL );
        DateTime::s_curTime = tv.tv_sec;
        DateTime::s_curTimeUs = tv.tv_usec;

        long lReqTime =  (DateTime::s_curTime - pSession->getReqTime())*1000000 +
                    (DateTime::s_curTimeUs - pSession->getReqTimeUs());
        i = snprintf( pValue, bufLen, "%ld", lReqTime );
        return i;
    }
    case REF_REQ_TIME_SEC:
        i = snprintf( pValue, bufLen, "%ld",
                    (DateTime::s_curTime - pSession->getReqTime()) );
        return i;
    case REF_DUMMY:
        return 0;
    case REF_PID:
        i = snprintf( pValue, bufLen, "%d", getpid() );
        return i;
    case REF_STATUS_CODE:
        memmove( pValue, HttpStatusCode::getCodeString( pReq->getStatusCode() )+1, 3 );
        pValue[3] = 0;
        return 3;
    
    case REF_CUR_URI:
        pValue = (char *)pReq->getURI();
        i = pReq->getURILen();
        return i;
    case REF_BYTES_IN:
        i = StringTool::str_off_t( pValue, bufLen, pSession->getBytesRecv() );
        return i;
    case REF_BYTES_OUT:
        i = StringTool::str_off_t( pValue, bufLen, pSession->getBytesSent() );
        return i;

    case REF_HTTPS:
        i = snprintf( pValue, bufLen, "%s", pSession->isSSL()?"on":"off" );
        return i;

    case REF_DATE_GMT:
    case REF_DATE_LOCAL:
    case REF_LAST_MODIFIED:
    {
        time_t mtime = DateTime::s_curTime;
        struct tm * tm;
        if ( type == REF_LAST_MODIFIED )
        {
            if ( pReq->getSSIRuntime() && pReq->getSSIRuntime()->getCurrentScript() )
            {
                mtime = pReq->getSSIRuntime()->getCurrentScript()->getLastMod();
            }
            else
                mtime = pReq->getFileStat().st_mtime;
        }
        if ( type == REF_DATE_GMT )
            tm = gmtime( &mtime );
        else
            tm = localtime( &mtime );
        char fmt[101]; 
        memccpy( fmt, pValue, 0, 100 );
        fmt[100] = 0;
        i = strftime( pValue, bufLen, fmt, tm );
        return i;
    } 
    case REF_DOCUMENT_NAME:
    {
        const AutoStr2 * psTemp = pReq->getRealPath();
        if ( psTemp )
        {
            pValue = (char *)psTemp->c_str() + psTemp->len();
            while( *(pValue -1) != '/' )
                --pValue;
            return psTemp->c_str() + psTemp->len() - pValue;
        }
        else
            return 0;
    }

    case REF_QS_UNESCAPED:
    {
        int qsLen = pReq->getQueryStringLen();
        const char * pQS = pReq->getQueryString();
        if ( qsLen > 0 )
        {
            qsLen = HttpUtil::unescape_n( pQS, qsLen, pValue, bufLen );
        }
        return qsLen;
    }
    case REF_RESP_CONTENT_TYPE:
        i = 0;
        pValue = (char*)pSession->getResp()->getContentTypeHeader( i );
        return i;
    case REF_RESP_CONTENT_LENGTH:
    {   off_t l = pSession->getResp()->getContentLen();
        if ( l <= 0 )
            l = 0;
        i = StringTool::str_off_t( pValue, bufLen, l );
        return i;
    }
    case REF_RESP_BODY:
        return 0;
    default:
        if ( type >= REF_TIME )
        {
            time_t t = time(NULL);
            struct tm *tm = localtime(&t);
            switch( type )
            {
            case REF_TIME:
                i = snprintf( pValue, bufLen,
                            "%04d%02d%02d%02d%02d%02d", tm->tm_year + 1900,
                            tm->tm_mon+1, tm->tm_mday,
                            tm->tm_hour, tm->tm_min, tm->tm_sec);
                break;
            case REF_TIME_YEAR:
                i = snprintf( pValue, bufLen, "%04d", tm->tm_year + 1900);
                break;
            case REF_TIME_MON:
                i = snprintf( pValue, bufLen, "%02d", tm->tm_mon+1 );
                break;
            case REF_TIME_DAY:
                i = snprintf( pValue, bufLen, "%02d", tm->tm_mday);
                break;
            case REF_TIME_HOUR:
                i = snprintf( pValue, bufLen, "%02d", tm->tm_hour);
                break;
            case REF_TIME_MIN:
                i = snprintf( pValue, bufLen, "%02d", tm->tm_min);
                break;
            case REF_TIME_SEC:
                i = snprintf( pValue, bufLen, "%02d", tm->tm_sec);
                break;
            case REF_TIME_WDAY:
                i = snprintf( pValue, bufLen, "%d", tm->tm_wday);
                break;
            default:
                return 0;
            }
            return i;
        }
        return 0;
    }
    return 0;
    
}
int RewriteEngine::processRuleSet( const RewriteRuleList * pRuleList, HttpConnection * pConn,
            const HttpContext * pContext, const HttpContext * pRootContext )
{
    const RewriteRule * pRule = NULL;
    int loopCount = 0;
    int flag = 0;
    int ret;
    m_pContext = pContext;
    if ( pRuleList )
        pRule = pRuleList->begin();
    else
        pRule = getNextRule( NULL, pContext, pRootContext );
    if ( !pRule )
        return 0;
    HttpReq * pReq = pConn->getReq();
    const AutoStr2 * pBase = NULL;
    AutoStr2    sStrip;
    m_rewritten = 0;
    //initialize rewrite engine
    //strip prefix aka. RewriteBase
    m_logLevel = pReq->getRewriteLogLevel();
    m_pSourceURL = pReq->getURI();
    m_sourceURLLen = pReq->getURILen();
    m_pStrip = m_pBase = NULL;
    m_iScriptLen = -1;
    m_iPathInfoLen = 0;
    if ( m_pContext )
    {
        pBase = m_pContext->getContextURI();
        if (( pBase )&&
            ( strncmp( m_pSourceURL, pBase->c_str(), pBase->len() ) == 0 ))
        {
            m_pStrip = m_pBase = pBase;
        }
        else
        {
            m_pBase = pBase = m_pContext->getRewriteBase();
            if (( pBase )&&
                ( strncmp( m_pSourceURL, pBase->c_str(), pBase->len() ) == 0 ))
            {
                m_pStrip = m_pBase = pBase;
            }
            
        }
        
        if ( m_pContext->getRewriteBase() )
            m_pBase = m_pContext->getRewriteBase();
        if ( m_pStrip )
        {
            if ( m_logLevel > 4 )
                LOG_INFO(( pConn->getLogger(),
                        "[%s] [REWRITE] strip base: '%s' from URI: '%s'",
                        pConn->getLogId(), m_pStrip->c_str(), m_pSourceURL ));
            m_pSourceURL += m_pStrip->len();
            m_sourceURLLen -= m_pStrip->len();
        }
        else
        {
            if ( pConn->getReq()->isMatched() )
            {
                const char * pURL;
                int len;
                pConn->getReq()->stripRewriteBase( m_pContext,
                    pURL, len );
                if (( len < m_sourceURLLen )&&( strncmp( 
                        m_pSourceURL + m_sourceURLLen - len, pURL, len ) == 0 ))
                {
                    sStrip.setStr( m_pSourceURL, m_sourceURLLen - len );
                    m_pStrip = &sStrip;
                    if ( !m_pBase )
                        m_pBase = m_pStrip;
                }
                m_pSourceURL = pURL;
                m_sourceURLLen = len;
            }
        }
    }

    m_pQS = pReq->getQueryString();
    m_qsLen = pReq->getQueryStringLen();

    m_pOrgSourceURL = m_pSourceURL;
    m_orgSourceURLLen = m_sourceURLLen;

    m_condMatches = 0;
    m_pDestURLLen = 0;
    m_pDestURL = m_rewriteBuf[0];
    m_pCondBuf = m_rewriteBuf[1];
    m_pFreeBuf = m_rewriteBuf[2];
    m_action   = RULE_ACTION_NONE;
    m_flag     = 0;
    m_statusCode = 0;
    while( pRule )
    {
        flag = pRule->getFlag();
//        if (( flag & RULE_FLAG_NOSUBREQ )&&( pReq->isSubReq() > 0 ))
//            ret = -1;
//        else
            ret = processRule( pRule, pConn );
        if ( ret )
        {
            pRule = getNextRule( pRule, pContext, pRootContext );
            while( pRule && ( flag & RULE_FLAG_CHAIN ))
            {
                if ( m_logLevel > 5 )
                    LOG_INFO(( pConn->getLogger(),
                        "[%s] [REWRITE] skip chained rule: '%s'",
                        pConn->getLogId(), pRule->getPattern() ));
                flag = pRule->getFlag();
                pRule = getNextRule( pRule, pContext, pRootContext );
                            //(const RewriteRule *) pRule->next();
            }
            continue;
        }
        if (( flag & RULE_FLAG_LAST )&&!pRule->getSkip())
        {
            if ( m_logLevel > 5 )
                LOG_INFO(( pConn->getLogger(),
                    "[%s] [REWRITE] Last Rule, stop!",
                    pConn->getLogId() ));
            if ( flag & RULE_FLAG_END )
            {
                if ( m_logLevel > 5 )
                    LOG_INFO(( pConn->getLogger(),
                        "[%s] [REWRITE] End rewrite!",
                        pConn->getLogId() ));
                pConn->getReq()->orContextState( SKIP_REWRITE );
            }
            break;
        }
NEXT_RULE:
        if ( flag & RULE_FLAG_NEXT )
        {
            pContext = m_pContext;
            if ( pRuleList )
                pRule = pRuleList->begin();
            else
                pRule = getNextRule( NULL, pContext, pRootContext );
            if ( ++loopCount > 10 )
            {
                LOG_ERR(( pConn->getLogger(),
                        "[%s] [REWRITE] Rules loop 10 times, possible infinite loop!",
                        pConn->getLogId() ));
                break;
            }
            if ( m_logLevel > 5 )
                LOG_INFO(( pConn->getLogger(),
                    "[%s] [REWRITE] Next round, restart from the first rule",
                    pConn->getLogId() ));
            continue;
        }
        if ( !pRule )
            break;
        int n = pRule->getSkip()+1;
        if (( n > 1 )&&( m_logLevel > 5 ))
            LOG_INFO(( pConn->getLogger(),
                "[%s] [REWRITE] skip next %d rules",
                pConn->getLogId(), n - 1 ));
        while( pRule && n > 0 )
        {
            pRule = getNextRule( pRule, pContext, pRootContext );
                    //(const RewriteRule *) pRule->next();
            --n;
        }
    }
    if ( m_rewritten )
    {
        if (( m_action == RULE_ACTION_FORBID )||
            ( m_action == RULE_ACTION_GONE   ))
            return m_statusCode;
        if ( m_rewritten & 2 )
        {
            //set the final URL and query string
            if ( ! isAbsoluteURI( m_pSourceURL, m_sourceURLLen ) )
            {
                if ( *m_pSourceURL != '/' )
                {
                    // add missing prefix (RewriteBase)
                    char * pBuf = m_pFreeBuf;
                    int baseLen;
                    if ( !m_pBase )
                    {
                        baseLen   = 1;
                        *pBuf = '/';
                    }
                    else
                    {
                        baseLen = m_pBase->len();
                        memmove( pBuf, m_pBase->c_str(), baseLen );
                    }
                    if ( m_sourceURLLen > REWRITE_BUF_SIZE - 1 - baseLen )
                        m_sourceURLLen = REWRITE_BUF_SIZE - 1 - baseLen;
                    memmove( pBuf + baseLen, m_pSourceURL, m_sourceURLLen );
                    m_pFreeBuf = (char *)m_pSourceURL;
                    m_pSourceURL = pBuf;
                    m_sourceURLLen += baseLen;
                    pBuf[m_sourceURLLen] = 0;
                    if (( m_logLevel > 4 )&&( m_pBase ))
                        LOG_INFO(( pConn->getLogger(),
                                "[%s] [REWRITE] prepend rewrite base: '%s', final URI: '%s'",
                                pConn->getLogId(), m_pBase->c_str(), m_pSourceURL ));
                }
            }
            else if ( m_action == RULE_ACTION_NONE )
            {
                m_action = RULE_ACTION_REDIRECT;
                m_statusCode = SC_302;
            }
            if ( m_action == RULE_ACTION_NONE )
            {
                if ( !pReq->getRedirects() || pBase)
                {
                    ret = pReq->saveCurURL();
                    if ( ret )
                        return ret;
                }
                if ( m_pQS == m_qsBuf )
                    pReq->setRewriteQueryString( m_pQS, m_qsLen );
                m_statusCode = -3;  //rewritten to another url
            }
            else if ( m_action == RULE_ACTION_REDIRECT )
            {
                if ( pReq->detectLoopRedirect( (char *)m_pSourceURL, m_sourceURLLen,
                                        m_pQS, m_qsLen, pConn->isSSL() ) == 0 )
                {
                    pReq->setRewriteLocation( (char *)m_pSourceURL, m_sourceURLLen,
                                        m_pQS, m_qsLen, m_flag & RULE_FLAG_NOESCAPE );
                    pReq->orContextState( REWRITE_REDIR );
                }
                else
                {
                    LOG_INFO(( pConn->getLogger(),
                            "[%s] [REWRITE] detect external loop redirection with target URL: %s, skip.",
                                pConn->getLogId(), m_pSourceURL ));
                    m_rewritten = m_statusCode = 0;
                    m_pSourceURL = m_pOrgSourceURL;
                    m_sourceURLLen = m_orgSourceURLLen ;

                    goto NEXT_RULE;
                }
            }
            else if ( m_action == RULE_ACTION_PROXY )
            {
                if ( strncasecmp( m_pSourceURL, "http://", 7 ) != 0 )
                {
                    LOG_ERR(( "[REWRITE] Absolute URL with leading 'http://' is "
                              "required for proxy, URL: %s", m_pSourceURL ));
                    return SC_500;
                }
                char * pHost = (char *)m_pSourceURL + 7;
                char * pHostEnd = strchr( pHost, '/' );
                if (( !pHostEnd )||(pHostEnd == pHost))
                {
                    LOG_ERR(( "[REWRITE] Can not determine proxy host name" ));
                    return SC_500;
                }
                *pHostEnd = 0;
                const HttpHandler * pHandler = HandlerFactory::getInstance(
                        HandlerType::HT_PROXY, pHost );
                if ( !pHandler )
                {
                    LOG_ERR(( "[REWRITE] Proxy target is not defined on "
                              "external application list, please add a 'web server'"
                              " with name '%s'", pHost ));
                    return SC_500;
                }
                *pHostEnd = '/';
                pReq->setHandler( pHandler );

                //FIXME: change request header
                ret = pReq->internalRedirectURI( pHostEnd, 
                        m_pSourceURL + m_sourceURLLen - pHostEnd, 0,
                        m_flag & RULE_FLAG_NOESCAPE );
                if ( ret )
                    return SC_500;

                if ( m_pQS == m_qsBuf )
                    pReq->setRewriteQueryString( m_pQS, m_qsLen );
            }
        }
        else if ( m_action == RULE_ACTION_REDIRECT )
        {
            return 0;
        }
        return m_statusCode;
    }
    return 0;
}
Example #3
0
int SSIEngine::processSubReq(HttpSession *pSession, SubstItem *pItem)
{
    char achBuf[40960];
    char *p;
    int len;
    int attr;
    if (!pItem)
        return 0;
    SSIRuntime *pRuntime = pSession->getReq()->getSSIRuntime();
    attr = pItem->getSubType();
    p = achBuf;
    len = 40960;
    switch (attr)
    {
    case SSI_INC_FILE:
        {
            HttpReq *pReq = pSession->getReq();
            memmove(p, pReq->getURI(), pReq->getURILen());
            p = p + pReq->getURILen() - pReq->getPathInfoLen();
            while (p[-1] != '/')
                --p;
            *p = 0;
            len -= p - achBuf;
            break;
        }
    case SSI_EXEC_CGI:
        pRuntime->requireCGI();
        break;
    case SSI_EXEC_CMD:
        pRuntime->requireCmd();
        p += snprintf(achBuf, 40960, "%s",
                      pRuntime->getCurrentScript()->getPath());
        while (p[-1] != '/')
            --p;
        *p++ = '&';
        *p++ = ' ';
        *p++ = '-';
        *p++ = 'c';
        *p++ = ' ';
        len -= p - achBuf;
        // make the command looks like "/script/path/& command"
        // '&' tell cgid to execute it as shell command
        break;
    }
    RequestVars::appendSubst(pItem, pSession, p, len,
                             0, pRuntime->getRegexResult());
    if (attr == SSI_INC_FILE)
    {
        if (strstr(achBuf, "/../") != NULL)

            return 0;
    }
    else if (attr == SSI_EXEC_CMD)
    {

        if (pSession->execExtCmd(achBuf, p - achBuf) == 0)
            return -2;
        else
            return 0;
        //len = snprintf( achBuf, 40960, "'exec cmd' is not available, "
        //            "use 'include virutal' instead.\n" );
        //pSession->appendDynBody( achBuf, len );

        //return 0;
    }
    if ((achBuf[0] != '/') && (attr != SSI_EXEC_CMD))
    {
        if (achBuf[0] == 0)
        {
            len = snprintf(achBuf, 40960,
                           "[an error occurred while processing this directive]\n");
            pSession->appendDynBody(achBuf, len);
            return 0;
        }
        HttpReq *pReq = pSession->getReq();
        const char *pURI = pReq->getURI();
        const char *p1 = pURI + pReq->getURILen() - pReq->getPathInfoLen();
        while ((p1 > pURI) && p1[-1] != '/')
            --p1;
        int prefix_len = p1 - pURI;
        memmove(&achBuf[prefix_len], achBuf, p - achBuf);
        memmove(achBuf, pReq->getURI(), prefix_len);
        p += prefix_len;
    }
    if (achBuf[0] == '/')
    {
        pSession->getReq()->setLocation(achBuf, p - achBuf);
        pSession->changeHandler();
        pSession->continueWrite();
        return -2;
    }
    return 0;
}