30#include <fcgi_stdio.h>
32using namespace Qt::StringLiterals;
34#if defined( Q_OS_UNIX ) && !defined( Q_OS_ANDROID )
37#include <sys/socket.h>
43typedef struct QgsFCGXStreamData
48 unsigned char *buffStop;
58 int isAnythingWritten;
60 FCGX_Request *reqDataPtr;
65using namespace std::chrono_literals;
70 : mFeedback( std::move( feedback ) )
72 Q_ASSERT( mFeedback );
74 mShouldStop.store(
false );
76#if defined( Q_OS_UNIX ) && !defined( Q_OS_ANDROID )
77 if ( FCGI_stdout && FCGI_stdout->fcgx_stream && FCGI_stdout->fcgx_stream->data )
79 QgsFCGXStreamData *stream =
static_cast<QgsFCGXStreamData *
>( FCGI_stdout->fcgx_stream->data );
80 if ( stream && stream->reqDataPtr )
82 mIpcFd = stream->reqDataPtr->ipcFd;
87 u
"FCGI_stdout stream data is null! Socket monitoring disabled."_s,
96 u
"FCGI_stdout is null! Socket monitoring disabled."_s,
107 mShouldStop.store(
true );
124#if defined( Q_OS_UNIX ) && !defined( Q_OS_ANDROID )
125 quint64 threadId =
reinterpret_cast<quint64
>( QThread::currentThreadId() );
130 FD_ZERO( &setOptions );
131 FD_SET( mIpcFd, &setOptions );
133 struct timeval timeout;
135 timeout.tv_usec = 10000;
137 while ( !mShouldStop.load() )
141 int rv = select( mIpcFd + 1, &setOptions,
nullptr,
nullptr, &timeout );
146 u
"FCGIServer %1: remote socket has been closed (select)! errno: %2"_s
159 const ssize_t x = recv( mIpcFd, &
c, 1, MSG_PEEK | MSG_DONTWAIT );
164 u
"FCGIServer %1: remote socket still connected. errno: %2, x: %3"_s
175 u
"FCGIServer %1: remote socket has been closed (recv)! errno: %2, x: %3"_s
189 if ( mMutex.try_lock_for( 333ms ) )
193 if ( mShouldStop.load() )
200 u
"FCGIServer::run %1: socket monitoring quits: no more socket."_s
217 mBuffer.open( QIODevice::ReadWrite );
220 mSocketMonitoringThread = std::make_unique<QgsSocketMonitoringThread>( mFeedback );
231 mSocketMonitoringThread->stop();
239 mHeaders.remove( key );
244 mHeaders.insert( key, value );
249 return mHeaders.value( key );
260 mHeaders.insert( u
"Status"_s, u
" %1"_s.arg( code ) );
275 setHeader( u
"Content-Type"_s, u
"text/html;charset=utf-8"_s );
276 write( u
"<html><body>%1</body></html>"_s.arg( message ) );
293 if ( mFeedback->isCanceled() )
296 FCGI_stdout->fcgx_stream->wasFCloseCalled =
true;
303 if ( !mHeaders.contains(
"Content-Length" ) )
305 mHeaders.insert( u
"Content-Length"_s, QString::number( mBuffer.pos() ) );
317 QMap<QString, QString>::const_iterator it;
318 for ( it = mHeaders.constBegin(); it != mHeaders.constEnd(); ++it )
320 fputs( it.key().toUtf8(), FCGI_stdout );
321 fputs(
": ", FCGI_stdout );
322 fputs( it.value().toUtf8(), FCGI_stdout );
323 fputs(
"\n", FCGI_stdout );
325 fputs(
"\n", FCGI_stdout );
334 mBuffer.buffer().clear();
336 else if ( mBuffer.bytesAvailable() > 0 )
338 QByteArray &ba = mBuffer.buffer();
339 const size_t count = fwrite( (
void * ) ba.data(), ba.size(), 1, FCGI_stdout );
341 qDebug() << u
"Sent %1 blocks of %2 bytes"_s.arg( count ).arg( ba.size() );
355 mBuffer.buffer().clear();
364 return mBuffer.data();
371 mBuffer.buffer().clear();
377 mHeaders.insert( u
"Server"_s, u
" QGIS FCGI server - QGIS version %1"_s.arg(
Qgis::version() ) );
static QString version()
Version string.
@ Warning
Warning message.
@ Info
Information message.
void setDefaultHeaders()
Set the default headers.
void clear() override
Reset all headers and content for this response.
void setHeader(const QString &key, const QString &value) override
Set Header entry Add Header entry to the response Note that it is usually an error to set Header afte...
void flush() override
Flushes the current output buffer to the network.
~QgsFcgiServerResponse() override
void removeHeader(const QString &key) override
Clear header Undo a previous 'setHeader' call.
QByteArray data() const override
Gets the data written so far.
QIODevice * io() override
Returns the underlying QIODevice.
bool headersSent() const override
Returns true if the headers have already been sent.
void setStatusCode(int code) override
Set the http status code.
QgsFcgiServerResponse(QgsServerRequest::Method method=QgsServerRequest::GetMethod)
Constructor for QgsFcgiServerResponse.
void sendError(int code, const QString &message) override
Send error This method delegates error handling at the server level.
void truncate() override
Truncate data.
void finish() override
Finish the response, ending the transaction.
QString header(const QString &key) const override
Returns the header value.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
Method
HTTP Method (or equivalent) used for the request.
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device.
void run()
main thread function
void stop()
Stop the thread.
QgsSocketMonitoringThread(std::shared_ptr< QgsFeedback > feedback)
Constructor for QgsSocketMonitoringThread.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define QgsDebugMsgLevel(str, level)