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