int CNetCacheBlobFetchApp::OnException(std::exception& e, CNcbiOstream& os) { union { CArgException* arg_exception; CNetCacheException* nc_exception; }; string status_str; string message; if ((arg_exception = dynamic_cast<CArgException*>(&e)) != NULL) { status_str = "400 Bad Request"; message = arg_exception->GetMsg(); SetHTTPStatus(CRequestStatus::e400_BadRequest); } else if ((nc_exception = dynamic_cast<CNetCacheException*>(&e)) != NULL) { switch (nc_exception->GetErrCode()) { case CNetCacheException::eAccessDenied: status_str = "403 Forbidden"; message = nc_exception->GetMsg(); SetHTTPStatus(CRequestStatus::e403_Forbidden); break; case CNetCacheException::eBlobNotFound: status_str = "404 Not Found"; message = nc_exception->GetMsg(); SetHTTPStatus(CRequestStatus::e404_NotFound); break; default: return CCgiApplication::OnException(e, os); } } else return CCgiApplication::OnException(e, os); // Don't try to write to a broken output if (!os.good()) { return -1; } try { // HTTP header os << "Status: " << status_str << HTTP_EOL << "Content-Type: text/plain" HTTP_EOL HTTP_EOL << "ERROR: " << status_str << " " HTTP_EOL HTTP_EOL << message << HTTP_EOL; // Check for problems in sending the response if (!os.good()) { ERR_POST("CNetCacheBlobFetchApp::OnException() " "failed to send error page back to the client"); return -1; } } catch (exception& e) { NCBI_REPORT_EXCEPTION("(CGI) CNetCacheBlobFetchApp::OnException", e); } return 0; }
int CCgiApplication::Run(void) { // Value to return from this method Run() int result; // Try to run as a Fast-CGI loop if ( x_RunFastCGI(&result) ) { return result; } /// Run as a plain CGI application // Make sure to restore old diagnostic state after the Run() CDiagRestorer diag_restorer; #if defined(NCBI_OS_UNIX) // Disable SIGPIPE if not allowed. if ( !TParamAllowSigpipe::GetDefault() ) { signal(SIGPIPE, SIG_IGN); struct sigaction sigterm, sigtermold; memset(&sigterm, 0, sizeof(sigterm)); sigterm.sa_handler = SigTermHandler; sigterm.sa_flags = SA_RESETHAND; if (sigaction(SIGTERM, &sigterm, &sigtermold) == 0 && sigtermold.sa_handler != SIG_DFL) { sigaction(SIGTERM, &sigtermold, 0); } } // Compose diagnostics prefix PushDiagPostPrefix(NStr::IntToString(getpid()).c_str()); #endif PushDiagPostPrefix(GetEnvironment().Get(m_DiagPrefixEnv).c_str()); // Timing CTime start_time(CTime::eCurrent); // Logging for statistics bool is_stat_log = GetConfig().GetBool("CGI", "StatLog", false, 0, CNcbiRegistry::eReturn); bool skip_stat_log = false; auto_ptr<CCgiStatistics> stat(is_stat_log ? CreateStat() : 0); CNcbiOstream* orig_stream = NULL; //int orig_fd = -1; CNcbiStrstream result_copy; auto_ptr<CNcbiOstream> new_stream; try { _TRACE("(CGI) CCgiApplication::Run: calling ProcessRequest"); GetDiagContext().SetAppState(eDiagAppState_RequestBegin); m_Context.reset( CreateContext() ); _ASSERT(m_Context.get()); m_Context->CheckStatus(); ConfigureDiagnostics(*m_Context); x_AddLBCookie(); try { // Print request start message x_OnEvent(eStartRequest, 0); VerifyCgiContext(*m_Context); ProcessHttpReferer(); LogRequest(); try { m_Cache.reset( GetCacheStorage() ); } catch( exception& ex ) { ERR_POST_X(1, "Couldn't create cache : " << ex.what()); } bool skip_process_request = false; bool caching_needed = IsCachingNeeded(m_Context->GetRequest()); if (m_Cache.get() && caching_needed) { skip_process_request = GetResultFromCache(m_Context->GetRequest(), m_Context->GetResponse().out()); } if (!skip_process_request) { if( m_Cache.get() ) { list<CNcbiOstream*> slist; orig_stream = m_Context->GetResponse().GetOutput(); slist.push_back(orig_stream); slist.push_back(&result_copy); new_stream.reset(new CWStream(new CMultiWriter(slist), 0,0, CRWStreambuf::fOwnWriter)); m_Context->GetResponse().SetOutput(new_stream.get()); } GetDiagContext().SetAppState(eDiagAppState_Request); result = CCgiContext::ProcessCORSRequest( m_Context->GetRequest(), m_Context->GetResponse()) ? 0 : ProcessRequest(*m_Context); GetDiagContext().SetAppState(eDiagAppState_RequestEnd); m_Context->GetResponse().Finalize(); if (result != 0) { SetHTTPStatus(500); m_ErrorStatus = true; } else { if (m_Cache.get()) { m_Context->GetResponse().Flush(); if (m_IsResultReady) { if(caching_needed) SaveResultToCache(m_Context->GetRequest(), result_copy); else { auto_ptr<CCgiRequest> request(GetSavedRequest(m_RID)); if (request.get()) SaveResultToCache(*request, result_copy); } } else if (caching_needed) { SaveRequest(m_RID, m_Context->GetRequest()); } } } } } catch (CCgiException& e) { if ( x_DoneHeadRequest() ) { // Ignore errors after HEAD request has been finished. GetDiagContext().SetAppState(eDiagAppState_RequestEnd); } else { if ( e.GetStatusCode() < CCgiException::e200_Ok || e.GetStatusCode() >= CCgiException::e400_BadRequest ) { throw; } GetDiagContext().SetAppState(eDiagAppState_RequestEnd); // If for some reason exception with status 2xx was thrown, // set the result to 0, update HTTP status and continue. m_Context->GetResponse().SetStatus(e.GetStatusCode(), e.GetStatusMessage()); } result = 0; } #ifdef NCBI_OS_MSWIN // Logging - on MSWin this must be done before flushing the output. if ( is_stat_log && !skip_stat_log ) { stat->Reset(start_time, result); stat->Submit(stat->Compose()); } is_stat_log = false; #endif _TRACE("CCgiApplication::Run: flushing"); m_Context->GetResponse().Flush(); _TRACE("CCgiApplication::Run: return " << result); x_OnEvent(result == 0 ? eSuccess : eError, result); x_OnEvent(eExit, result); } catch (exception& e) { GetDiagContext().SetAppState(eDiagAppState_RequestEnd); if ( x_DoneHeadRequest() ) { // Ignore errors after HEAD request has been finished. result = 0; x_OnEvent(eSuccess, result); } else { // Call the exception handler and set the CGI exit code result = OnException(e, NcbiCout); x_OnEvent(eException, result); // Logging {{ string msg = "(CGI) CCgiApplication::ProcessRequest() failed: "; msg += e.what(); if ( is_stat_log ) { stat->Reset(start_time, result, &e); msg = stat->Compose(); stat->Submit(msg); skip_stat_log = true; // Don't print the same message again } }} // Exception reporting. Use different severity for broken connection. ios_base::failure* fex = dynamic_cast<ios_base::failure*>(&e); CNcbiOstream* os = m_Context.get() ? m_Context->GetResponse().GetOutput() : NULL; if ((fex && os && !os->good()) || m_OutputBroken) { if ( !TClientConnIntOk::GetDefault() ) { ERR_POST_X(13, Severity(TClientConnIntSeverity::GetDefault()) << "Connection interrupted"); } } else { NCBI_REPORT_EXCEPTION_X(13, "(CGI) CCgiApplication::Run", e); } } } #ifndef NCBI_OS_MSWIN // Logging if ( is_stat_log && !skip_stat_log ) { stat->Reset(start_time, result); stat->Submit(stat->Compose()); } #endif x_OnEvent(eEndRequest, 120); x_OnEvent(eExit, result); if (m_Context.get()) { m_Context->GetResponse().SetOutput(NULL); } return result; }