-
Notifications
You must be signed in to change notification settings - Fork 0
/
fortran_fcgi.F90
267 lines (214 loc) · 10.1 KB
/
fortran_fcgi.F90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
!
! Demonstration Fortran FastCGI program, to run with the nginx webserver
! By [email protected] and [email protected]
!
! Requires:
! - the FLIBS modules cgi_protocol and fcgi_protocol
! - the FastCGI library
! See 'readme' for setup instructions of the compiler, nignx, and FastCGI library
!
! See 'makefile' for compile and execute commands. In summary,
! To compile test_fcgi.f90 : make
! To execute as FastCGI process : spawn-fcgi -a 127.0.0.1 -p 9000 ./test_fcgi
! The "-a 127.0.0.1" and "-p 9000" options to spawn-fcgi must match the
! "fastcgi_pass 127.0.0.1:9000;" in nginx.conf
!
! Notes:
! 1. Example 2 is from FLIBS test_cgi.f90
! 2. Customize routine respond() for your own application
!
program test_fcgi
use fcgi_protocol
implicit none
type(DICT_STRUCT), pointer :: dict => null() ! Initialisation is important!
logical :: stopped = .false. ! set to true in respond() to terminate program
integer :: unitNo ! unit number for a scratch file
! open scratch file
open(newunit=unitNo, status='scratch')
! comment previous line AND uncomment next line for debugging;
!open(newunit=unitNo, file='fcgiout', status='unknown') ! file 'fcgiout' will show %REMARKS%
! wait for environment variables from webserver
do while (fcgip_accept_environment_variables() >= 0)
! build dictionary from GET or POST data, environment variables
call fcgip_make_dictionary( dict, unitNo )
! give dictionary to the user supplied routine
! routine writes the response to unitNo
! routine sets stopped to true to terminate program
call respond(dict, unitNo, stopped)
! copy file unitNo to the webserver
call fcgip_put_file( unitNo, 'text/html' )
! terminate?
if (stopped) exit
end do ! while (fcgip_accept_environment_variables() >= 0)
! before termination, it is good practice to close files that are open
close(unitNo)
! webserver will return an error since this process will now terminate
unitNo = fcgip_accept_environment_variables()
contains
subroutine respond ( dict, unitNo, stopped )
type(DICT_STRUCT), pointer :: dict
integer, intent(in) :: unitNo
logical, intent(out) :: stopped
! the following are defined in fcgi_protocol
!character(len=3), parameter :: AFORMAT = '(a)'
!character(len=2), parameter :: CRLF = achar(13)//achar(10)
!character(len=1), parameter :: NUL = achar(0)
! the script name
character(len=80) :: scriptName
! variables for Example 1
character(len=80) :: actionButton, username, password
! variables for Example 2 (from test_cgi.f90 of FLIBS)
integer :: steps
real :: xmin
real :: xmax
character(len=20) :: fnName
character(len=20) :: output
real, dimension(:), allocatable :: x
real, dimension(:), allocatable :: y
integer :: i
logical :: okInputs
! start of response
! lines starting with %REMARK% are for debugging & will not be copied to webserver
write(unitNo, AFORMAT) &
'%REMARK% respond() started ...', &
'<html>', &
'<head><title>Fortran FastCGI</title></head>', &
'<body>', &
'<h1>Fortran FastCGI</h1>'
! retrieve script name (key=DOCUMENT_URI) from dictionary
call cgi_get( dict, "DOCUMENT_URI", scriptName )
if ( trim(scriptName) /= '/' ) & ! a script was requested
write(unitNo,AFORMAT) 'Script is : '//trim(scriptName)
select case (trim(scriptName))
case ('/login') ! See form in Example 1 below
! keys are: action, username, password
call cgi_get( dict, "action", actionButton)
write(unitNo,AFORMAT) '<br>Action is : '//trim(actionButton)
call cgi_get( dict, "username", username)
write(unitNo,AFORMAT) '<br>Username is : '//trim(username)
call cgi_get( dict, "password", password)
write(unitNo,AFORMAT) '<br>Password is : '//trim(password)
case ('/calculate') ! See form in Example 2 below
! keys are: function, minimum, maximum, steps, output
fnName = '?'
xmin = 0.0
xmax = 1.0
steps = 10
call cgi_get( dict, "function", fnName )
call cgi_get( dict, "minimum", xmin )
call cgi_get( dict, "maximum", xmax )
call cgi_get( dict, "steps", steps )
call cgi_get( dict, "output", output )
write(unitNo, AFORMAT) '%REMARK% function='//trim(fnName )
write(unitNo, '(a,f8.3)') '%REMARK% minimum=', xmin
write(unitNo, '(a,f8.3)') '%REMARK% maximum=', xmax
write(unitNo, '(a,i4)') '%REMARK% steps=', steps
write(unitNo, AFORMAT) '%REMARK% output='//trim(output)
okInputs = .true.
if ( trim(fnName ) == '?' ) then
write(unitNo,AFORMAT) '<br>No function selected'
okInputs = .false.
endif
if ( abs(xmin) > 100.0 .or. abs(xmax) > 100.0 ) then
write(unitNo,AFORMAT) '<br>Minimum and maximum should be in the range -100 to 100'
okInputs = .false.
endif
if ( trim(fnName ) == 'J0' ) then
write(unitNo,AFORMAT) '<br>Sorry, the Bessel function is not yet implemented'
okInputs = .false.
endif
if (okInputs) then
!
! Actual processing
!
allocate( x(0:steps), y(0:steps) )
x = (/ (xmin + i*(xmax-xmin)/steps, i=0,steps) /)
if ( trim(fnName ) == 'sin' ) then
y = sin(x)
endif
if ( trim(fnName ) == 'cos' ) then
y = cos(x)
endif
!
! Write the HTML output or the CSV file
!
if ( trim(output) == 'html' ) then
write( unitNo,AFORMAT ) &
'<table>', &
'<tr><td>X</td><td>'//trim(fnName)//'(X)</td></tr>'
do i = 0,steps
write( unitNo, '(a,f12.6,a,f12.6,a)' ) &
'<tr><td>', x(i), '</td><td>', y(i), '</td></tr>'
enddo
write( unitNo,AFORMAT ) &
'</table>'
else
write( unitNo,AFORMAT ) &
'<pre>', ' X , '//trim(fnName)//'(X)'
do i = 0,steps
write( unitNo, '(f12.6,a,f12.6)' ) x(i), ',', y(i)
enddo
write( unitNo,AFORMAT ) &
'</pre>'
endif
end if
case ('/shutdown') ! to terminate program
write(unitNo,AFORMAT) '<br>Program has terminated.<br><a href="/">Verify</a>'
stopped = .true.
end select
! generate page for next action
if (.not. stopped) then
write(unitNo,AFORMAT) &
"<hr>", &
"<b>Example 1: POST method</b>", &
"<table>", &
"<form action='login' method='post'>", &
"<tr><td>Username:</td><td>Password:</td><td> Action:</td></tr>", &
"<tr><td><input type='text' name='username' value=''></td>", &
" <td><input type='password' name='password' value=''></td>", &
" <td> <input type='submit' name='action' value='Login'>", &
" or <input type='submit' name='action' value='Register'></td></tr>", &
"</form>", &
"</table>"
write(unitNo,AFORMAT) &
"<hr>", &
"<b>Example 2: GET method</b>", &
"<form action='calculate' method='get'>", &
"<p>", &
"Function: f(x) =", &
"<select name='function'>", &
" <option value='sin' selected>sin(x)</option>", &
" <option value='cos'>cos(x)</option>", &
" <option value='J0'>J0(x)</option>", &
"</select>", &
"<br>", &
"Domain:", &
"<table>", &
"<tr>", &
"<td>Minimum = </td><td><input type='text' name='minimum' value='0.0'></td>", &
"</tr>", &
"<tr>", &
"<td>Maximum = </td><td><input type='text' name='maximum' value='1.0'></td>", &
"</tr>", &
"<tr>", &
"<td>Steps = </td><td><input type='text' name='steps' value='10'></td>", &
"</tr>", &
"</table>", &
"<p>", &
"Type of output:", &
"<input type='radio' name='output' value='html', checked>HTML</input>", &
"<input type='radio' name='output' value='csv'>CSV</input>", &
"<p>", &
"<input type='submit' value='Calculate'>", &
"</form>"
write(unitNo,AFORMAT) &
"<hr>", &
"<b>Example 3: Hyperlink</b><br>", &
" <a href='shutdown'><b>Stop</b></a> the Fortran FastCGI program."
end if
! end of response
write(unitNo,AFORMAT) '</body>', '</html>', &
'%REMARK% respond() completed ...'
return
end subroutine respond
end program test_fcgi