Skip to content

Commit

Permalink
Implement QgsFcgiRequest and QgsFcgiResponse
Browse files Browse the repository at this point in the history
  • Loading branch information
dmarteau committed Jan 10, 2017
1 parent 891e163 commit 64fc56c
Show file tree
Hide file tree
Showing 33 changed files with 1,101 additions and 595 deletions.
15 changes: 2 additions & 13 deletions python/server/qgsrequesthandler.sip
Expand Up @@ -66,32 +66,21 @@ class QgsRequestHandler
//! @note not available in Python bindings
virtual void setGetCoverageResponse( QByteArray* ba ) = 0;

virtual void setDefaultHeaders();

/** Set an HTTP header*/
virtual void setHeader( const QString &name, const QString &value ) = 0;

/** Remove an HTTP header*/
virtual int removeHeader( const QString &name ) = 0;
virtual void removeHeader( const QString &name ) = 0;

/** Delete all HTTP headers*/
virtual void clearHeaders() = 0;
virtual void clear() = 0;

/** Append the bytestream to response body*/
virtual void appendBody( const QByteArray &body ) = 0;

/** Clears the response body*/
virtual void clearBody() = 0;

/** Return the response body*/
virtual QByteArray body();

/** Set the info format string such as "text/xml"*/
virtual void setInfoFormat( const QString &format ) = 0;

/** Check whether there is any header set or the body is not empty*/
virtual bool responseReady() const = 0;

/** Send out HTTP headers and flush output buffer*/
virtual void sendResponse() = 0;

Expand Down
27 changes: 15 additions & 12 deletions python/server/qgsserver.sip
Expand Up @@ -165,7 +165,7 @@ class QgsServer
/** Creates the server instance
* @param captureOutput set to false for stdout output (FCGI)
*/
QgsServer( bool captureOutput = true );
QgsServer();
~QgsServer();

/** Set environment variable
Expand All @@ -175,22 +175,25 @@ class QgsServer
*/
void putenv( const QString &var, const QString &val );

/** Handles the request. The output is normally printed trough FCGI printf
* by the request handler or, in case the server has been invoked from python
* bindings, a flag is set that captures all the output headers and body, instead
* of printing it returns the output as a QPair of QByteArray.
/** Handles the request.
* The query string is normally read from environment
* but can be also passed in args and in this case overrides the environment
* variable
*
* @param queryString optional QString containing the query string
* @return the response headers and body QPair of QByteArray if called from python bindings, empty otherwise
* @param request a QgsServerRequest holding request parameters
* @param response a QgsServerResponse for handling response I/O)
*/
QPair<QByteArray, QByteArray> handleRequest( const QString& queryString = QString() );
/*
// The following code was used to test type conversion in python bindings
QPair<QByteArray, QByteArray> testQPair( QPair<QByteArray, QByteArray> pair );
*/
void handleRequest( const QgsServerRequest& request, QgsServerResponse& response );

/** Handles the request from query strinf
* The query string is normally read from environment
* but can be also passed in args and in this case overrides the environment
* variable.
*
* @param queryString QString containing the query string
* @return the response headers and body QPair of QByteArray
*/
QPair<QByteArray, QByteArray> handleRequest( const QString& queryString );

/** Returns a pointer to the server interface */
QgsServerInterface* serverInterface();
Expand Down
15 changes: 15 additions & 0 deletions python/server/qgsserverrequest.sip
Expand Up @@ -35,6 +35,11 @@ class QgsServerRequest
HeadMethod, PutMethod, GetMethod, PostMethod, DeleteMethod
};

/**
* Constructor
*/
QgsServerRequest();

/**
* Constructor
*
Expand Down Expand Up @@ -81,5 +86,15 @@ class QgsServerRequest
*/
virtual QByteArray data() const;

/**
* Set the request url
*/
void setUrl( const QUrl& url );

/**
* Set the request method
*/
void setMethod( Method method );

};

25 changes: 25 additions & 0 deletions python/server/qgsserverresponse.sip
Expand Up @@ -42,6 +42,13 @@ class QgsServerResponse
*/
virtual void setHeader( const QString& key, const QString& value ) = 0;

/**
* Clear header
* Undo a previous 'set_header' call
*/
virtual void clearHeader( const QString& key ) = 0;


/** Set the http return code
* @param code HTTP return code value
*/
Expand Down Expand Up @@ -76,5 +83,23 @@ class QgsServerResponse
*/
virtual QIODevice* io() = 0;

/**
* End the transaction
*/
virtual void finish() = 0;

/**
* Flushes the current output buffer to the network
*
* 'flush()' may be called multiple times. For HTTP transactions
* headers will be written on the first call to 'flush()'.
*/
virtual void flush() = 0;

/**
* Reset all headers and content for this response
*/
virtual void clear() = 0;

};

5 changes: 2 additions & 3 deletions src/server/CMakeLists.txt
Expand Up @@ -24,9 +24,6 @@ SET ( qgis_mapserv_SRCS
qgscapabilitiescache.cpp
qgsconfigcache.cpp
qgshttprequesthandler.cpp
# qgshttptransaction.cpp
qgsgetrequesthandler.cpp
qgspostrequesthandler.cpp
qgsowsserver.cpp
qgswmsserver.cpp
qgswfsserver.cpp
Expand Down Expand Up @@ -57,6 +54,8 @@ SET ( qgis_mapserv_SRCS
qgsserviceregistry.cpp
qgsserverrequest.cpp
qgsserverresponse.cpp
qgsfcgiserverresponse.cpp
qgsbufferserverresponse.cpp
#----------------------------
)
IF("${Qt5Network_VERSION}" VERSION_LESS "5.0.0")
Expand Down
14 changes: 12 additions & 2 deletions src/server/qgis_map_serv.cpp
Expand Up @@ -19,6 +19,7 @@
//for CMAKE_INSTALL_PREFIX
#include "qgsconfig.h"
#include "qgsserver.h"
#include "qgsfcgiserverresponse.h"

#include <fcgi_stdio.h>
#include <stdlib.h>
Expand All @@ -38,14 +39,23 @@ int fcgi_accept()
int main( int argc, char * argv[] )
{
QgsApplication app( argc, argv, getenv( "DISPLAY" ), QString(), QStringLiteral( "server" ) );
QgsServer server( false );
QgsServer server;
#ifdef HAVE_SERVER_PYTHON_PLUGINS
server.initPython();
#endif
// Starts FCGI loop
while ( fcgi_accept() >= 0 )
{
server.handleRequest();
QgsFcgiServerRequest request;
QgsFcgiServerResponse response( request.method() );
if ( ! request.hasError() )
{
server.handleRequest( request, response );
}
else
{
response.sendError( 400, "Bad request" );
}
}
app.exitQgis();
return 0;
Expand Down
148 changes: 148 additions & 0 deletions src/server/qgsbufferserverresponse.cpp
@@ -0,0 +1,148 @@
/***************************************************************************
qgsfcgiserverresponse.cpp
Define response wrapper for fcgi response
-------------------
begin : 2017-01-03
copyright : (C) 2017 by David Marteau
email : david dot marteau at 3liz dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsbufferserverresponse.h"
#include "qgslogger.h"
#include "qgsmessagelog.h"

#include <QDebug>

//
// QgsBufferServerResponse
//

QgsBufferServerResponse::QgsBufferServerResponse()
{
mBuffer.open( QIODevice::ReadWrite );
mHeadersWritten = false;
mFinished = false;
mReturnCode = 200;
}

QgsBufferServerResponse::~QgsBufferServerResponse()
{

}

void QgsBufferServerResponse::clearHeader( const QString& key )
{
if ( !mHeadersWritten )
mHeaders.remove( key );
}

void QgsBufferServerResponse::setHeader( const QString& key, const QString& value )
{
if ( ! mHeadersWritten )
mHeaders.insert( key, value );
}

void QgsBufferServerResponse::setReturnCode( int code )
{
mReturnCode = code;
}

void QgsBufferServerResponse::sendError( int code, const QString& message )
{
if ( mHeadersWritten )
{
QgsMessageLog::logMessage( "Cannot send error after headers written" );
return;
}

clear();
setReturnCode( code );
setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/plain; charset=utf-8" ) );
write( message );
finish();
}

QIODevice* QgsBufferServerResponse::io()
{
return &mBuffer;
}

void QgsBufferServerResponse::finish()
{
if ( mFinished )
{
QgsMessageLog::logMessage( "finish() called twice" );
return;
}

if ( !mHeadersWritten )
{
if ( ! mHeaders.contains( "Content-Length" ) )
{
mHeaders.insert( QStringLiteral( "Content-Length" ), QStringLiteral( "%1" ).arg( mBuffer.pos() ) );
}
}
flush();
mFinished = true;
}

void QgsBufferServerResponse::flush()
{
if ( ! mHeadersWritten )
{
mHeadersWritten = true;
}

mBuffer.seek( 0 );
QByteArray& ba = mBuffer.buffer();
mBody.append( ba );
ba.clear();
}


void QgsBufferServerResponse::clear()
{
if ( !mHeadersWritten )
mHeaders.clear();

mBuffer.seek( 0 );
mBuffer.buffer().clear();
}


//QgsBufferServerRequest
//
QgsBufferServerRequest::QgsBufferServerRequest( const QString& url, Method method, QByteArray* data )
: QgsServerRequest( url, method )
{
if ( data )
{
mData = *data;
}
}

QgsBufferServerRequest::QgsBufferServerRequest( const QUrl& url, Method method, QByteArray* data )
: QgsServerRequest( url, method )
{
if ( data )
{
mData = *data;
}
}

QgsBufferServerRequest::~QgsBufferServerRequest()
{
}



0 comments on commit 64fc56c

Please sign in to comment.