Example #1
0
int L4Handler::init(HttpReq &req, const GSockAddr *pGSockAddr, const char *pIP, int iIpLen)
{
    int ret = m_pL4conn->init(pGSockAddr);
    if (ret != 0)
        return ret;
    
    int hasSlashR = 1; //"\r\n"" or "\n"
    LoopBuf *pBuff = m_pL4conn->getBuf();
    pBuff->append(req.getOrgReqLine(), req.getHttpHeaderLen());
    char *pBuffEnd = pBuff->end();
    assert(pBuffEnd[-1] == '\n');
    if (pBuffEnd[-2] == 'n')
        hasSlashR = 0;
    else
    {
        assert(pBuffEnd[-2] == '\r');
    }
    
    pBuff->used( -1 * hasSlashR - 1);
    pBuff->append("X-Forwarded-For", 15);
    pBuff->append(": ", 2);
    pBuff->append(pIP, iIpLen);
    if (hasSlashR)
        pBuff->append("\r\n\r\n", 4);
    else
        pBuff->append("\n\n", 2);
    
    continueRead();
    if ( D_ENABLED( DL_LESS ) )
    {
        LOG_D ((getLogger(), "[%s] L4Handler: init web socket, reqheader [%s], len [%d]",
                getLogId(), req.getOrgReqLine(), req.getHttpHeaderLen() ));
    }
    return 0;
}
int HttpCgiTool::buildFcgiEnv(FcgiEnv *pEnv, HttpSession *pSession)
{
    static const char *SP_ENVs[] =
    {
        "\017\010SERVER_PROTOCOLHTTP/1.1",
        "\017\010SERVER_PROTOCOLHTTP/1.0",
        "\017\010SERVER_PROTOCOLHTTP/0.9"
    };
    static const char *RM_ENVs[10] =
    {
        "\016\007REQUEST_METHODUNKNOWN",
        "\016\007REQUEST_METHODOPTIONS",
        "\016\003REQUEST_METHODGET",
        "\016\004REQUEST_METHODHEAD",
        "\016\004REQUEST_METHODPOST",
        "\016\003REQUEST_METHODPUT",
        "\016\006REQUEST_METHODDELETE",
        "\016\005REQUEST_METHODTRACE",
        "\016\007REQUEST_METHODCONNECT",
        "\016\004REQUEST_METHODMOVE"

    };

    static int RM_ENV_LEN[10] =
    {   23, 23, 19, 20, 20, 19, 22, 21, 23, 20 };


    HttpReq *pReq = pSession->getReq();
    int n;

    pEnv->add(GISS_ENV, GISS_ENV_LEN);
    n = pReq->getVersion();
    pEnv->add(SP_ENVs[n], 25);
    n = pReq->getMethod();
    if (n < 10)
        pEnv->add(RM_ENVs[n], RM_ENV_LEN[n]);
    else
        pEnv->add("REQUEST_METHOD", 016, HttpMethod::get(n),
                  HttpMethod::getLen(n));

    addSpecialEnv(pEnv, pReq);
    buildCommonEnv(pEnv, pSession);
    addHttpHeaderEnv(pEnv, pReq);
    return 0;
}
Example #3
0
int ProxyConn::connectSSL()
{
    if (!m_ssl.getSSL())
    {
        m_ssl.setSSL(getSslConn());
        if (!m_ssl.getSSL())
            return LS_FAIL;
        m_ssl.setfd(getfd());
        HttpReq *pReq = getConnector()->getHttpSession()->getReq();
        char *pHostName;
        int hostLen = pReq->getNewHostLen();
        if (hostLen > 0)
            pHostName = (char *)pReq->getNewHost();
        else
        {
            pHostName = (char *)pReq->getHeader(HttpHeader::H_HOST);
            hostLen = pReq->getHeaderLen(HttpHeader::H_HOST);
        }
        if (pHostName)
        {
            char ch = *(pHostName + hostLen);
            *(pHostName + hostLen) = 0;
            m_ssl.setTlsExtHostName(pHostName);
            *(pHostName + hostLen) = ch;
        }
    }
    int ret = m_ssl.connect();
    switch (ret)
    {
    case 0:
        setSSLAgain();
        break;
    case 1:
        LS_DBG_L(this, "[SSL] connected!");
        break;
    default:
        if (errno == EIO)
            LS_DBG_L(this, "SSL_connect() failed!: %s ", SslError().what());
        break;
    }

    return ret;
}
int RequestVars::getSubstValue( const SubstItem * pItem, HttpSession *pSession,
                        char * &pValue, int bufLen )
{
    HttpReq * pReq = pSession->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;
    }

    switch( type )
    {
    case REF_STRING:
        pValue = (char *)pItem->getStr()->c_str();
        return pItem->getStr()->len();
        
    case REF_ENV:
        pValue = (char *)RequestVars::getEnv( pSession, 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;
    default:
        return RequestVars::getReqVar( pSession, type, pValue, bufLen );
    }
    return 0;
}
HttpReq::Status HttpReq::status()
{
	if(mStatus == REQ_IN_PROGRESS)
	{
		int handle_count;
		CURLMcode merr = curl_multi_perform(s_multi_handle, &handle_count);
		if(merr != CURLM_OK && merr != CURLM_CALL_MULTI_PERFORM)
		{
			mStatus = REQ_IO_ERROR;
			onError(curl_multi_strerror(merr));
			return mStatus;
		}

		int msgs_left;
		CURLMsg* msg;
        while((msg = curl_multi_info_read(s_multi_handle, &msgs_left)))
		{
			if(msg->msg == CURLMSG_DONE)
			{
				HttpReq* req = s_requests[msg->easy_handle];
				
				if(req == NULL)
				{
					LOG(LogError) << "Cannot find easy handle!";
					continue;
				}

				if(msg->data.result == CURLE_OK)
				{
					req->mStatus = REQ_SUCCESS;
				}else{
					req->mStatus = REQ_IO_ERROR;
					req->onError(curl_easy_strerror(msg->data.result));
				}
			}
		}
	}

	return mStatus;
}
Example #6
0
int HttpCgiTool::buildEnv( IEnv* pEnv, HttpConnection* pConn )
{
    HttpReq * pReq = pConn->getReq();
    int n;
    pEnv->add( "GATEWAY_INTERFACE",17, "CGI/1.1", 7 );
    if ( getenv( "PATH" ) == NULL )
    {
        pEnv->add( "PATH", 4, DEFAULT_PATH, DEFAULT_PATHLEN );
    }
    n = pReq->getVersion();
    pEnv->add( "SERVER_PROTOCOL", 15,
        HttpVer::getVersionString( n ),
        HttpVer::getVersionStringLen( n ));
    const char * pServerStr;
    pServerStr = HttpServerVersion::getVersion();
    n = HttpServerVersion::getVersionLen();
    pEnv->add( "SERVER_SOFTWARE", 15, pServerStr, n);
    n = pReq->getMethod();
    pEnv->add( "REQUEST_METHOD", 14, HttpMethod::get( n ),
            HttpMethod::getLen( n ));



//    //FIXME: do nslookup
//
//    tmp = dnslookup(r->cn->peer.sin_addr, r->c->dns);
//    if (tmp) {
//            ADD_ENV(pEnv, "REMOTE_HOST", tmp);
//            free(tmp);
//    }
//
//    //ADD_ENV(pEnv, "REMOTE_HOST", achTemp );

    addSpecialEnv( pEnv, pReq );
    buildCommonEnv( pEnv, pConn );
    addHttpHeaderEnv( pEnv, pReq );
    pEnv->add( 0, 0, 0, 0);
    return 0;
}
Example #7
0
int SSIEngine::startExecute( HttpSession *pSession, 
                             SSIScript * pScript )
{
    if ( !pScript )
        return SC_500;
    SSIRuntime * pRuntime = pSession->getReq()->getSSIRuntime();
    if ( !pRuntime )
    {
        char ct[]= "text/html";
        HttpReq * pReq = pSession->getReq();
        pRuntime = new SSIRuntime();
        if (!pRuntime )
            return SC_500;
        pRuntime->init();
        pRuntime->initConfig( pReq->getSSIConfig() );
        pReq->setSSIRuntime( pRuntime );
        pSession->getResp()->reset();
        //pSession->getResp()->prepareHeaders( pReq );
        //pSession->setupChunkOS( 0 );
        HttpCgiTool::processContentType( pReq, pSession->getResp(), 
                      ct , 9 );
//        pSession->setupRespCache();
        if ( pReq->isXbitHackFull() )
        {
            pSession->getResp()->appendLastMod( pReq->getLastMod() );
        }
        int status = pReq->getStatusCode();
        if (( status >= SC_300 )&&( status < SC_400 ))
        {
            if ( pReq->getLocation() != NULL )
            {
                pSession->addLocationHeader();
            }
        }
        pSession->setupGzipFilter();
        pReq->andGzip( ~GZIP_ENABLED );  //disable GZIP
    }
    if ( pRuntime->push( pScript ) == -1 )
        return SC_500;
    pSession->getReq()->backupPathInfo();
    pScript->resetRuntime();
    return resumeExecute( pSession );
}
Example #8
0
int buildMoov(HttpSession *pSession)
{
    int ret = 0;
    HttpReq *pReq = pSession->getReq();
    SendFileInfo *pData = pSession->getSendFileInfo();

    FileCacheDataEx *&pECache = pData->getECache();

    unsigned char *mini_moov = NULL;
    uint32_t mini_moov_size;
    mini_moov = pData->getFileData()->getMiniMoov();
    mini_moov_size = pData->getFileData()->getMiniMoovSize();

    moov_data_t *moov_data = (moov_data_t *)pData->getParam();
    if (!moov_data)
        return LS_FAIL;

    while (moov_data->remaining_bytes > 0)
    {
        ret = get_moov(
                  pECache->getfd(),
                  moov_data->start_time,
                  0.0,
                  moov_data,
                  mini_moov,
                  mini_moov_size);
        if (ret == -1)
            return LS_FAIL;
        if (moov_data->is_mem == 1)
        {
            LS_DBG_L(pReq->getLogSession(), "is_mem, buf_size=%u, remaining=%d",
                     moov_data->mem.buf_size, moov_data->remaining_bytes);
            pSession->appendDynBody((char *)moov_data->mem.buffer,
                                    moov_data->mem.buf_size);
            free(moov_data->mem.buffer);
            moov_data->mem.buffer = NULL;
        }
        else
        {
            //pSession->flushDynBodyChunk();
            LS_DBG_L(pReq->getLogSession(),
                     "Send from file, start=%u, buf_size=%u, remaining=%d",
                     (uint32_t)moov_data->file.start_offset,
                     moov_data->file.data_size,
                     moov_data->remaining_bytes);
            pSession->setSendFileBeginEnd(moov_data->file.start_offset,
                                          moov_data->file.start_offset + moov_data->file.data_size);
            return 1;
            //sendfile( pECache->getfd(), moov_data.file.start_offset,
            //            moov_data.file.data_size );
            //fseek(infile, moov_data.file.start_offset, SEEK_SET);
            //copy_data(infile, outfile, moov_data.file.data_size);
        }
    }

    pSession->getReq()->clearContextState(MP4_SEEK);

    static char mdat_header64[16] = { 0, 0, 0, 1, 'm', 'd', 'a', 't' };
    uint64_t mdat_start;
    uint64_t mdat_size;
    int      mdat_64bit;
    uint32_t *pLen32;

    ret = get_mdat(
              pECache->getfd(),
              moov_data->start_time,
              0.0,
              & mdat_start,
              & mdat_size,
              & mdat_64bit,
              mini_moov,
              mini_moov_size);
    free(moov_data);
    pData->setParam(NULL);
    if (ret == -1)
        return LS_FAIL;
    LS_DBG_L(pReq->getLogSession(),
             "mdat_start=%u, mdat_size=%u, mdat_64bit=%d",
             (uint32_t)mdat_start, (uint32_t)mdat_size, mdat_64bit);
    pLen32 = (uint32_t *)(&mdat_header64[8]);
    if (mdat_64bit)
    {
        *pLen32++ = htonl((uint32_t)((mdat_size + 16) >> 32));
        *pLen32 = htonl((uint32_t)((mdat_size + 16) & 0xffffffff));
        pSession->appendDynBody(mdat_header64, 16);
    }
    else
    {
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 #10
0
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;
}
Example #11
0
int JConn::readRespHeader( unsigned char *&p, unsigned char *pEnd )
{
    while( m_iNumHeader > 0 )
    {
        if ( pEnd - p < 4 )
            return 0;
        unsigned char id1 = *p;
        unsigned char id2;
        int headerNameLen;
        const char * pHeaderName;
        unsigned char * p1;
        if ( id1 == 0xA0 )
        {
            id2 = *(p+1);
            if (( id2 > 0 )&&( id2 <= AJP_RESP_HEADERS_NUM ))
            {
                pHeaderName = JkAjp13::getRespHeaderById( id2 );
                headerNameLen = JkAjp13::getRespHeaderLenById( id2 );
                p1 = p + 2;
            }
            else
            {
                //invalid header id
                return -1;
            }
        }
        else
        {
            headerNameLen = id1 << 8 | *(p+1);
            if ( pEnd - p < headerNameLen + 5 )
                return 0;
            pHeaderName = (const char *)p + 2;
            p1 = p + headerNameLen + 3;
        }
        int headerValLen = peekInt( p1 );
        if ( pEnd - p1 < headerValLen + 3 )
            return 0;
        char * pHeaderVal = (char *)p1 + 2;
        p = p1 + headerValLen + 3;
        --m_iNumHeader;
        HttpResp * pResp = getConnector()->getHttpConn()->getResp();
        int ret = pResp->appendHeader(
                    pHeaderName, headerNameLen, pHeaderVal, headerValLen );
        if ( ret )
            return ret;
        HttpReq * pReq = getConnector()->getHttpConn()->getReq();
        if ( pReq->gzipAcceptable() )
        {
            if ( *pHeaderName == 'C' || *pHeaderName == 'c' )
            {
                if ( strcasecmp( pHeaderName, "content-type" ) == 0 )
                {
                    char * p = (char *)memchr( pHeaderVal, ';', headerValLen );
                    if ( !p )
                        p = pHeaderVal + headerValLen;
                    register char ch;
                    ch = *p;
                    *p = 0;
                    if ( !HttpGlobals::getMime()->compressable( pHeaderVal ) )
                        pReq->andGzip( ~GZIP_ENABLED );
                    *p = ch;
                }
                else if ( strcasecmp( pHeaderName, "content-encoding" ) == 0 )
                {
                    pReq->andGzip( ~GZIP_ENABLED );
                }
            }
        }
    }
    getConnector()->getRespState() |= HttpReq::HEADER_OK;
    return getConnector()->respHeaderDone( m_pCurPos - p );
}
//Only for types from LSI_REQ_SSL_VERSION to LSI_REQ_PATH_TRANSLATED which are defined in ls.h
int RequestVars::getReqVar2( HttpSession *pSession, int type, char * &pValue, int bufLen)
{
    HttpReq * pReq = pSession->getReq();
    int ret = 0;
    
    if (type >= LSI_REQ_SSL_VERSION && type <= LSI_REQ_SSL_CLIENT_CERT)
    {
        if( !pSession->isSSL() )
            return 0;
        
        SSLConnection *pSSL = pSession->getSSL();
        if( type == LSI_REQ_SSL_VERSION)
        {
            pValue = (char *)pSSL->getVersion();
            ret = strlen( pValue );
            return ret;
        }    
        else if( type == LSI_REQ_SSL_SESSION_ID )
        {
            SSL_SESSION *pSession = pSSL->getSession();
            if ( pSession )
            {
                int idLen = SSLConnection::getSessionIdLen( pSession );
                ret = idLen * 2;
                if ( ret > bufLen )
                    ret = bufLen;
                StringTool::hexEncode((char *)SSLConnection::getSessionId( pSession ), ret / 2, pValue );
            }
            return ret;
        }
        else if( type == LSI_REQ_SSL_CLIENT_CERT )
        {
            X509 * pClientCert = pSSL->getPeerCertificate();
            if ( pClientCert )
                ret = SSLCert::PEMWriteCert( pClientCert, pValue, bufLen );
            
            return ret;
        }
        else
        {
            const SSL_CIPHER * pCipher = pSSL->getCurrentCipher();
            if ( pCipher )
            {
                if( type == LSI_REQ_SSL_CIPHER )
                {
                    pValue = (char *)pSSL->getCipherName();
                    ret = strlen( pValue );
                }
                else
                {
                    int algkeysize;
                    int keysize = SSLConnection::getCipherBits( pCipher, &algkeysize );
                    if( type == LSI_REQ_SSL_CIPHER_USEKEYSIZE )
                        ret = safe_snprintf( pValue, 20, "%d", keysize );
                    else //LSI_REQ_SSL_CIPHER_ALGKEYSIZE
                        ret = safe_snprintf( pValue, 20, "%d", algkeysize );
                }
            }
            return ret;
        }
    }
    else if( type == LSI_REQ_GEOIP_ADDR)
    {
        ret = pSession->getPeerAddrStrLen();
        pValue = (char *)pSession->getPeerAddrString();
        return ret;
    }
    else if( type == LSI_REQ_PATH_TRANSLATED)
    {
        int n = pReq->getPathInfoLen();
        if ( n > 0)
            ret =  pReq->translatePath( pReq->getPathInfo(), n, pValue, bufLen);
        return ret;
    }
    else
        return 0;
}
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;
    
}
Example #14
0
int CgidConn::buildReqHeader()
{
    static unsigned int s_id = 0;
    HttpSession *pSession = getConnector()->getHttpSession();
    HttpReq * pReq = pSession->getReq();
    const char * pQueryString = pReq->getQueryString();
    const char * pQsEnd = pReq->getQueryString() + pReq->getQueryStringLen();
    const char * pReal;
    const AutoStr2 * psChroot;
    const AutoStr2 * realPath = pReq->getRealPath();
    const char * pChroot;
    int ret;
    uid_t uid;
    gid_t gid;
    pReal = realPath->c_str();
    ret = pReq->getUGidChroot( &uid, &gid, &psChroot );
    if ( ret )
        return ret;
//    if ( D_ENABLED( DL_LESS ) )
//        LOG_D(( getLogger(),
//            "[%s] UID: %d, GID: %d",
//            getLogId(), pHeader->m_uid, pHeader->m_gid ));
    if ( psChroot )
    {
//        if ( D_ENABLED( DL_LESS ) )
//            LOG_D(( getLogger(),
//                "[%s] chroot: %s, real path: %s",
//                getLogId(), pChroot->c_str(), pReal ));
        pChroot = psChroot->c_str();
        ret = psChroot->len();
    }
    else
    {
        pChroot = NULL;
        ret = 0;
    }
    int priority = ((CgidWorker *)getWorker())->getConfig().getPriority();
    m_req.buildReqHeader( uid, gid, priority, pChroot, ret, pReal,
                pReq->getRealPath()->len(),
                ((CgidWorker *)getWorker())->getConfig().getRLimits() );
    if ( *pQueryString && (memchr( pQueryString, '=',
                                pQsEnd - pQueryString ) == NULL ))
    {
        char * pPlus;
        do
        {
            pPlus = (char*)memchr( pQueryString, '+', pQsEnd - pQueryString);
            if ( pPlus != pQueryString )
            {
                int len;
                if ( pPlus )
                    len = pPlus - pQueryString;
                else
                    len = pQsEnd - pQueryString;
                m_req.appendArgv( pQueryString, len );
            }
            if ( pPlus )
                pQueryString = pPlus + 1;
        }while( pPlus );
    }
    m_req.appendArgv( NULL, 0 );

    HttpCgiTool::buildEnv( &m_req, pSession );

    m_req.finalize( s_id++, ((CgidWorker *)getWorker())->getConfig().getSecret(),
                    LSCGID_TYPE_CGI );
    return 0;
}
Example #15
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;
}
Example #16
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;
}
Example #17
0
int HttpCgiTool::buildCommonEnv( IEnv * pEnv, HttpConnection * pConn )
{
    int count = 0;
    HttpReq * pReq = pConn->getReq();
    const char * pTemp;
    int n;
    int i;
    char buf[128];

    pTemp = pReq->getAuthUser();
    if (  *pTemp )
    {
        //FIXME: only Basic is support now
        pEnv->add( "AUTH_TYPE", 9, "Basic", 5 );
        pEnv->add( "REMOTE_USER", 11, pTemp, strlen( pTemp ) );
        count += 2;
    }
    //ADD_ENV("REMOTE_IDENT", "" )        //FIXME: not supported yet
    //extensions of CGI/1.1
    const AutoStr2 * pDocRoot = pReq->getDocRoot();
    pEnv->add( "DOCUMENT_ROOT", 13,
            pDocRoot->c_str(), pDocRoot->len()-1 );
    pEnv->add( "REMOTE_ADDR", 11, pConn->getPeerAddrString(),
            pConn->getPeerAddrStrLen() );
    
    n = safe_snprintf( buf, 10, "%hu", pConn->getRemotePort() );
    pEnv->add( "REMOTE_PORT", 11, buf, n );

    n = pConn->getServerAddrStr( buf, 128 );
    
    pEnv->add( "SERVER_ADDR", 11, buf, n );
    
    pEnv->add( "SERVER_NAME", 11, pReq->getHostStr(),  pReq->getHostStrLen() );
    const AutoStr2 &sPort = pReq->getPortStr();
    pEnv->add( "SERVER_PORT", 11, sPort.c_str(), sPort.len() );
    pEnv->add( "REQUEST_URI", 11, pReq->getOrgReqURL(), pReq->getOrgReqURLLen() );
    count += 7;
    
    n = pReq->getPathInfoLen();
    if ( n > 0)
    {
        int m;
        char achTranslated[10240];
        m =  pReq->translatePath( pReq->getPathInfo(), n,
                        achTranslated, sizeof( achTranslated ) );
        if ( m != -1 );
        {
            pEnv->add( "PATH_TRANSLATED", 15, achTranslated, m );
            ++count;
        }
        pEnv->add( "PATH_INFO", 9, pReq->getPathInfo(), n);
        ++count;
    }
    
    //add geo IP env here
    if ( pReq->isGeoIpOn() )
    {
        GeoInfo * pInfo = pConn->getClientInfo()->getGeoInfo();
        if ( pInfo )
        {
            pEnv->add( "GEOIP_ADDR", 10, pConn->getPeerAddrString(),
                    pConn->getPeerAddrStrLen() );
            count += pInfo->addGeoEnv( pEnv )+1;
        }
    }    

    n = pReq->getEnvCount();
    count += n;
    for( i = 0; i < n; ++i )
    {
        const char * pKey;
        const char * pVal;
        int keyLen;
        int valLen;
        pKey = pReq->getEnvByIndex( i, keyLen, pVal, valLen );
        if ( pKey )
            pEnv->add( pKey, keyLen, pVal, valLen );
    }
    
    if ( pConn->isSSL() )
    {
        SSLConnection * pSSL = pConn->getSSL();
        pEnv->add( "HTTPS", 5, "on",  2 );
        const char * pVersion = pSSL->getVersion();
        n = strlen( pVersion );
        pEnv->add( "SSL_VERSION", 11, pVersion, n );
        count += 2;
        SSL_SESSION * pSession = pSSL->getSession();
        if ( pSession )
        {
            int idLen = SSLConnection::getSessionIdLen( pSession );
            n = idLen * 2;
            assert( n < (int)sizeof( buf ) );
            StringTool::hexEncode(
                (char *)SSLConnection::getSessionId( pSession ),
                idLen, buf );
            pEnv->add( "SSL_SESSION_ID", 14, buf, n );
            ++count;
        }

        const SSL_CIPHER * pCipher = pSSL->getCurrentCipher();
        if ( pCipher )
        {
            const char * pName = pSSL->getCipherName();
            n = strlen( pName );
            pEnv->add( "SSL_CIPHER", 10, pName, n );
            int algkeysize;
            int keysize = SSLConnection::getCipherBits( pCipher, &algkeysize );
            n = safe_snprintf( buf, 20, "%d", keysize );
            pEnv->add( "SSL_CIPHER_USEKEYSIZE", 21, buf, n );
            n = safe_snprintf( buf, 20, "%d", algkeysize );
            pEnv->add( "SSL_CIPHER_ALGKEYSIZE", 21, buf, n );
            count += 3;
        }

        X509 * pClientCert = pSSL->getPeerCertificate();
        if ( pClientCert )
        {
            //IMPROVE: too many deep copy here.
            char achBuf[4096];
            n = SSLCert::PEMWriteCert( pClientCert, achBuf, 4096 );
            if ((n>0)&&( n <= 4096 ))
            {
                pEnv->add( "SSL_CLIENT_CERT", 15, achBuf, n );
                ++count;
            }
        }
        
    }    
    return count;
}
int HttpCgiTool::buildCommonEnv(IEnv *pEnv, HttpSession *pSession)
{
    int count = 0;
    HttpReq *pReq = pSession->getReq();
    const char *pTemp;
    int n;
    char buf[128];
    RadixNode *pNode;

    pTemp = pReq->getAuthUser();
    if (pTemp)
    {
        //NOTE: only Basic is support now
        pEnv->add("AUTH_TYPE", 9, "Basic", 5);
        pEnv->add("REMOTE_USER", 11, pTemp, strlen(pTemp));
        count += 2;
    }
    //ADD_ENV("REMOTE_IDENT", "" )        //TODO: not supported yet
    //extensions of CGI/1.1
    const AutoStr2 *pDocRoot = pReq->getDocRoot();
    pEnv->add("DOCUMENT_ROOT", 13,
              pDocRoot->c_str(), pDocRoot->len() - 1);
    pEnv->add("REMOTE_ADDR", 11, pSession->getPeerAddrString(),
              pSession->getPeerAddrStrLen());

    n = ls_snprintf(buf, 10, "%hu", pSession->getRemotePort());
    pEnv->add("REMOTE_PORT", 11, buf, n);

    n = pSession->getServerAddrStr(buf, 128);

    pEnv->add("SERVER_ADDR", 11, buf, n);

    pEnv->add("SERVER_NAME", 11, pReq->getHostStr(),  pReq->getHostStrLen());
    const AutoStr2 &sPort = pReq->getPortStr();
    pEnv->add("SERVER_PORT", 11, sPort.c_str(), sPort.len());
    pEnv->add("REQUEST_URI", 11, pReq->getOrgReqURL(),
              pReq->getOrgReqURLLen());
    count += 7;

    n = pReq->getPathInfoLen();
    if (n > 0)
    {
        int m;
        char achTranslated[10240];
        m =  pReq->translatePath(pReq->getPathInfo(), n,
                                 achTranslated, sizeof(achTranslated));
        if (m != -1)
        {
            pEnv->add("PATH_TRANSLATED", 15, achTranslated, m);
            ++count;
        }
        pEnv->add("PATH_INFO", 9, pReq->getPathInfo(), n);
        ++count;
    }

    //add geo IP env here
    if (pReq->isGeoIpOn())
    {
        GeoInfo *pInfo = pSession->getClientInfo()->getGeoInfo();
        if (pInfo)
        {
            pEnv->add("GEOIP_ADDR", 10, pSession->getPeerAddrString(),
                      pSession->getPeerAddrStrLen());
            count += pInfo->addGeoEnv(pEnv) + 1;
        }
    }
    n = pReq->getEnvCount();
    count += n;
    if ((pNode = (RadixNode *)pReq->getEnvNode()) != NULL)
        pNode->for_each2(addEnv, pEnv);

    if (pSession->getStream()->isSpdy())
    {
        const char *pProto = HioStream::getProtocolName((HiosProtocol)
                             pSession->getStream()->getProtocol());
        pEnv->add("X_SPDY", 6, pProto, strlen(pProto));
        ++count;
    }

    if (pSession->isSSL())
    {
        SslConnection *pSSL = pSession->getSSL();
        pEnv->add("HTTPS", 5, "on",  2);
        const char *pVersion = pSSL->getVersion();
        n = strlen(pVersion);
        pEnv->add("SSL_VERSION", 11, pVersion, n);
        count += 2;
        SSL_SESSION *pSession = pSSL->getSession();
        if (pSession)
        {
            int idLen = SslConnection::getSessionIdLen(pSession);
            n = idLen * 2;
            assert(n < (int)sizeof(buf));
            StringTool::hexEncode(
                (char *)SslConnection::getSessionId(pSession),
                idLen, buf);
            pEnv->add("SSL_SESSION_ID", 14, buf, n);
            ++count;
        }

        const SSL_CIPHER *pCipher = pSSL->getCurrentCipher();
        if (pCipher)
        {
            const char *pName = pSSL->getCipherName();
            n = strlen(pName);
            pEnv->add("SSL_CIPHER", 10, pName, n);
            int algkeysize;
            int keysize = SslConnection::getCipherBits(pCipher, &algkeysize);
            n = ls_snprintf(buf, 20, "%d", keysize);
            pEnv->add("SSL_CIPHER_USEKEYSIZE", 21, buf, n);
            n = ls_snprintf(buf, 20, "%d", algkeysize);
            pEnv->add("SSL_CIPHER_ALGKEYSIZE", 21, buf, n);
            count += 3;
        }

        int i = pSSL->getVerifyMode();
        if (i != 0)
        {
            char achBuf[4096];
            X509 *pClientCert = pSSL->getPeerCertificate();
            if (pSSL->isVerifyOk())
            {
                if (pClientCert)
                {
                    //IMPROVE: too many deep copy here.
                    //n = SslCert::PEMWriteCert( pClientCert, achBuf, 4096 );
                    //if ((n>0)&&( n <= 4096 ))
                    //{
                    //    pEnv->add( "SSL_CLIENT_CERT", 15, achBuf, n );
                    //    ++count;
                    //}
                    n = snprintf(achBuf, sizeof(achBuf), "%lu",
                                 X509_get_version(pClientCert) + 1);
                    pEnv->add("SSL_CLIENT_M_VERSION", 20, achBuf, n);
                    ++count;
                    n = lookup_ssl_cert_serial(pClientCert, achBuf, 4096);
                    if (n != -1)
                    {
                        pEnv->add("SSL_CLIENT_M_SERIAL", 19, achBuf, n);
                        ++count;
                    }
                    X509_NAME_oneline(X509_get_subject_name(pClientCert), achBuf, 4096);
                    pEnv->add("SSL_CLIENT_S_DN", 15, achBuf, strlen(achBuf));
                    ++count;
                    X509_NAME_oneline(X509_get_issuer_name(pClientCert), achBuf, 4096);
                    pEnv->add("SSL_CLIENT_I_DN", 15, achBuf, strlen(achBuf));
                    ++count;
                    if (SslConnection::isClientVerifyOptional(i))
                    {
                        strcpy(achBuf, "GENEROUS");
                        n = 8;
                    }
                    else
                    {
                        strcpy(achBuf, "SUCCESS");
                        n = 7;
                    }
                }
                else
                {
                    strcpy(achBuf, "NONE");
                    n = 4;
                }
            }
            else
                n = pSSL->buildVerifyErrorString(achBuf, sizeof(achBuf));
            pEnv->add("SSL_CLIENT_VERIFY", 17, achBuf, n);
            ++count;
        }

    }
    return count;
}
Example #19
0
void AccessLog::customLog( HttpConnection* pConn )
{
    CustomFormat::iterator iter = m_pCustomFormat->begin();
    HttpReq * pReq = pConn->getReq();
    LogFormatItem *pItem;
    const char * pValue = NULL;
    char * pBuf;
    int n;
    while( iter != m_pCustomFormat->end() )
    {
        pItem = *iter;
        switch( pItem->m_itemId )
        {
            case REF_STRING:
                appendStrNoQuote( pItem->m_sExtra.c_str(), pItem->m_sExtra.len() );
                break;
            case REF_STRFTIME:
                if ( pItem->m_sExtra.c_str() )
                {
                    logTime( &m_buf, pConn->getReqTime(), pItem->m_sExtra.c_str() );
                }
                else
                {
                    DateTime::getLogTime( pConn->getReqTime(), m_buf.end() );
                    m_buf.used( 28 );
                }
                break;
            case REF_CONN_STATE:
                if ( pConn->isConnCanceled() )
                {
                    m_buf.append( 'X' );
                }
                else if ( pConn->isClosing() )
                {
                    m_buf.append( '-' );
                }
                else
                    m_buf.append( '+' );
                break;
            case REF_COOKIE_VAL:
            case REF_ENV:
            case REF_HTTP_HEADER:
                switch( pItem->m_itemId )
                {
                    case REF_COOKIE_VAL:
                        pValue = RequestVars::getCookieValue( pReq, pItem->m_sExtra.c_str(), pItem->m_sExtra.len(), n );
                        break;
                    case REF_ENV:
                        pValue = RequestVars::getEnv(pConn, pItem->m_sExtra.c_str(), pItem->m_sExtra.len(), n );
                        break;
                    case REF_HTTP_HEADER:
                        pValue = pReq->getHeader( pItem->m_sExtra.c_str(), pItem->m_sExtra.len(), n );
                        break;
                }
                if ( pValue )
                    appendStrNoQuote( pValue, n );
                else
                    m_buf.append( '-' );
                break;
                
                    default:
                        pBuf= m_buf.end();
                        
                        n = RequestVars::getReqVar( pConn, pItem->m_itemId, pBuf, m_buf.available() );
                        if ( n )
                        {
                            if ( pBuf != m_buf.end() )
                                appendStrNoQuote( pBuf, n );
                            else
                                m_buf.used( n );
                        }
                        else
                            m_buf.append( '-' );
                        break;
                        
        }
        ++iter;
    }
    m_buf.append( '\n' );
    if (( m_buf.available() < MAX_LOG_LINE_LEN )
        ||!asyncAccessLog() )
    {
        flush();
    }
}
Example #20
0
void AccessLog::log( HttpConnection* pConn )
{
    int  n;
    HttpReq*  pReq  = pConn->getReq();
    HttpResp* pResp = pConn->getResp();
    const char * pUser = pReq->getAuthUser();
    long contentWritten = pResp->getBodySent();
    const ClientInfo * pInfo = pConn->getClientInfo();
    const char * pAddr = pInfo->getHostName();
    pResp->needLogAccess( 0 );
    if ( m_iPipedLog )
    {
        if ( !m_pManager )
            return;
        m_pAppender = m_pManager->getAppender();
        if ( !m_pAppender )
            return;
    }
    
    if ( m_pCustomFormat )
        return customLog( pConn );
    
    if (( pAddr )&&( *pAddr ))
    {
        n = pInfo->getHostNameLen();
    }
    else
    {
        pAddr = pInfo->getAddrString();
        n = pInfo->getAddrStrLen();
    }
    m_buf.appendNoCheck( pAddr, n );
    if ( ! *pUser )
    {
        m_buf.appendNoCheck( " - - ", 5 );
    }
    else
    {
        n = safe_snprintf( m_buf.end(), 70, " - \"%s\" ", pUser );
        m_buf.used( n );
    }

    DateTime::getLogTime( pConn->getReqTime(), m_buf.end() );
    m_buf.used( 30 );
    n = pReq->getOrgReqLineLen();
    char * pOrgReqLine = (char *)pReq->getOrgReqLine();
    if ( pReq->getVersion() == HTTP_1_0 )
        *(pOrgReqLine + n - 1) = '0';
    if (( n > 4096 )||( m_buf.available() < 100 + n ))
    {
        flush();
        m_pAppender->append( pOrgReqLine, n );
    }
    else
        m_buf.appendNoCheck(pOrgReqLine, n );
    m_buf.append( '"' );
    m_buf.appendNoCheck(
        HttpStatusCode::getCodeString( pReq->getStatusCode() ), 5 );
    if ( contentWritten == 0 )
    {
        m_buf.append( '-' );
    }
    else
    {
        n = safe_snprintf( m_buf.end(), 20, "%ld", contentWritten );
        m_buf.used( n );
    }
    if ( getAccessLogHeader() & LOG_REFERER )
    {
        m_buf.append( ' ' );
        appendStr( pReq->getHeader( HttpHeader::H_REFERER ),
                pReq->getHeaderLen( HttpHeader::H_REFERER ));
    }
    if ( getAccessLogHeader() & LOG_USERAGENT )
    {
        m_buf.append( ' ' );
        appendStr( pReq->getHeader( HttpHeader::H_USERAGENT),
                pReq->getHeaderLen( HttpHeader::H_USERAGENT) );
    }
    if ( getAccessLogHeader() & LOG_VHOST )
    {
        m_buf.append( ' ' );
        appendStr( pReq->getHeader( HttpHeader::H_HOST ),
                pReq->getHeaderLen( HttpHeader::H_HOST ) );
    }
    m_buf.append( '\n' );
    if (( m_buf.available() < MAX_LOG_LINE_LEN )
        ||!asyncAccessLog() )
    {
        flush();
    }
}
Example #21
0
// handle WinHTTP callbacks (which can be in a worker thread context)
VOID CALLBACK WinHttpIO::asynccallback(HINTERNET hInternet, DWORD_PTR dwContext,
                                       DWORD dwInternetStatus,
                                       LPVOID lpvStatusInformation,
                                       DWORD dwStatusInformationLength)
{
    WinHttpContext* httpctx = (WinHttpContext*)dwContext;
    WinHttpIO* httpio = (WinHttpIO*)httpctx->httpio;

    if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING)
    {
        LOG_verbose << "Closing request";
        assert(!httpctx->req);

        if (httpctx->gzip)
        {
            inflateEnd(&httpctx->z);
        }
        
        delete httpctx;
        return;
    }

    httpio->lock();

    HttpReq* req = httpctx->req;

    // request cancellations that occured after asynccallback() was entered are caught here
    if (!req)
    {
        LOG_verbose << "Request cancelled";
        httpio->unlock();
        return;
    }

    switch (dwInternetStatus)
    {
        case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
        {
            DWORD size = *(DWORD*)lpvStatusInformation;

            if (!size)
            {
                if (req->binary)
                {
                    LOG_debug << "[received " << (req->buf ? req->buflen : req->in.size()) << " bytes of raw data]";
                }
                else
                {
                    if(req->in.size() < 2048)
                    {
                        LOG_debug << "Received: " << req->in.c_str();
                    }
                    else
                    {
                        LOG_debug << "Received: " << req->in.substr(0,2048).c_str();
                    }
                }

                LOG_debug << "Request finished with HTTP status: " << req->httpstatus;
                req->status = (req->httpstatus == 200
                            && (req->contentlength < 0
                             || req->contentlength == (req->buf ? req->bufpos : (int)req->in.size())))
                             ? REQ_SUCCESS : REQ_FAILURE;

                if (req->status == REQ_SUCCESS)
                {
                    httpio->lastdata = Waiter::ds;
                }
                httpio->success = true;
            }
            else
            {
                LOG_verbose << "Data available. Remaining: " << size << " bytes";

                char* ptr;

                if (httpctx->gzip)
                {                    
                    m_off_t zprevsize = httpctx->zin.size();
                    httpctx->zin.resize(zprevsize + size);
                    ptr = (char*)httpctx->zin.data() + zprevsize;
                }
                else
                {                    
                    ptr = (char*)req->reserveput((unsigned*)&size);
                    req->bufpos += size;
                }

                if (!WinHttpReadData(hInternet, ptr, size, NULL))
                {
                    LOG_err << "Unable to get more data. Code: " << GetLastError();
                    httpio->cancel(req);
                }
            }

            httpio->httpevent();
            break;
        }

        case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
            LOG_verbose << "Read complete";

            if (dwStatusInformationLength)
            {
                LOG_verbose << dwStatusInformationLength << " bytes received";
                if (req->httpio)
                {
                    req->httpio->lastdata = Waiter::ds;
                }
            
                if (httpctx->gzip)
                {                    
                    httpctx->z.next_in = (Bytef*)lpvStatusInformation;
                    httpctx->z.avail_in = dwStatusInformationLength;

                    req->bufpos += httpctx->z.avail_out;
                    int t = inflate(&httpctx->z, Z_SYNC_FLUSH);
                    req->bufpos -= httpctx->z.avail_out;

                    if ((char*)lpvStatusInformation + dwStatusInformationLength ==
                             httpctx->zin.data() + httpctx->zin.size())
                    {
                        httpctx->zin.clear();
                    }

                    if (t != Z_OK && (t != Z_STREAM_END || httpctx->z.avail_out))
                    {
                        LOG_err << "GZIP error";
                        httpio->cancel(req);
                    }
                }

                if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL))
                {
                    LOG_err << "Error on WinHttpQueryDataAvailable. Code: " << GetLastError();
                    httpio->cancel(req);
                    httpio->httpevent();
                }
            }
            break;

        case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
        {
            DWORD statusCode;
            DWORD statusCodeSize = sizeof(statusCode);

            if (!WinHttpQueryHeaders(httpctx->hRequest,
                                     WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
                                     WINHTTP_HEADER_NAME_BY_INDEX,
                                     &statusCode,
                                     &statusCodeSize,
                                     WINHTTP_NO_HEADER_INDEX))
            {
                LOG_err << "Error getting headers. Code: " << GetLastError();
                httpio->cancel(req);
                httpio->httpevent();
            }
            else
            {
                LOG_verbose << "Headers available";

                req->httpstatus = statusCode;

                if (req->httpio)
                {
                    req->httpio->lastdata = Waiter::ds;
                }

                if (!req->buf)
                {
                    // obtain original content length - always present if gzip is in use
                    DWORD contentLength;
                    DWORD contentLengthSize = sizeof(contentLength);

                    if (WinHttpQueryHeaders(httpctx->hRequest,
                                            WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_NUMBER,
                                            L"Original-Content-Length",
                                            &contentLength,
                                            &contentLengthSize,
                                            WINHTTP_NO_HEADER_INDEX))
                    {
                        LOG_verbose << "Content-Length: " << contentLength;
                        req->setcontentlength(contentLength);

                        // check for gzip content encoding
                        WCHAR contentEncoding[16];
                        DWORD contentEncodingSize = sizeof(contentEncoding);

                        httpctx->gzip = WinHttpQueryHeaders(httpctx->hRequest,
                                                WINHTTP_QUERY_CONTENT_ENCODING,
                                                WINHTTP_HEADER_NAME_BY_INDEX,
                                                &contentEncoding,
                                                &contentEncodingSize,
                                                WINHTTP_NO_HEADER_INDEX)
                                    && !wcscmp(contentEncoding, L"gzip");

                        if (httpctx->gzip)
                        {
                            LOG_verbose << "Using GZIP";

                            httpctx->z.zalloc = Z_NULL;
                            httpctx->z.zfree = Z_NULL;
                            httpctx->z.opaque = Z_NULL;
                            httpctx->z.avail_in = 0;
                            httpctx->z.next_in = Z_NULL;

                            inflateInit2(&httpctx->z, MAX_WBITS+16);

                            req->in.resize(contentLength);
                            httpctx->z.avail_out = contentLength;
                            httpctx->z.next_out = (unsigned char*)req->in.data();
                        }
                        else
                        {
                            LOG_verbose << "Not using GZIP";
                        }
                    }
                    else
                    {
                        LOG_verbose << "Content-Length not available";
                    }
                }

                if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL))
                {
                    LOG_err << "Unable to query data. Code: " << GetLastError();

                    httpio->cancel(req);
                    httpio->httpevent();
                }
                else if (httpio->waiter && httpio->noinetds)
                {
                    httpio->inetstatus(true);
                }
            }

            break;
        }

        case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
        {
            DWORD e = GetLastError();

            LOG_err << "Request error. Code: " << e;

            if (httpio->waiter && e != ERROR_WINHTTP_TIMEOUT)
            {
                httpio->inetstatus(false);
            }
        }
        // fall through
        case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
            if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
            {
                LOG_err << "Security check failed. Code: " << (*(DWORD*)lpvStatusInformation);
            }

            httpio->cancel(req);
            httpio->httpevent();
            break;

        case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
        {
            if(MegaClient::disablepkp)
            {
                break;
            }

            PCCERT_CONTEXT cert;
            DWORD len = sizeof cert;

            if (WinHttpQueryOption(httpctx->hRequest, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert, &len))
            {
                CRYPT_BIT_BLOB* pkey = &cert->pCertInfo->SubjectPublicKeyInfo.PublicKey;

                // this is an SSL connection: verify public key to prevent MITM attacks
                if (pkey->cbData != 270
                 || (memcmp(pkey->pbData, "\x30\x82\x01\x0a\x02\x82\x01\x01\x00" APISSLMODULUS1
                                          "\x02" APISSLEXPONENTSIZE APISSLEXPONENT, 270)
                  && memcmp(pkey->pbData, "\x30\x82\x01\x0a\x02\x82\x01\x01\x00" APISSLMODULUS2
                                          "\x02" APISSLEXPONENTSIZE APISSLEXPONENT, 270)))
                {
                    LOG_err << "Certificate error. Possible MITM attack!!";
                    CertFreeCertificateContext(cert);
                    httpio->cancel(req);
                    httpio->httpevent();
                    break;
                }

                CertFreeCertificateContext(cert);
            }

            break;
        }

        case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
        case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
            if (httpctx->postpos < httpctx->postlen)
            {
                LOG_verbose << "Chunk written";
                unsigned pos = httpctx->postpos;
                unsigned t = httpctx->postlen - pos;

                if (t > HTTP_POST_CHUNK_SIZE)
                {
                    t = HTTP_POST_CHUNK_SIZE;
                }

                httpctx->postpos += t;

                if (!WinHttpWriteData(httpctx->hRequest, (LPVOID)(httpctx->postdata + pos), t, NULL))
                {
                    LOG_err << "Error writting data. Code: " << GetLastError();
                    req->httpio->cancel(req);
                }

                httpio->httpevent();
            }
            else
            {
                LOG_verbose << "Request written";
                if (!WinHttpReceiveResponse(httpctx->hRequest, NULL))
                {
                    LOG_err << "Error receiving response. Code: " << GetLastError();
                    httpio->cancel(req);
                    httpio->httpevent();
                }

                httpctx->postdata = NULL;
            }
    }

    httpio->unlock();
}
Example #22
0
int ProxyConn::processResp()
{
    HttpExtConnector *pHEC = getConnector();
    if (!pHEC)
    {
        errno = ECONNRESET;
        return LS_FAIL;
    }
    int len = 0;
    int ret = 0;
    int &respState = pHEC->getRespState();
    if (!(respState & 0xff))
    {
        char *p = HttpResourceManager::getGlobalBuf();
        const char *pBuf = p;
        if (m_iSsl)
            len = m_ssl.read(p, 1460);
        else
            len = ExtConn::read(p, 1460);

        if (len > 0)
        {
            int copy = len;
            if (m_iRespHeaderRecv + copy > 4095)
                copy = 4095 - m_iRespHeaderRecv;
            //memmove( &m_achRespBuf[ m_iRespHeaderRecv ], pBuf, copy );
            m_iRespHeaderRecv += copy;
            m_iRespRecv += len;
            LS_DBG_L(this, "Read Response %d bytes", len);
            //debug code
            //::write( 1, pBuf, len );

            ret = pHEC->parseHeader(pBuf, len, 1);
            switch (ret)
            {
            case -2:
                LS_WARN(this, "Invalid Http response header, retry!");
                //debug code
                //::write( 1, pBuf, len );
                errno = ECONNRESET;
            case -1:
                return LS_FAIL;
            }
        }
        else
            return len;
        if (respState & 0xff)
        {
            //debug code
            //::write(1, HttpResourceManager::getGlobalBuf(),
            //        pBuf - HttpResourceManager::getGlobalBuf() );
            HttpReq *pReq = pHEC->getHttpSession()->getReq();
            if (pReq->noRespBody())
            {
                incReqProcessed();
                if (len > 0)
                    abort();
                else if (respState & HEC_RESP_CONN_CLOSE)
                    setState(CLOSING);
                else if (getState() == ABORT)
                    setState(PROCESSING);

                setInProcess(0);
                pHEC->endResponse(0, 0);
                return 0;
            }

            m_iRespBodySize = pHEC->getHttpSession()->getResp()->getContentLen();
            LS_DBG_L(this, "Response body size of proxy reply is %d",
                     m_iRespBodySize);
            if (m_iRespBodySize == LSI_RSP_BODY_SIZE_CHUNKED)
                setupChunkIS();
            else if (!(respState & HEC_RESP_CONT_LEN))
                m_iRespBodySize = INT_MAX;

            m_pBufBegin = pBuf;
            m_pBufEnd = pBuf + len;
            LS_DBG_M(this, "Process Response body %d bytes", len);
            return readRespBody();
        }
    }
    else
        return readRespBody();
    return 0;
}
int HttpCgiTool::processHeaderLine(HttpExtConnector *pExtConn,
                                   const char  *pLineBegin,
                                   const char *pLineEnd, int &status)
{
    HttpRespHeaders::HEADERINDEX index;
    int tmpIndex;
    const char *pKeyEnd = NULL;
    const char *pValue = pLineBegin;
    char *p;
    HttpResp *pResp = pExtConn->getHttpSession()->getResp();
    HttpReq *pReq = pExtConn->getHttpSession()->getReq();

    index = HttpRespHeaders::getRespHeaderIndex(pValue);
    if (index < HttpRespHeaders::H_HEADER_END)
    {
        pValue += HttpRespHeaders::getHeaderStringLen(index);

        while (isspace(*pValue))
            ++pValue;
        pKeyEnd = pValue;
        if (*pValue != ':')
            index = HttpRespHeaders::H_HEADER_END;
        else
        {
            do { ++pValue; }
            while (isspace(*pValue));
        }
    }
    if (index == HttpRespHeaders::H_HEADER_END)
    {
        pKeyEnd = (char *)memchr(pValue, ':', pLineEnd - pValue);
        if (pKeyEnd != NULL)
        {
            pValue = pKeyEnd + 1;
            while (isspace(*pValue))
                ++pValue;
        }
        else
        {
            if (!isspace(*pLineBegin))
                return 0;
        }
    }
    switch (index)
    {
    case HttpRespHeaders::H_CONTENT_TYPE:
        if (pReq->getStatusCode() == SC_304)
            return 0;
        p = (char *)memchr(pValue, ';', pLineEnd - pValue);
        if (pReq->gzipAcceptable() == GZIP_REQUIRED)
        {
            char ch = 0;
            char *p1;
            if (p)
                p1 = (char *)p;
            else
                p1 = (char *)pLineEnd;
            ch = *p1;
            *p1 = 0;
            if (!HttpMime::getMime()->compressible(pValue))
                pReq->andGzip(~GZIP_ENABLED);
            *p1 = ch;
        }
        if (pReq->isKeepAlive())
            pReq->smartKeepAlive(pValue);
        {
            if (!HttpMime::needCharset(pValue))
                break;
            const AutoStr2 *pCharset = pReq->getDefaultCharset();
            if (!pCharset)
                break;
            if (p)
            {
                while (isspace(*(++p)))
                    ;
                if (strncmp(p, "charset=", 8) == 0)
                    break;
            }
            HttpRespHeaders &buf = pResp->getRespHeaders();
            AutoStr2 str = "";
            str.append(pLineBegin, pLineEnd - pLineBegin);
            str.append(pCharset->c_str(), pCharset->len());
            str.append("\r\n", 2);
            buf.parseAdd(str.c_str(), str.len(), LSI_HEADEROP_ADD);
        }
        return 0;
    case HttpRespHeaders::H_CONTENT_ENCODING:
        if (pReq->getStatusCode() == SC_304)
            return 0;
        if (strncasecmp(pValue, "gzip", 4) == 0)
            pReq->orGzip(UPSTREAM_GZIP);
        else if (strncasecmp(pValue, "deflate", 7) == 0)
            pReq->orGzip(UPSTREAM_DEFLATE);
//             if ( !(pReq->gzipAcceptable() & REQ_GZIP_ACCEPT) )
//                 return 0;
//         }
//         else //if ( strncasecmp( pValue, "deflate", 7 ) == 0 )
//         {
//             pReq->andGzip( ~GZIP_ENABLED );
//         }
        break;
    case HttpRespHeaders::H_LOCATION:
        if ((status & HEC_RESP_PROXY) || (pReq->getStatusCode() != SC_200))
            break;
    case HttpRespHeaders::H_LITESPEED_LOCATION:
        if (*pValue != '/')
        {
            //set status code to 307
            pReq->setStatusCode(SC_302);
        }
        else
        {
            if ((pReq->getStatusCode() == SC_404) ||
                (index == HttpRespHeaders::H_LITESPEED_LOCATION))
                pReq->setStatusCode(SC_200);
            if (index == HttpRespHeaders::H_LITESPEED_LOCATION)
            {
                char ch = *pLineEnd;
                *((char *)pLineEnd) = 0;
                pReq->locationToUrl(pValue, pLineEnd - pValue);
                *((char *)pLineEnd) = ch;
            }
            else
                pReq->setLocation(pValue, pLineEnd - pValue);
            pExtConn->getHttpSession()->changeHandler();
            //status |= HEC_RESP_LOC_SET;
            return 0;
        }
        break;
    case HttpRespHeaders::H_CGI_STATUS:
        tmpIndex = HttpStatusCode::getInstance().codeToIndex(pValue);
        if (tmpIndex != -1)
        {
            pReq->updateNoRespBodyByStatus(tmpIndex);
            if ((tmpIndex >= SC_300) && (tmpIndex < SC_400))
            {
                if (pReq->getLocation() != NULL)
                {
                    pResp->appendHeader("location: ", 10,
                                        pReq->getLocation(), pReq->getLocationLen());
                    pReq->clearLocation();
                }
            }
            if ((status & HEC_RESP_AUTHORIZER) && (tmpIndex == SC_200))
                status |= HEC_RESP_AUTHORIZED;
        }
        return 0;
    case HttpRespHeaders::H_TRANSFER_ENCODING:
        pResp->setContentLen(LSI_RSP_BODY_SIZE_CHUNKED);
        return 0;
        
    case HttpRespHeaders::H_SET_COOKIE:
        //pReq->getRespCacheCtrl().setHasCookie();
        pReq->processSetCookieHeader(pValue, pLineEnd - pValue);
        break;

    case HttpRespHeaders::H_PROXY_CONNECTION:
    case HttpRespHeaders::H_CONNECTION:
        if (strncasecmp(pValue, "close", 5) == 0)
            status |= HEC_RESP_CONN_CLOSE;
        return 0;
    case HttpRespHeaders::H_CONTENT_LENGTH:
        if (pResp->getContentLen() == LSI_RSP_BODY_SIZE_UNKNOWN)
        {
            off_t lContentLen = strtoll(pValue, NULL, 10);
            if ((lContentLen >= 0) && (lContentLen != LLONG_MAX))
            {
                pResp->setContentLen(lContentLen);
                status |= HEC_RESP_CONT_LEN;
                pReq->orContextState(RESP_CONT_LEN_SET);
            }
        }
    //fall through
    case HttpRespHeaders::H_KEEP_ALIVE:
    case HttpRespHeaders::H_SERVER:
    case HttpRespHeaders::H_DATE:
        return 0;
    default:
        //"script-control: no-abort" is not supported
        break;
    }
    if (status & HEC_RESP_AUTHORIZED)
    {
        if (strncasecmp(pLineBegin, "Variable-", 9) == 0)
        {
            if (pKeyEnd > pLineBegin + 9)
                RequestVars::setEnv(pExtConn->getHttpSession(), pLineBegin + 9,
                                    pKeyEnd - pLineBegin - 9,
                                    pValue, pLineEnd - pValue);
        }
        return 0;
    }
    assert(pKeyEnd);
    return pResp->appendHeader(pLineBegin, pKeyEnd - pLineBegin, pValue,
                               pLineEnd - pValue);
}
Example #24
0
int CgidConn::buildSSIExecHeader()
{
    static unsigned int s_id = 0;
    HttpSession *pSession = getConnector()->getHttpSession();
    HttpReq * pReq = pSession->getReq();
    const char * pReal;
    const AutoStr2 * psChroot;
    const char * pChroot;
    int ret;
    uid_t uid;
    gid_t gid;
    pReal = pReq->getRealPath()->c_str();
    ret = pReq->getUGidChroot( &uid, &gid, &psChroot );
    if ( ret )
        return ret;
//    if ( D_ENABLED( DL_LESS ) )
//        LOG_D(( getLogger(),
//            "[%s] UID: %d, GID: %d",
//            getLogId(), pHeader->m_uid, pHeader->m_gid ));
    if ( psChroot )
    {
//        if ( D_ENABLED( DL_LESS ) )
//            LOG_D(( getLogger(),
//                "[%s] chroot: %s, real path: %s",
//                getLogId(), pChroot->c_str(), pReal ));
        pChroot = psChroot->c_str();
        ret = psChroot->len();
    }
    else
    {
        pChroot = NULL;
        ret = 0;
    }
    char achBuf[4096];
    memccpy( achBuf, pReal, 0, 4096 );
    char * argv[256];
    char ** p;
    char * pDir ;
    SUExec::buildArgv( achBuf, &pDir, argv, 256 );
    if ( pDir )
        *(argv[0]-1) = '/';
    else
        pDir = argv[0];

    int priority = ((CgidWorker *)getWorker())->getConfig().getPriority();
    m_req.buildReqHeader( uid, gid, priority, pChroot, ret, pDir,
                strlen( pDir ),
                ((CgidWorker *)getWorker())->getConfig().getRLimits() );
    p = &argv[1];
    while( *p )
    {
        m_req.appendArgv( *p, strlen( *p ) );
        ++p;
    }
    m_req.appendArgv( NULL, 0 );

    HttpCgiTool::buildEnv( &m_req, pSession );

    m_req.finalize( s_id++, ((CgidWorker *)getWorker())->getConfig().getSecret(),
                     LSCGID_TYPE_CGI );
    return 0;
}
Example #25
0
int HttpCgiTool::processHeaderLine( HttpExtConnector * pExtConn, const char * pLineBegin,
                                const char * pLineEnd, int &status )
{
    int index;
    const char * pKeyEnd;
    const char * pValue = pLineBegin;
    char * p;
    HttpResp* pResp = pExtConn->getHttpConn()->getResp();
    HttpReq * pReq = pExtConn->getHttpConn()->getReq();
    
    index = HttpHeader::getRespHeaderIndex( pValue );
    if ( index < HttpHeader::H_HEADER_END )
    {
        pValue += HttpHeader::getHeaderStringLen( index );

        while( isspace(*pValue) )
            ++pValue;
        pKeyEnd = pValue;
        if ( *pValue != ':' )
        {
            index = HttpHeader::H_HEADER_END;
        }
        else
        {
            do { ++pValue; }
            while( isspace(*pValue) );
        }
    }
    if ( index == HttpHeader::H_HEADER_END )
    {
        pKeyEnd = (char *)memchr( pValue, ':', pLineEnd - pValue );
        if ( pKeyEnd != NULL )
        {
            pValue = pKeyEnd + 1;
            while( isspace(*pValue) )
                ++pValue;
        }
        else
        {
            if ( !isspace( *pLineBegin ) )
                return 0;
        }
    }
    switch( index )
    {
    case HttpHeader::H_CONTENT_TYPE:
        p = (char *)memchr( pValue, ';', pLineEnd - pValue );
        if ( pReq->gzipAcceptable() )
        {
            register char ch = 0;
            register char *p1;
            if ( p )
            {
                p1 = (char*)p;
            }
            else
                p1 = (char*)pLineEnd;
            ch = *p1;
            *p1 = 0;
            if ( !HttpGlobals::getMime()->compressable( pValue ) )
                pReq->setGzip( 0 );
            *p1 = ch;
        }
        if ( pReq->isKeepAlive() )
            pReq->smartKeepAlive( pValue );
        {
            if ( !HttpMime::needCharset( pValue ) )
                break;
            const AutoStr2 * pCharset = pReq->getDefaultCharset();
            if ( !pCharset )
                break;
            if ( p )
            {
                while( isspace( *(++p) ) )
                    ;
                if ( strncmp( p, "charset=", 8 ) == 0 )
                    break;
            }
            AutoBuf& buf = pResp->getOutputBuf();
            if ( buf.available() < pLineEnd - pLineBegin + pCharset->len() + 4 )
            {
                buf.grow( pLineEnd - pLineBegin + pCharset->len() + 4 );
            }
            buf.appendNoCheck( pLineBegin, pLineEnd - pLineBegin );
            buf.appendNoCheck( pCharset->c_str(), pCharset->len() );
            buf.appendNoCheck( "\r\n", 2 );
        }
        return 0;
    case HttpHeader::H_CONTENT_ENCODING:
        pReq->setGzip( 0 );
        break;
    case HttpHeader::H_LOCATION:
        if ( pReq->getStatusCode() != SC_200 )
            break;
        if ( *pValue != '/' )
        {
            //set status code to 307
            pReq->setStatusCode( SC_302 );
        }
        else
        {
            pReq->setLocation( pValue, pLineEnd - pValue );
            return 0;
        }
        break;
    case HttpHeader::CGI_STATUS:
        index = HttpStatusCode::codeToIndex( pValue );
        if ( index != -1 )
        {
            pReq->updateNoRespBodyByStatus( index );
            if (( index >= SC_300 )&&( index < SC_400 ))
            {
                if ( *pReq->getLocation() )
                {
                    pResp->appendHeader( "Location: ", 10,
                        pReq->getLocation(), pReq->getLocationLen() );
                    pReq->clearLocation();    
                }
            }
            if (( status & HEC_RESP_AUTHORIZER )&&( index == SC_200))
                status |= HEC_RESP_AUTHORIZED;
        }
        return 0;
    case HttpHeader::H_TRANSFER_ENCODING:
        pResp->setContentLen( -1 );
        return 0;
    case HttpHeader::H_PROXY_CONNECTION:
    case HttpHeader::H_CONNECTION:
        if ( strncasecmp( pValue, "close", 5 ) == 0 )
            status |= HEC_RESP_CONN_CLOSE;
        return 0;
    case HttpHeader::H_CONTENT_LENGTH:
        if ( pResp->getContentLen() >= 0 )
        {
            long lContentLen = strtol( pValue, NULL, 10 );
            if (( lContentLen >= 0 )&&( lContentLen != LONG_MAX ))
                pResp->setContentLen( lContentLen );
        }
        //fall through
    case HttpHeader::H_KEEP_ALIVE:
    case HttpHeader::H_SERVER:
    case HttpHeader::H_DATE:
        return 0;
    default:
        //"script-control: no-abort" is not supported
        break;
    }
    if ( status & HEC_RESP_AUTHORIZED )
    {
        if (strncasecmp( pLineBegin, "Variable-", 9 ) == 0 )
        {
            if ( pKeyEnd > pLineBegin + 9 )
                pReq->addEnv( pLineBegin + 9, pKeyEnd - pLineBegin - 9,
                            pValue, pLineEnd - pValue );
        }
        return 0;
    }
    return pResp->appendHeaderLine( pLineBegin, pLineEnd );
}
Example #26
0
int SSIEngine::processFileAttr(HttpSession *pSession,
                               SSIComponent *pComponent)
{
    SubstItem *pItem = (SubstItem *)pComponent->getFirstAttr();
    if (!pItem)
        return 0;
    int len;
    int attr = pItem->getSubType();
    char achBuf[4096];
    char *p = achBuf;
    len = 4096;
    if ((attr != SSI_INC_FILE) && (attr != SSI_INC_VIRTUAL))
        return 0;
    SSIRuntime *pRuntime = pSession->getReq()->getSSIRuntime();
    RequestVars::appendSubst(pItem, pSession, p, len,
                             0, pRuntime->getRegexResult());
    {
        if (achBuf[0] == 0)
        {
            len = snprintf(achBuf, 4096,
                           "[an error occurred while processing this directive]\n");
            pSession->appendDynBody(achBuf, len);
            return 0;
        }
        HttpReq *pReq = pSession->getReq();
        const char *pURI ;
        const char *p1;
        if ((attr == SSI_INC_FILE) || (achBuf[0] != '/'))
        {
            pURI = pReq->getRealPath()->c_str();
            p1 =  pURI + pReq->getRealPath()->len();
            while ((p1 > pReq->getRealPath()->c_str()) && p1[-1] != '/')
                --p1;
        }
        else
        {
            pURI = pReq->getDocRoot()->c_str();
            p1 = pURI + pReq->getDocRoot()->len();
        }
        int prefix_len = p1 - pURI;
        memmove(&achBuf[prefix_len], achBuf, p - achBuf);
        memmove(achBuf, pURI, prefix_len);
        p += prefix_len;
    }
    *p = 0;
    p = achBuf;
    struct stat st;
    if (ls_fio_stat(achBuf, &st) == -1)
    {
        pSession->appendDynBody("[error: stat() failed!\n", 23);
        return 0;
    }
    if (pComponent->getType() == SSIComponent::SSI_FSize)
    {
        long long size = st.st_size;
        len = snprintf(achBuf, 1024, "%lld", size);
    }
    else    //SSIComponent::SSI_Flastmod
    {
        struct tm *tm;
        tm = localtime(&st.st_mtime);
        len = strftime(achBuf, 1024, pRuntime
                       ->getConfig()->getTimeFmt()->c_str(), tm);
    }
    pSession->appendDynBody(achBuf, len);
    return 0;
}