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; }
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; }
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; }
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 ); }
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; }
int RewriteEngine::getSubstValue( const RewriteSubstItem * pItem, HttpConnection *pConn, char * &pValue, int bufLen ) { HttpReq * pReq = pConn->getReq(); int type = pItem->getType(); int i; if ( type < REF_STRING ) { pValue = (char *)pReq->getHeader( type ); if ( *pValue ) return pReq->getHeaderLen( type ); else return 0; } /* if ( type >= REF_TIME ) { time_t t = time(NULL); struct tm *tm = localtime(&t); switch( type ) { case REF_TIME: i = snprintf( pValue, bufLen, "%04d%02d%02d%02d%02d%02d", tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); break; case REF_TIME_YEAR: i = snprintf( pValue, bufLen, "%04d", tm->tm_year + 1900); break; case REF_TIME_MON: i = snprintf( pValue, bufLen, "%02d", tm->tm_mon+1 ); break; case REF_TIME_DAY: i = snprintf( pValue, bufLen, "%02d", tm->tm_mday); break; case REF_TIME_HOUR: i = snprintf( pValue, bufLen, "%02d", tm->tm_hour); break; case REF_TIME_MIN: i = snprintf( pValue, bufLen, "%02d", tm->tm_min); break; case REF_TIME_SEC: i = snprintf( pValue, bufLen, "%02d", tm->tm_sec); break; case REF_TIME_WDAY: i = snprintf( pValue, bufLen, "%d", tm->tm_wday); break; default: return 0; } return i; } */ switch( type ) { case REF_STRING: pValue = (char *)pItem->getStr()->c_str(); return pItem->getStr()->len(); case REF_MAP: { MapRefItem * pRef = pItem->getMapRef(); int len = 1024; char achBuf[1024]; if ( buildString( pRef->getKeyFormat(), pConn, achBuf, len ) == NULL ) return 0; if ( (len = pRef->getMap()->lookup( achBuf, len, pValue, bufLen )) == -1 ) { if ( pRef->getDefaultFormat() ) { if ( buildString( pRef->getDefaultFormat(), pConn, pValue, bufLen ) == NULL ) return 0; len = bufLen; } else len = 0; } return len; } break; case REF_RULE_SUBSTR: return getSubstr( m_pSourceURL, m_ruleVec, m_ruleMatches, pItem->getIndex(), pValue, m_flag & RULE_FLAG_BR_ESCAPE ); case REF_COND_SUBSTR: return getSubstr( m_pCondBuf, m_condVec, m_condMatches, pItem->getIndex(), pValue, m_flag & RULE_FLAG_BR_ESCAPE ); case REF_ENV: pValue = (char *)RequestVars::getEnv( pConn, pItem->getStr()->c_str(), pItem->getStr()->len(), i ); if ( !pValue ) { i = 0; } return i; case REF_HTTP_HEADER: pValue = (char *)pReq->getHeader( pItem->getStr()->c_str(), pItem->getStr()->len(), i ); if ( !pValue ) i = 0; return i; case REF_REQUST_FN: case REF_SCRIPTFILENAME: if ( m_iScriptLen == -1 ) { pReq->checkPathInfo( m_pSourceURL, m_sourceURLLen, m_iFilePathLen, m_iScriptLen, m_iPathInfoLen, m_pContext ); } pValue = HttpGlobals::g_achBuf; //if ( m_pStrip ) // return m_iFilePathLen; //else // return m_iFilePathLen + m_iPathInfoLen; return m_iFilePathLen; case REF_PATH_INFO: if ( m_iScriptLen == -1 ) { pReq->checkPathInfo( m_pSourceURL, m_sourceURLLen, m_iFilePathLen, m_iScriptLen, m_iPathInfoLen, m_pContext ); } pValue = &HttpGlobals::g_achBuf[ m_iFilePathLen ]; return m_iPathInfoLen; case REF_SCRIPT_NAME: if ( m_iScriptLen == -1 ) { pReq->checkPathInfo( m_pSourceURL, m_sourceURLLen, m_iFilePathLen, m_iScriptLen, m_iPathInfoLen, m_pContext ); } pValue = (char *)pReq->getOrgReqURL(); return m_iScriptLen; case REF_REQ_URI: //in rewrite rule, this does not include Query String part if ( pReq->getRedirects() == 0 ) { pValue = (char *)pReq->getOrgReqURL(); return pReq->getOrgReqURILen(); } if ( m_pStrip ) { memmove( pValue, m_pStrip->c_str(), m_pStrip->len() ); memmove( pValue + m_pStrip->len(), m_pSourceURL, m_sourceURLLen ); return m_pStrip->len() + m_sourceURLLen; } //fall through case REF_CUR_URI: pValue = (char *)m_pSourceURL; return m_sourceURLLen; case REF_QUERY_STRING: pValue = (char *)m_pQS; return m_qsLen; default: return RequestVars::getReqVar( pConn, type, pValue, bufLen ); } return 0; }
int 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; }
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; }
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; }
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; }
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; }
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(); } }
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(); } }
// 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(); }
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); }
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; }
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 ); }
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; }