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;
103 mShouldStop.store(
true );
120#if defined( Q_OS_UNIX ) && !defined( Q_OS_ANDROID )
121 quint64 threadId =
reinterpret_cast<quint64
>( QThread::currentThreadId() );
126 FD_ZERO( &setOptions );
127 FD_SET( mIpcFd, &setOptions );
129 struct timeval timeout;
131 timeout.tv_usec = 10000;
133 while ( !mShouldStop.load() )
137 int rv = select( mIpcFd + 1, &setOptions,
nullptr,
nullptr, &timeout );
152 const ssize_t x = recv( mIpcFd, &
c, 1, MSG_PEEK | MSG_DONTWAIT );
156 QgsDebugMsgLevel( u
"FCGIServer %1: remote socket still connected. errno: %2, x: %3"_s
177 if ( mMutex.try_lock_for( 333ms ) )
181 if ( mShouldStop.load() )
202 mBuffer.open( QIODevice::ReadWrite );
205 mSocketMonitoringThread = std::make_unique<QgsSocketMonitoringThread>( mFeedback );
216 mSocketMonitoringThread->stop();
224 mHeaders.remove( key );
229 mHeaders.insert( key, value );
234 return mHeaders.value( key );
245 mHeaders.insert( u
"Status"_s, u
" %1"_s.arg( code ) );
260 setHeader( u
"Content-Type"_s, u
"text/html;charset=utf-8"_s );
261 write( u
"<html><body>%1</body></html>"_s.arg( message ) );
278 if ( mFeedback->isCanceled() )
281 FCGI_stdout->fcgx_stream->wasFCloseCalled =
true;
288 if ( !mHeaders.contains(
"Content-Length" ) )
290 mHeaders.insert( u
"Content-Length"_s, QString::number( mBuffer.pos() ) );
302 QMap<QString, QString>::const_iterator it;
303 for ( it = mHeaders.constBegin(); it != mHeaders.constEnd(); ++it )
305 fputs( it.key().toUtf8(), FCGI_stdout );
306 fputs(
": ", FCGI_stdout );
307 fputs( it.value().toUtf8(), FCGI_stdout );
308 fputs(
"\n", FCGI_stdout );
310 fputs(
"\n", FCGI_stdout );
319 mBuffer.buffer().clear();
321 else if ( mBuffer.bytesAvailable() > 0 )
323 QByteArray &ba = mBuffer.buffer();
324 const size_t count = fwrite( (
void * ) ba.data(), ba.size(), 1, FCGI_stdout );
326 qDebug() << u
"Sent %1 blocks of %2 bytes"_s.arg( count ).arg( ba.size() );
340 mBuffer.buffer().clear();
349 return mBuffer.data();
356 mBuffer.buffer().clear();
362 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())
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)