43 # if defined(NCBI_OS_UNIX)
50 #define NCBI_USE_ERRCODE_X Cgi_Fast_MT
77 m_ManagerStopped(
false)
126 "specified, but this functionality is not supported");
139 void (*old_sig_handler)(
int) = SIG_DFL;
140 if (handle_sigterm) {
144 TManager::setupSignals();
150 if ( !path.empty() ) {
151 #ifdef NCBI_COMPILER_MSVC
158 if (!
m_Manager->listen(
nullptr, path.c_str())) {
159 ERR_POST_X(1,
"CFastCgiApplicationMT::x_RunFastCGI: cannot run as a "
160 "standalone server at: '" << path <<
"'");
174 if (handle_sigterm) {
175 signal(SIGTERM, old_sig_handler);
177 ERR_POST(Message <<
"Caught SIGTERM and performed graceful shutdown.");
181 _TRACE(
"CFastCgiApplicationMT::x_RunFastCGI: return (FastCGI loop finished)");
201 bool skip_stat_log =
false;
205 unique_ptr<CNcbiOstream> new_stream;
207 shared_ptr<CCgiContext> context;
228 context->CheckStatus();
233 && context->GetRequest().GetEntries().find(
"exitfastcgi")
234 != context->GetRequest().GetEntries().end()) {
240 _TRACE(
"CFastCgiApplicationMT aborting by request");
256 _TRACE(
"CFastCgiApplicationMT calling ProcessRequest()");
260 if ( !self_ref.empty() ) {
266 shared_ptr<ICache> cache;
272 bool skip_process_request =
false;
274 if (cache.get() && caching_needed) {
276 context->GetResponse().out(), *cache);
279 if (!skip_process_request) {
287 list<CNcbiOstream*> slist;
288 orig_stream = context->GetResponse().GetOutput();
289 slist.push_back(orig_stream);
290 slist.push_back(&result_copy);
292 context->GetResponse().SetOutput(new_stream.get());
310 context->GetResponse().Finalize();
313 context->GetResponse().Flush();
319 if (saved_request.get())
322 }
else if (caching_needed) {
347 _TRACE(
"CFastCgiApplicationMT flushing");
348 context->GetResponse().Flush();
349 _TRACE(
"CFastCgiApplicationMT: done, status: " << x_result);
354 context->GetResponse().SetOutput(0);
355 context->GetRequest().SetInputStream(0);
357 catch (exception& e) {
361 if (os && !os->good()) {
367 context->GetResponse().SetOutput(0);
368 context->GetRequest().SetInputStream(0);
380 string msg =
"CCgiRequestProcessorMT::ProcessRequest() failed: ";
386 skip_stat_log =
true;
397 _TRACE(
"CCgiApplication::x_RunFastCGI: FINISHING(forced)");
406 _TRACE(
"CCgiRequestProcessor::x_ProcessThreadedRequest: FINISHING");
411 string msg =
m_Stat->Compose();
425 if (restart_code != 0) {
467 Fastcgipp::Request<char>::errorHandler();
475 const auto&
buf = environment().postBuffer();
483 const auto&
env = environment();
487 if ( !
env.userAgent.empty() )
m_Env.
Set(
"HTTP_USER_AGENT",
env.userAgent);
488 if ( !
env.acceptContentTypes.empty() )
m_Env.
Set(
"HTTP_ACCEPT",
env.acceptContentTypes);
489 if ( !
env.acceptCharsets.empty() )
m_Env.
Set(
"HTTP_ACCEPT_CHARSET",
env.acceptCharsets);
490 if ( !
env.authorization.empty() )
m_Env.
Set(
"HTTP_AUTHORIZATION",
env.authorization);
491 if ( !
env.referer.empty() )
m_Env.
Set(
"HTTP_REFERER",
env.referer);
492 if ( !
env.contentType.empty() )
m_Env.
Set(
"CONTENT_TYPE",
env.contentType);
494 if ( !
env.scriptName.empty() )
m_Env.
Set(
"SCRIPT_NAME",
env.scriptName);
495 if ( !
env.requestUri.empty() )
m_Env.
Set(
"REQUEST_URI",
env.requestUri);
503 switch (
env.requestMethod) {
505 case Fastcgipp::Http::RequestMethod::GET:
m_Env.
Set(
"REQUEST_METHOD",
"GET");
break;
506 case Fastcgipp::Http::RequestMethod::POST:
m_Env.
Set(
"REQUEST_METHOD",
"POST");
break;
507 case Fastcgipp::Http::RequestMethod::PUT:
m_Env.
Set(
"REQUEST_METHOD",
"PUT");
break;
508 case Fastcgipp::Http::RequestMethod::DELETE:
m_Env.
Set(
"REQUEST_METHOD",
"DELETE");
break;
509 case Fastcgipp::Http::RequestMethod::TRACE:
m_Env.
Set(
"REQUEST_METHOD",
"TRACE");
break;
510 case Fastcgipp::Http::RequestMethod::OPTIONS:
m_Env.
Set(
"REQUEST_METHOD",
"OPTIONS");
break;
511 case Fastcgipp::Http::RequestMethod::CONNECT:
m_Env.
Set(
"REQUEST_METHOD",
"CONNECT");
break;
513 ERR_POST_X(3,
"REQUEST_METHOD not set or not supported");
517 if (
env.serverAddress ) {
523 if (
env.remoteAddress ) {
529 if (
env.ifModifiedSince ) {
537 for (
const auto& lang :
env.acceptLanguages) {
538 if (!languages.empty()) languages +=
", ";
541 if ( !languages.empty() )
m_Env.
Set(
"HTTP_ACCEPT_LANGUAGE", languages);
545 for (
const auto& element :
env.pathInfo) {
550 if (!
env.cookies.empty()) {
552 for (
const auto& cookie :
env.cookies) {
553 if (!cookies.empty()) cookies +=
"; ";
560 if (!
env.gets.empty()) {
562 for (
const auto& arg :
env.gets) {
570 for (
const auto& it :
env.others) {
Exception classes used by the NCBI CGI framework.
CCgiRequestException –.
Base class for request processors.
IWriter which can write simultaneously to the different streams.
@ fOwnWriter
Own the underlying writer.
Writer-based output stream.
static const struct name_t names[]
DEFINE_STATIC_FAST_MUTEX(s_ManagerMutex)
void s_ScheduleFastCGIMTExit(void)
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
const CNcbiArguments & GetArguments(void) const
Get the application's cached unprocessed command-line arguments.
void RunIdler(void)
Execute currently installed idler if any.
unsigned int GetFastCGIWatchFileTimeout(bool have_watcher) const
virtual ~CCgiRequestProcessorMT(void)
void SetOutputBroken(bool val)
unique_ptr< CCgiStatistics > m_Stat
bool GetFastCGIComplete_Request_On_Sigterm(void) const
bool CheckMemoryLimit(void)
CCgiRequestProcessorMT(CFastCgiApplicationMT &app)
bool x_RunFastCGI(int *result, unsigned int def_iter=10) override
unsigned int GetFastCGIIterations(unsigned int def_iter) const
unsigned int GetFastCGIMTMaxThreads(void) const
CAtomicCounter m_Iteration
int GetFastCGIWatchFileRestartDelay(void) const
virtual int ProcessRequest(CCgiContext &context)
Process request provided by the context. By default calls application's ProcessRequest.
static CTime GetFileModificationTime(const string &filename)
bool GetFastCGIStatLog(void) const
void SetCacheStream(CNcbiOstream &stream)
CFastCgiApplicationMT(const SBuildInfo &build_info=NCBI_SBUILDINFO_DEFAULT())
bool GetFastCGIStopIfFailed(void) const
static bool ProcessCORSRequest(const CCgiRequest &request, CCgiResponse &response)
Process cross-origin resource sharing (CORS) request.
bool x_ProcessHelpRequest(CCgiRequestProcessor &processor)
Fastcgipp::Manager< CFastCgiThreadedRequest > TManager
unique_ptr< TManager > m_Manager
string GetFastCGIStandaloneServer(void) const
static ERestartReason ShouldRestart(CTime &mtime, CCgiWatchFile *watcher, int delay)
unsigned int m_WatchTimeout
void Set(const string &name, const string &value)
bool x_ProcessAdminRequest(CCgiRequestProcessor &processor)
~CFastCgiThreadedRequest(void)
virtual CCgiContext * CreateContext(CNcbiArguments *args=0, CNcbiEnvironment *env=0, CNcbiIstream *inp=0, CNcbiOstream *out=0, int ifd=-1, int ofd=-1)
Factory method for the Context object construction.
void x_OnEvent(CCgiRequestProcessor *pprocessor, EEvent event, int status)
virtual ICache * GetCacheStorage(void) const
unique_ptr< CNcbiResource > m_Resource
virtual int OnException(std::exception &e, CNcbiOstream &os)
unique_ptr< CCgiWatchFile > m_Watcher
virtual bool ValidateSynchronizationToken(void)
CCgiApplication & GetApp(void)
string GetRID(void) const
void errorHandler(void) override
virtual bool IsCachingNeeded(const CCgiRequest &request) const
virtual CCgiStatistics * CreateStat()
Class factory for statistics class.
~CFastCgiApplicationMT(void)
void SaveResultToCache(const CCgiRequest &request, CNcbiIstream &is, ICache &cache)
bool x_ProcessVersionRequest(CCgiRequestProcessor &processor)
void SetContext(shared_ptr< CCgiContext > context)
void SaveRequest(const string &rid, const CCgiRequest &request, ICache &cache)
CAtomicCounter m_ErrorCounter
void FASTCGI_ScheduleExit(void) override
Schedule Fast-CGI loop to end as soon as possible, after safely finishing the currently processed req...
static CCgiApplication * Instance(void)
Singleton.
bool inProcessor(void) override
CCgiRequestProcessor & x_CreateProcessor(void)
CCgiRequest * GetSavedRequest(const string &rid, ICache &cache)
string GetSelfReferer(void) const
Get self-URL to be used as referer.
const char *const * env(void) const
CFastCgiThreadedRequest(void)
CRef< CTls< CCgiRequestProcessor > > m_Processor
void x_ParseEnv(void) const
shared_ptr< istream > m_InputStream
void x_ProcessThreadedRequest(CFastCgiThreadedRequest &req)
bool GetFastCGIDebug(void) const
CCgiWatchFile * CreateFastCGIWatchFile(void) const
bool response(void) override
unsigned int m_MaxIterations
bool GetResultReady(void) const
bool GetResultFromCache(const CCgiRequest &request, CNcbiOstream &os, ICache &cache)
void LogRequest(void) const
bool GetFastCGIHonorExitRequest(void) const
void VerifyCgiContext(CCgiContext &context)
Check CGI context for possible problems, throw exception with HTTP status set if something is wrong.
void AddLBCookie(CCgiCookies &cookies)
static CFastCgiApplicationMT * Instance(void)
Singleton.
@ eException
An exception occured during the request processing.
@ eExitRequest
FCGI forced to exit by client's 'exitfastcgi' request.
@ eExit
No more iterations, exiting (called the very last)
@ eError
The HTTP request was processed, non-zero exit code.
@ eEndRequest
HTTP request processed, all results sent to client.
@ eExecutable
FCGI forced to exit as its modif. time has changed.
@ eWatchFile
FCGI forced to exit as its "watch file" has changed.
@ eExitOnFail
[FastCGI].StopIfFailed set, and the iteration failed
@ eSuccess
The HTTP request was processed, with zero exit code.
#define NCBI_CGI_THROW_WITH_STATUS(exception, err_code, message, status)
EStatusCode GetStatusCode(void) const
string GetStatusMessage(void) const
TNCBIAtomicValue TValue
Alias TValue for TNCBIAtomicValue.
void Set(TValue new_value) THROWS_NONE
Set atomic counter value.
TValue Add(int delta) THROWS_NONE
Atomically add value (=delta), and return new counter value.
TValue Get(void) const THROWS_NONE
Get atomic counter value.
void SetBytesWr(Int8 bytes)
CDiagContext & GetDiagContext(void)
Get diag context instance.
void SetAppState(EDiagAppState state)
Set application state.
void SetDiagRequestId(Uint8 id)
Set iteration number/request ID.
void SetProperty(const string &name, const string &value)
Add/change property.
static CRequestContext & GetRequestContext(void)
Shortcut to CDiagContextThreadData::GetThreadData().GetRequestContext()
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
void SetBytesRd(Int8 bytes)
void AddPassThroughProperty(const string &name, const string &value)
Add pass-through value if it matches a pattern from NCBI_CONTEXT_FIELDS.
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
@ eDiagAppState_RequestEnd
RE.
@ eDiagAppState_AppEnd
AE.
@ eDiagAppState_RequestBegin
RB.
@ eDiagAppState_Request
R.
#define NCBI_CATCH_ALL_X(err_subcode, message)
void Warning(CExceptionArgs_Base &args)
#define NCBI_REPORT_EXCEPTION_X(err_subcode, title, ex)
Generate a report on the exception with default error code and given subcode.
static TPid GetPid(void)
Get process identifier (pid) for the current process.
#define END_NCBI_SCOPE
End previously defined NCBI scope.
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Int8 NcbiStreamposToInt8(NCBI_NS_STD::char_traits< char >::pos_type stream_pos)
Convert stream position to 64-bit int.
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
static string & Replace(const string &src, const string &search, const string &replace, string &dst, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
static string URLEncode(const CTempString str, EUrlEncode flag=eUrlEnc_SkipMarkChars)
URL-encode string.
@ eUrlEnc_URIQueryValue
Encode query part of an URI, arg value.
@ eUrlEnc_URIQueryName
Encode query part of an URI, arg name.
@ eUrlEnc_Path
Same as ProcessMarkChars but preserves valid path characters ('/', '.')
@ eUrlEnc_Cookie
Same as SkipMarkChars with encoded ','.
@ eCurrent
Use current time. See also CCurrentTime.
@ eGmt
GMT (Greenwich Mean Time)
unsigned int
A callback function used to compare two keys in a database.
Interfaces for a local cache of versioned binary large objects (BLOBS).
Definition of all error codes used in cgi (xcgi.lib).
Defines unified interface to application:
#define GetProgramName
Avoid name clash with the NCBI C Toolkit.
Defines CRequestContext class for NCBI C++ diagnostic API.
This class allows to add build info (date and tag) to application version.