int RewriteEngine::getSubstValue( const RewriteSubstItem * pItem, HttpConnection *pConn, char * &pValue, int bufLen ) { HttpReq * pReq = pConn->getReq(); int type = pItem->getType(); int i; if ( type < REF_STRING ) { pValue = (char *)pReq->getHeader( type ); if ( *pValue ) return pReq->getHeaderLen( type ); else return 0; } /* 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; } */ switch( type ) { case REF_STRING: pValue = (char *)pItem->getStr()->c_str(); return pItem->getStr()->len(); case REF_MAP: { MapRefItem * pRef = pItem->getMapRef(); int len = 1024; char achBuf[1024]; if ( buildString( pRef->getKeyFormat(), pConn, achBuf, len ) == NULL ) return 0; if ( (len = pRef->getMap()->lookup( achBuf, len, pValue, bufLen )) == -1 ) { if ( pRef->getDefaultFormat() ) { if ( buildString( pRef->getDefaultFormat(), pConn, pValue, bufLen ) == NULL ) return 0; len = bufLen; } else len = 0; } return len; } break; case REF_RULE_SUBSTR: return getSubstr( m_pSourceURL, m_ruleVec, m_ruleMatches, pItem->getIndex(), pValue, m_flag & RULE_FLAG_BR_ESCAPE ); case REF_COND_SUBSTR: return getSubstr( m_pCondBuf, m_condVec, m_condMatches, pItem->getIndex(), pValue, m_flag & RULE_FLAG_BR_ESCAPE ); case REF_ENV: pValue = (char *)RequestVars::getEnv( pConn, pItem->getStr()->c_str(), pItem->getStr()->len(), i ); if ( !pValue ) { i = 0; } return i; case REF_HTTP_HEADER: pValue = (char *)pReq->getHeader( pItem->getStr()->c_str(), pItem->getStr()->len(), i ); if ( !pValue ) i = 0; return i; case REF_REQUST_FN: case REF_SCRIPTFILENAME: if ( m_iScriptLen == -1 ) { pReq->checkPathInfo( m_pSourceURL, m_sourceURLLen, m_iFilePathLen, m_iScriptLen, m_iPathInfoLen, m_pContext ); } pValue = HttpGlobals::g_achBuf; //if ( m_pStrip ) // return m_iFilePathLen; //else // return m_iFilePathLen + m_iPathInfoLen; return m_iFilePathLen; case REF_PATH_INFO: if ( m_iScriptLen == -1 ) { pReq->checkPathInfo( m_pSourceURL, m_sourceURLLen, m_iFilePathLen, m_iScriptLen, m_iPathInfoLen, m_pContext ); } pValue = &HttpGlobals::g_achBuf[ m_iFilePathLen ]; return m_iPathInfoLen; case REF_SCRIPT_NAME: if ( m_iScriptLen == -1 ) { pReq->checkPathInfo( m_pSourceURL, m_sourceURLLen, m_iFilePathLen, m_iScriptLen, m_iPathInfoLen, m_pContext ); } pValue = (char *)pReq->getOrgReqURL(); return m_iScriptLen; case REF_REQ_URI: //in rewrite rule, this does not include Query String part if ( pReq->getRedirects() == 0 ) { pValue = (char *)pReq->getOrgReqURL(); return pReq->getOrgReqURILen(); } if ( m_pStrip ) { memmove( pValue, m_pStrip->c_str(), m_pStrip->len() ); memmove( pValue + m_pStrip->len(), m_pSourceURL, m_sourceURLLen ); return m_pStrip->len() + m_sourceURLLen; } //fall through case REF_CUR_URI: pValue = (char *)m_pSourceURL; return m_sourceURLLen; case REF_QUERY_STRING: pValue = (char *)m_pQS; return m_qsLen; default: return RequestVars::getReqVar( pConn, type, pValue, bufLen ); } 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 ProxyConn::sendReqHeader() { m_iovec.clear(); HttpSession *pSession = getConnector()->getHttpSession(); HttpReq *pReq = pSession->getReq(); //remove the trailing "\r\n" before adding our headers const char *pBegin = pReq->getOrgReqLine(); m_iTotalPending = pReq->getHttpHeaderLen(); int newReqLineLen = 0; int headerLen = 17; char *pExtraHeader = &m_extraHeader[23]; const char *pForward = pReq->getHeader(HttpHeader::H_X_FORWARDED_FOR); int len; if (*pForward != '\0') { len = pReq->getHeaderLen(HttpHeader::H_X_FORWARDED_FOR); if (len > 160) len = 160; memmove(&pExtraHeader[headerLen], pForward, len); headerLen += len; pExtraHeader[headerLen++] = ','; } //add "X-Forwarded-For" header memmove(&pExtraHeader[headerLen], pSession->getPeerAddrString(), pSession->getPeerAddrStrLen()); headerLen += pSession->getPeerAddrStrLen(); pExtraHeader[headerLen++] = '\r'; pExtraHeader[headerLen++] = '\n'; #if 1 //always set "Accept-Encoding" header to "gzip" char *pAE = (char *)pReq->getHeader(HttpHeader::H_ACC_ENCODING); if (*pAE) { int len = pReq->getHeaderLen(HttpHeader::H_ACC_ENCODING); if (len >= 4) { memmove(pAE, "gzip", 4); memset(pAE + 4, ' ', len - 4); } } else { pExtraHeader = m_extraHeader; headerLen += 23; } #endif if (*(pBegin + --m_iTotalPending - 1) == '\r') --m_iTotalPending; if (*pForward) { if ((pBegin + m_iTotalPending) - (pForward + pReq->getHeaderLen(HttpHeader::H_X_FORWARDED_FOR)) == 2) { const char *p = pForward -= 16; while (*(p - 1) != '\n') --p; m_iTotalPending = p - pBegin; } } //reconstruct request line if URL has been rewritten if (pReq->getRedirects() > 0) { const char *pReqLine = pReq->encodeReqLine(newReqLineLen); if (newReqLineLen > 0) { m_iovec.append(pReqLine, newReqLineLen); pBegin += pReq->getOrgReqLineLen() - 9; m_iTotalPending -= pReq->getOrgReqLineLen() - 9; } } int newHostLen = pReq->getNewHostLen(); char *pHost = (char *)pReq->getHeader(HttpHeader::H_HOST); int hostLen = pReq->getHeaderLen(HttpHeader::H_HOST); if (newHostLen > 0) { if (*pHost) { m_iovec.append(pBegin, pHost - pBegin); m_iovec.append(pReq->getNewHost(), newHostLen); m_iovec.append(pHost + hostLen, pBegin + m_iTotalPending - pHost - hostLen); m_iTotalPending += (newHostLen - hostLen); } else { m_iovec.append(pBegin, m_iTotalPending); m_iovec.append("Host: ", 6); m_iovec.append(pReq->getNewHost(), newHostLen); m_iovec.append("\r\n", 2); m_iTotalPending += newHostLen + 8; } } else m_iovec.append(pBegin, m_iTotalPending); m_iTotalPending += newReqLineLen; if (hostLen) { m_iovec.append(s_achForwardHost, sizeof(s_achForwardHost) - 1); m_iovec.append(pHost, hostLen); m_iovec.append("\r\n", 2); m_iTotalPending += hostLen + sizeof(s_achForwardHost) + 1 ; } if (pSession->isSSL()) { m_iovec.append(s_achForwardHttps, sizeof(s_achForwardHttps) - 1); m_iTotalPending += sizeof(s_achForwardHttps) - 1; } //if ( headerLen > 0 ) { pExtraHeader[headerLen++] = '\r'; pExtraHeader[headerLen++] = '\n'; m_iovec.append(pExtraHeader, headerLen); m_iTotalPending += headerLen; } m_iReqHeaderSize = m_iTotalPending; m_iReqBodySize = pReq->getContentFinished(); setInProcess(1); return 1; }