aboutsummaryrefslogtreecommitdiff
path: root/src/3rd/flibs/src/cgi/cgi_protocol.f90
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rd/flibs/src/cgi/cgi_protocol.f90')
-rwxr-xr-xsrc/3rd/flibs/src/cgi/cgi_protocol.f90541
1 files changed, 541 insertions, 0 deletions
diff --git a/src/3rd/flibs/src/cgi/cgi_protocol.f90 b/src/3rd/flibs/src/cgi/cgi_protocol.f90
new file mode 100755
index 0000000..6ce9f0b
--- /dev/null
+++ b/src/3rd/flibs/src/cgi/cgi_protocol.f90
@@ -0,0 +1,541 @@
+! cgi_protocol.f90 --
+! Module for interfacing with a web server via the CGI protocol
+! (GET, POST, ...)
+!
+! TODO:
+! - find out how to deal with text area data
+! - find out how to deal with uploaded files
+! - merge environment variables into the cgi_get routines
+! - implement the SCGI protocol
+! - implement delayed responses (also via customisable template)
+!
+module cgi_protocol
+ implicit none
+
+ integer, parameter :: DICT_KEY_LENGTH = 80
+ integer, parameter :: DICT_VALUE_LENGTH = 200
+ integer, parameter :: DICT_BUFFER_LENGTH = DICT_KEY_LENGTH + DICT_VALUE_LENGTH + 1
+
+ integer, parameter :: output_no_header = 0
+ integer, parameter :: output_html = 1
+ integer, parameter :: output_text = 2
+ integer, parameter, private :: output_html_delayed = 3 ! Not implemented yet!
+ integer, parameter, private :: output_text_delayed = 4
+
+ type DICT_DATA
+ character(len=DICT_VALUE_LENGTH) :: value
+ end type DICT_DATA
+
+ interface cgi_get
+ module procedure cgi_get_string
+ module procedure cgi_get_integer
+ module procedure cgi_get_real
+ end interface
+
+ type(DICT_DATA), parameter :: dict_null = dict_data('')
+
+ integer, private, save :: method = -1
+ integer, private, save :: luout_cgi = -1
+ logical, private, save :: header_written
+
+!
+! Body of source code for storing and retrieving the data
+! (also contains the CONTAINS clause)
+!
+include 'dictionary.f90'
+
+! cgi_begin --
+! Determine the type of interaction with the server and retrieve the data
+!
+! Arguments:
+! html Whether the output will be HTML or plain text
+! dict Dictionary holding the information from the server (output)
+! luout LU-number for writing the file (output!)
+!
+! Note:
+! This routine determines the way the server passes on the data
+! by looking for clues in the environment variables QUERY_LENGTH
+! and QUERY_STRING
+!
+!
+! TODO:
+! Support for two-pass run (if the computation takes a longer
+! than a few seconds)
+!
+subroutine cgi_begin( html, dict, luout )
+ integer, intent(in) :: html
+ type(DICT_STRUCT), pointer :: dict
+ integer, intent(out) :: luout
+
+ integer :: length
+ integer :: status
+ logical :: opend
+ character(len=DICT_BUFFER_LENGTH) :: string
+ character(len=1) :: ch
+
+ !
+ ! Clean up, if necessary
+ !
+ if ( associated(dict) ) then
+ call dict_destroy( dict )
+ endif
+
+ header_written = .false.
+
+ !
+ ! Determine which input method
+ !
+ call get_environment_variable( "QUERY_STRING", length=length, status=status )
+ if ( status == 0 ) then
+ call cgi_get_method( dict, length )
+ method = 1
+ else
+ call get_environment_variable( "CONTENT_LENGTH", value=string, status=status )
+ if ( status == 0 ) then
+ read( string, * ) length
+ call cgi_post_method( dict, length )
+ method = 1
+ else
+ read( *, '(A)', advance = 'no' ) ch
+ if ( ch == '%' ) then
+ !
+ ! TODO: better method for determining length
+ call cgi_dustmote_method( dict )
+ method = 2
+ elseif ( index( '1234567890', ch ) > 0 ) then
+ ! call cgi_simple_cgi( dict )
+ method = -1
+ else
+ method = -1
+ endif
+ endif
+ endif
+
+ !
+ ! If we did not get the correct information, just blow the
+ ! whole thing off
+ !
+ if ( method == -1 ) then
+ call cgi_error( "CGI protocol not recognised or not implemented" )
+ endif
+
+ !
+ ! What LU-number for the output
+ ! method 1: write directly to standard output (assumed to be at unit 6)
+ ! method 2: write to a file first (cgiout)
+ !
+ if ( method == 1 ) then
+ luout = 6
+ endif
+ if ( method == 2 ) then
+ do luout = 10,99
+ inquire( luout, opened = opend )
+ if ( .not. opend ) then
+ exit
+ endif
+ enddo
+ open( luout, file = 'cgiout' )
+ endif
+ luout_cgi = luout
+
+ !
+ ! Write the header lines
+ !
+ select case ( html )
+ case ( output_html, output_text )
+ call cgi_header( html )
+ case( output_html_delayed, output_text_delayed )
+ ! TODO
+ case( output_no_header )
+ ! Writing the header is delayed, because the type is not known yet
+ case default
+ call cgi_error( "Programming error: wrong value for parameter 'html' in CGI_BEGIN" )
+ end select
+
+end subroutine cgi_begin
+
+! cgi_header --
+! Write the CGI header information
+!
+! Arguments:
+! type Type of header
+!
+subroutine cgi_header( type )
+ integer, intent(in) :: type
+
+ header_written = .true.
+
+ select case ( type )
+ case ( output_html, output_html_delayed )
+ write( luout_cgi, '(a)' ) 'Content-Type: text/html;charset=iso8859-1'
+ write( luout_cgi, '(a)' ) ''
+ case( output_text, output_text_delayed )
+ write( luout_cgi, '(a)' ) 'Content-Type: text/plain;charset=iso8859-1'
+ write( luout_cgi, '(a)' ) ''
+ case( output_no_header )
+ call cgi_error( "Programming error: value 'output_no_header' not allowed in CGI_HEADER" )
+ case default
+ call cgi_error( "Programming error: wrong value for parameter 'type' in CGI_HEADER" )
+ end select
+end subroutine cgi_header
+
+! cgi_get_method --
+! Get the information via the environment variable QUERY_STRING
+!
+! Arguments:
+! dict Dictionary holding the information from the server (output)
+! length Total length of the input
+!
+subroutine cgi_get_method( dict, length )
+ type(DICT_STRUCT), pointer :: dict
+ integer, intent(in) :: length
+
+ character(len=length) :: buffer
+
+ call get_environment_variable( "QUERY_STRING", value=buffer )
+ call cgi_store_dict( dict, buffer )
+
+end subroutine cgi_get_method
+
+! cgi_post_method --
+! Get the information via standard input
+!
+! Arguments:
+! dict Dictionary holding the information from the server (output)
+! length Total length of the input
+!
+subroutine cgi_post_method( dict, length )
+ type(DICT_STRUCT), pointer :: dict
+ integer, intent(in) :: length
+
+ character(len=length) :: buffer
+
+ read( *, '(a)', advance='no' ) buffer
+ call cgi_store_dict( dict, buffer )
+
+end subroutine cgi_post_method
+
+! cgi_dustmote_method --
+! Get the information line by line
+!
+! Arguments:
+! dict Dictionary holding the information from the server (output)
+!
+!
+subroutine cgi_dustmote_method( dict )
+ type(DICT_STRUCT), pointer :: dict
+
+ type(DICT_DATA) :: data
+ character(len=DICT_KEY_LENGTH) :: key
+ character(len=DICT_BUFFER_LENGTH) :: input
+ integer :: k
+ integer :: lu
+ integer :: ierr
+ logical :: opend
+
+ read( *, '(a)' ) input ! Skip the remainder of the first line
+ read( *, '(a)' ) input
+
+ do while ( input /= '%END%' )
+ call cgi_store_dict( dict, input )
+
+ read( *, '(a)', iostat=ierr ) input
+ if ( ierr /= 0 ) then
+ exit
+ endif
+ enddo
+
+end subroutine cgi_dustmote_method
+
+! cgi_store_dict --
+! Store the information in the dictionary
+!
+! Arguments:
+! dict Dictionary holding all information
+! string Complete string received from CGI server
+!
+subroutine cgi_store_dict( dict, string )
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*), intent(in) :: string
+
+ character(len=DICT_KEY_LENGTH) :: key
+ character(len=len(string)) :: buffer
+ type(DICT_DATA) :: data
+
+ integer :: k
+ integer :: keq
+
+ buffer = string
+
+ do
+ k = index( buffer, '&' )
+ if ( k .le. 0 ) then
+ if ( buffer == ' ' ) then
+ exit
+ else
+ k = len(buffer) + 1 ! Remaining piece
+ endif
+ endif
+
+ call cgi_decode_string( buffer(1:k-1) )
+
+ !
+ ! Store the string
+ !
+ keq = index( buffer(1:k-1), '=' )
+ if ( keq > 0 ) then
+ key = buffer(1:keq-1)
+ data%value = buffer(keq+1:k-1)
+
+ if ( .not. associated( dict ) ) then
+ call dict_create( dict, key, data )
+ else
+ call dict_add_key( dict, key, data )
+ endif
+ endif
+
+ if ( k < len(buffer) ) then
+ buffer = buffer(k+1:)
+ else
+ buffer = ' '
+ endif
+
+ enddo
+end subroutine cgi_store_dict
+
+! cgi_decode_string --
+! Decode the string (replace + and %xx)
+!
+! Arguments:
+! dict Dictionary holding all information
+! string Complete string received from CGI server
+!
+subroutine cgi_decode_string( string )
+ character(len=*), intent(inout) :: string
+
+ integer :: k
+ integer :: ch
+
+ !
+ ! First the +'s
+ !
+ do
+ k = index( string, '+' )
+ if ( k .le. 0 ) exit
+
+ string(k:k) = ' '
+ enddo
+
+ !
+ ! Now %xx
+ !
+ do
+ k = index( string, '%' )
+ if ( k .le. 0 ) exit
+
+ read( string(k+1:k+2), '(z2)' ) ch
+ string(k:) = achar(ch) // string(k+3:)
+ enddo
+end subroutine cgi_decode_string
+
+! cgi_end --
+! Indicate to the server that we are done
+! Arguments:
+! None
+! Note:
+! This is simply done by writing a file cgiready,
+! if method 2 is used. Stop in all cases
+!
+subroutine cgi_end
+
+ integer :: lu
+ logical :: opend
+
+ if ( method == 2 ) then
+ do lu = 10,99
+ inquire( lu, opened=opend )
+ if ( .not. opend ) then
+ open( lu, file = "cgiready" )
+ close( lu )
+ exit
+ endif
+ enddo
+ endif
+
+ stop
+
+end subroutine cgi_end
+
+! cgi_error --
+! Report a fatal error
+! Arguments:
+! msg Message to be printed
+! template Template file to be used (optional)
+!
+subroutine cgi_error( msg, template )
+ character(len=*), intent(in) :: msg
+ character(len=*), intent(in), optional :: template
+
+ character(len=200) :: text
+ integer :: k
+ integer :: ierr
+ integer :: lu
+ logical :: opend
+ logical :: exists
+
+ exists = .false.
+ if ( present(template) ) then
+ inquire( file = template, exist = exists )
+ endif
+
+ if ( .not. header_written ) then
+ write( luout_cgi, '(a)' ) 'Content-Type: text/html;charset=iso8859-1'
+ write( luout_cgi, '(a)' ) ''
+ endif
+
+ if ( exists ) then
+ do lu = 10,99
+ inquire( lu, opened = opend )
+ if ( .not. opend ) then
+ exit
+ endif
+ enddo
+ open( lu, file = template )
+
+ do
+ read( lu, '(a)', iostat=ierr ) text
+ if ( ierr /= 0 ) exit
+
+ k = index( text, 'MSG' )
+ if ( k > 0 ) then
+ write( luout_cgi, '(3a)' ) text(1:k-1), trim(msg), text(k+3:)
+ else
+ write( luout_cgi, '(a)' ) text
+ endif
+ enddo
+ close( lu )
+ else
+ write( luout_cgi, * ) '<html>'
+ write( luout_cgi, * ) '<head><title>Severe error</title></head>'
+ write( luout_cgi, * ) '<body>'
+ write( luout_cgi, * ) '<b>', trim(msg), '</b>'
+ write( luout_cgi, * ) '</body></html>'
+ endif
+
+ call cgi_end
+
+end subroutine cgi_error
+
+! cgi_get_session --
+! Get the value of the "sessionid" variable
+! Arguments:
+! dict Dictionary with values
+! value Value of the session ID (character(len=20))
+! Note:
+! The session ID can be used to uniquely identify the
+! connection with the user. But it should be passed into the
+! HTML output as a hidden variable (see the documentation
+! for more information)
+!
+subroutine cgi_get_session( dict, value )
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*) :: value
+
+ character(len=20) :: time_string
+ type(DICT_DATA) :: data
+
+ if ( dict_has_key( dict, "sessionid" ) ) then
+ data = dict_get_key( dict, "sessionid" )
+ value = data%value
+ else
+ call date_and_time( time = time_string )
+ value = time_string(5:6) // time_string(8:10)
+ data%value = value
+ call dict_add_key( dict, "sessionid", data )
+ endif
+
+end subroutine cgi_get_session
+
+! cgi_get_* --
+! Get the value of variables
+! Arguments:
+! dict Dictionary with values
+! varname Name of the variable to retrieve
+! value Value of the variable
+! Note:
+! If the variable does not exist, then the value
+! is not changed! (Use dict_has_key() to check the
+! existence)
+!
+subroutine cgi_get_string( dict, varname, value )
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*) :: varname
+ character(len=*) :: value
+
+ type(DICT_DATA) :: data
+
+ if ( dict_has_key( dict, varname ) ) then
+ data = dict_get_key( dict, varname )
+ value = data%value
+ endif
+
+end subroutine cgi_get_string
+
+subroutine cgi_get_integer( dict, varname, value )
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*) :: varname
+ integer :: value
+
+ type(DICT_DATA) :: data
+ integer :: ierr
+ integer :: new_value
+
+ if ( dict_has_key( dict, varname ) ) then
+ data = dict_get_key( dict, varname )
+ read( data%value, *, iostat=ierr ) new_value
+ if ( ierr == 0 ) then
+ value = new_value
+ endif
+ endif
+
+end subroutine cgi_get_integer
+
+subroutine cgi_get_real( dict, varname, value )
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*) :: varname
+ real :: value
+
+ type(DICT_DATA) :: data
+ integer :: ierr
+ real :: new_value
+
+ if ( dict_has_key( dict, varname ) ) then
+ data = dict_get_key( dict, varname )
+ read( data%value, *, iostat=ierr ) new_value
+ if ( ierr == 0 ) then
+ value = new_value
+ endif
+ endif
+
+end subroutine cgi_get_real
+
+subroutine cgi_get_logical( dict, varname, value )
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*) :: varname
+ logical :: value
+
+ type(DICT_DATA) :: data
+ integer :: ierr
+ integer :: new_value
+
+ if ( dict_has_key( dict, varname ) ) then
+ data = dict_get_key( dict, varname )
+ read( data%value, *, iostat=ierr ) new_value
+ if ( ierr == 0 ) then
+ value = (new_value == 1)
+ endif
+ endif
+
+end subroutine cgi_get_logical
+
+end module cgi_protocol