const AutoStr2 * StringList::add( const char * pStr, int len ) { AutoStr2* pTemp = new AutoStr2(); if ( !pTemp ) return NULL; pTemp->setStr( pStr, len ); push_back( pTemp ); return pTemp; }
//When checking we use lock for may need to update the conf file later //If user RCS checkout a revision, a unlock should be used for next time checkin. //Example: co -u1.1 httpd_config.conf void plainconf::checkInFile(const char *path) { if (access(path, 0) == -1) return ; //Backup file abd checkin and out char new_path[4096]; strcpy(new_path, path); strcat(new_path, "0"); AutoStr2 buf; buf.setStr("cp \""); buf.append(path, strlen(path)); buf.append("\" \"", 3); buf.append(new_path, strlen(new_path)); buf.append("\"", 1); int ret = system(buf.c_str()); if (ret != 0) { logToMem(LOG_LEVEL_INFO, "Failed to backup the conf file %s, ret %d.", path, ret); return ; } buf.setStr("ci -l -q -t-\""); buf.append(new_path, strlen(new_path)); buf.append("\" -mUpdate \"", 12); buf.append(new_path, strlen(new_path)); buf.append("\" >/dev/null 2>&1", 17); ret = system(buf.c_str()); if (ret == 0) logToMem(LOG_LEVEL_INFO, "RCS checkin config file %s OK.", new_path); else logToMem(LOG_LEVEL_INFO, "Failed to RCS checkin conf file %s, ret %d, error(%s). " "Org command is %s.", new_path, ret, strerror(errno), buf.c_str()); unlink(new_path); }
static void setLastErrMsg(const char *format, ...) { const unsigned int MAX_LINE_LENGTH = 1024; char s[MAX_LINE_LENGTH] = {0}; va_list ap; va_start(ap, format); int ret = vsnprintf(s, MAX_LINE_LENGTH, format, ap); va_end(ap); if ((unsigned int)ret > MAX_LINE_LENGTH) ret = MAX_LINE_LENGTH; s_ErrMsg.setLen(0); s_ErrMsg.setStr(s, ret); }
//name: form like "moduleName|submodlue|itemname" const char *plainconf::getConfDeepValue(const XmlNode *pNode, const char *name) { const char *p = strchr(name, '|'); if (!p) return pNode->getChildValue(name); else { AutoStr2 subName; subName.setStr(name, p - name); const XmlNode *subNode = pNode->getChild(subName.c_str()); if (subNode) return getConfDeepValue(subNode, p + 1); else return NULL; } }
const char *MIMESubMap::setMainType(const char *pType, int len) { m_sMainType.setStr(pType, len); return m_sMainType.c_str(); }
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; }
//This function may be recruse called void plainconf::loadConfFile(const char *path) { logToMem(LOG_LEVEL_INFO, "start parsing file %s", path); int type = checkFiletype(path); if (type == 0) return; else if (type == 2) loadDirectory(path, NULL); else if (type == 3) { AutoStr2 prefixPath = path; const char *p = strrchr(path, '/'); if (p) prefixPath.setStr(path, p - path); struct stat sb; //removed the wildchar filename, should be a directory if exist if (stat(prefixPath.c_str(), &sb) == -1) { logToMem(LOG_LEVEL_ERR, "LoadConfFile error 1, path:%s directory:%s", path, prefixPath.c_str()); return ; } if ((sb.st_mode & S_IFMT) != S_IFDIR) { logToMem(LOG_LEVEL_ERR, "LoadConfFile error 2, path:%s directory:%s", path, prefixPath.c_str()); return ; } loadDirectory(prefixPath.c_str(), p + 1); } else //existed file { //gModuleList.push_back(); //XmlNode *xmlNode = new XmlNode; FILE *fp = fopen(path, "r"); if (fp == NULL) { logToMem(LOG_LEVEL_ERR, "Cannot open configuration file: %s", path); return; } const int MAX_LINE_LENGTH = 8192; char sLine[MAX_LINE_LENGTH]; char *p; char sLines[MAX_LINE_LENGTH] = {0}; int lineNumber = 0; const int MAX_MULLINE_SIGN_LENGTH = 128; char sMultiLineModeSign[MAX_MULLINE_SIGN_LENGTH] = {0}; size_t nMultiLineModeSignLen = 0; //>0 is mulline mode while (fgets(sLine, MAX_LINE_LENGTH, fp), !feof(fp)) { ++lineNumber; p = sLine; if (nMultiLineModeSignLen) { //Check if reach the END of the milline mode size_t len = 0; const char *pLineStart = getStrNoSpace(p, len); if (len == nMultiLineModeSignLen && strncasecmp(pLineStart, sMultiLineModeSign, nMultiLineModeSignLen) == 0) { nMultiLineModeSignLen = 0; removeSpace(sLines, 1); //Remove the last \r\n so that if it is one line, it will still be one line parseLine(path, lineNumber, sLines); sLines[0] = 0x00; } else strcat(sLines, p); continue; } removeSpace(p, 0); removeSpace(p, 1); if (!isValidline(p)) continue; AutoStr2 pathInclude; if (isInclude(p, pathInclude)) { char achBuf[512] = {0}; getIncludeFile(pathInclude.c_str(), achBuf); loadConfFile(achBuf); } else { nMultiLineModeSignLen = checkMultiLineMode(p, sMultiLineModeSign, MAX_MULLINE_SIGN_LENGTH); if (nMultiLineModeSignLen > 0) strncat(sLines, p, strlen(p) - (3 + nMultiLineModeSignLen)); //need to continue else if (isChunkedLine(p)) { strncat(sLines, p, strlen(p) - 1); //strcatchr(sLines, ' ', MAX_LINE_LENGTH); //add a space at the end of the line which has a '\\' } else { strcat(sLines, p); parseLine(path, lineNumber, sLines); sLines[0] = 0x00; } } } fclose(fp); //Parsed, check in it checkInFile(path); } }