Skip to content
Permalink
Browse files

Implement QgsFcgiRequest and QgsFcgiResponse

  • Loading branch information
dmarteau committed Jan 10, 2017
1 parent 891e163 commit 64fc56c808570ae53a46bd94fd15c3dfa7dbc4f8
Showing with 1,101 additions and 595 deletions.
  1. +2 −13 python/server/qgsrequesthandler.sip
  2. +15 −12 python/server/qgsserver.sip
  3. +15 −0 python/server/qgsserverrequest.sip
  4. +25 −0 python/server/qgsserverresponse.sip
  5. +2 −3 src/server/CMakeLists.txt
  6. +12 −2 src/server/qgis_map_serv.cpp
  7. +148 −0 src/server/qgsbufferserverresponse.cpp
  8. +119 −0 src/server/qgsbufferserverresponse.h
  9. +258 −0 src/server/qgsfcgiserverresponse.cpp
  10. +98 −0 src/server/qgsfcgiserverresponse.h
  11. +0 −44 src/server/qgsgetrequesthandler.cpp
  12. +0 −32 src/server/qgsgetrequesthandler.h
  13. +106 −208 src/server/qgshttprequesthandler.cpp
  14. +14 −18 src/server/qgshttprequesthandler.h
  15. +0 −89 src/server/qgspostrequesthandler.cpp
  16. +0 −33 src/server/qgspostrequesthandler.h
  17. +9 −34 src/server/qgsrequesthandler.h
  18. +88 −61 src/server/qgsserver.cpp
  19. +23 −13 src/server/qgsserver.h
  20. +0 −2 src/server/qgsserverinterfaceimpl.h
  21. +43 −2 src/server/qgsserverrequest.cpp
  22. +34 −1 src/server/qgsserverrequest.h
  23. +4 −3 src/server/qgsserverresponse.cpp
  24. +28 −1 src/server/qgsserverresponse.h
  25. +1 −0 src/server/qgsservice.h
  26. +2 −0 src/server/qgsservicemodule.h
  27. +2 −0 src/server/qgsservicenativeloader.h
  28. +5 −0 src/server/services/DummyService/CMakeLists.txt
  29. +5 −0 src/server/services/wms/CMakeLists.txt
  30. +1 −2 tests/src/python/qgis_wrapped_server.py
  31. +5 −6 tests/src/python/test_qgsserver.py
  32. +1 −1 tests/src/python/test_qgsserver_accesscontrol.py
  33. +36 −15 tests/src/python/test_qgsserver_services.py
@@ -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;

@@ -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
@@ -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();
@@ -35,6 +35,11 @@ class QgsServerRequest
HeadMethod, PutMethod, GetMethod, PostMethod, DeleteMethod
};

/**
* Constructor
*/
QgsServerRequest();

/**
* Constructor
*
@@ -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 );

};

@@ -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
*/
@@ -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;

};

@@ -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
@@ -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")
@@ -19,6 +19,7 @@
//for CMAKE_INSTALL_PREFIX
#include "qgsconfig.h"
#include "qgsserver.h"
#include "qgsfcgiserverresponse.h"

#include <fcgi_stdio.h>
#include <stdlib.h>
@@ -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;
@@ -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.
You can’t perform that action at this time.