22#include "moc_qgsfcgiserverresponse.cpp"
24#include <fcgi_stdio.h>
30#if defined( Q_OS_UNIX ) && !defined( Q_OS_ANDROID )
33#include <sys/socket.h>
39typedef struct QgsFCGXStreamData
44 unsigned char *buffStop;
54 int isAnythingWritten;
56 FCGX_Request *reqDataPtr;
61using namespace std::chrono_literals;
66 : mFeedback( std::move( feedback ) )
69 Q_ASSERT( mFeedback );
71 mShouldStop.store(
false );
73#if defined( Q_OS_UNIX ) && !defined( Q_OS_ANDROID )
74 if ( FCGI_stdout && FCGI_stdout->fcgx_stream && FCGI_stdout->fcgx_stream->data )
76 QgsFCGXStreamData *stream =
static_cast<QgsFCGXStreamData *
>( FCGI_stdout->fcgx_stream->data );
77 if ( stream && stream->reqDataPtr )
79 mIpcFd = stream->reqDataPtr->ipcFd;
84 QStringLiteral(
"FCGIServer" ),
91 QStringLiteral(
"FCGIServer" ),
100 mShouldStop.store(
true );
117#if defined( Q_OS_UNIX ) && !defined( Q_OS_ANDROID )
118 quint64 threadId =
reinterpret_cast<quint64
>( QThread::currentThreadId() );
120 mShouldStop.store(
false );
124 FD_ZERO( &setOptions );
125 FD_SET( mIpcFd, &setOptions );
127 struct timeval timeout;
129 timeout.tv_usec = 10000;
131 while ( !mShouldStop.load() )
135 int rv = select( mIpcFd + 1, &setOptions, NULL, NULL, &timeout );
150 const ssize_t x = recv( mIpcFd, &
c, 1, MSG_PEEK | MSG_DONTWAIT );
154 QgsDebugMsgLevel( QStringLiteral(
"FCGIServer %1: remote socket still connected. errno: %2, x: %3" )
175 if ( mMutex.try_lock_for( 333ms ) )
179 if ( mShouldStop.load() )
181 QgsDebugMsgLevel( QStringLiteral(
"FCGIServer::run %1: socket monitoring quits normally." ).arg( threadId ), 2 );
200 mBuffer.open( QIODevice::ReadWrite );
203 mSocketMonitoringThread = std::make_unique<QgsSocketMonitoringThread>( mFeedback );
214 mSocketMonitoringThread->stop();
222 mHeaders.remove( key );
227 mHeaders.insert( key, value );
232 return mHeaders.value( key );
243 mHeaders.insert( QStringLiteral(
"Status" ), QStringLiteral(
" %1" ).arg( code ) );
258 setHeader( QStringLiteral(
"Content-Type" ), QStringLiteral(
"text/html;charset=utf-8" ) );
259 write( QStringLiteral(
"<html><body>%1</body></html>" ).arg( message ) );
276 if ( mFeedback->isCanceled() )
279 FCGI_stdout->fcgx_stream->wasFCloseCalled =
true;
286 if ( !mHeaders.contains(
"Content-Length" ) )
288 mHeaders.insert( QStringLiteral(
"Content-Length" ), QString::number( mBuffer.pos() ) );
300 QMap<QString, QString>::const_iterator it;
301 for ( it = mHeaders.constBegin(); it != mHeaders.constEnd(); ++it )
303 fputs( it.key().toUtf8(), FCGI_stdout );
304 fputs(
": ", FCGI_stdout );
305 fputs( it.value().toUtf8(), FCGI_stdout );
306 fputs(
"\n", FCGI_stdout );
308 fputs(
"\n", FCGI_stdout );
317 mBuffer.buffer().clear();
319 else if ( mBuffer.bytesAvailable() > 0 )
321 QByteArray &ba = mBuffer.buffer();
322 const size_t count = fwrite( (
void * ) ba.data(), ba.size(), 1, FCGI_stdout );
324 qDebug() << QStringLiteral(
"Sent %1 blocks of %2 bytes" ).arg( count ).arg( ba.size() );
338 mBuffer.buffer().clear();
347 return mBuffer.data();
354 mBuffer.buffer().clear();
360 mHeaders.insert( QStringLiteral(
"Server" ), QStringLiteral(
" QGIS FCGI server - QGIS version %1" ).arg(
Qgis::version() ) );
static QString version()
Version string.
@ Warning
Warning 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.
virtual ~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)