PageRenderTime 235ms CodeModel.GetById 79ms app.highlight 6ms RepoModel.GetById 59ms app.codeStats 86ms

/library/server/httpd/tests/application.e

http://github.com/jocelyn/EiffelWebReloaded
Specman e | 594 lines | 503 code | 61 blank | 30 comment | 28 complexity | 887dbe15b3c7a98663b107477e1cc4f9 MD5 | raw file
  1note
  2	description : "Objects that ..."
  3	author      : "$Author$"
  4	date        : "$Date$"
  5	revision    : "$Revision$"
  6
  7class
  8	APPLICATION
  9
 10inherit
 11	HTTPD_FCGI_APPLICATION
 12		redefine
 13			pre_execute,
 14			post_execute,
 15			rescue_execute,
 16			new_request_context
 17		end
 18
 19	SHARED_LOGGER
 20
 21	HTTP_FILE_SYSTEM_UTILITIES
 22
 23create
 24	make
 25
 26feature {NONE} -- Initialization
 27
 28	make
 29			-- Initialize `Current'.
 30		do
 31			logger_cell.replace (create {FILE_LOGGER}.make_with_filename ("sample.log"))
 32			initialize
 33			launch
 34			logger.close
 35		end
 36
 37feature -- Access
 38
 39	new_request_context (a_vars: HASH_TABLE [STRING, STRING]; a_input: HTTPD_SERVER_INPUT; a_output: HTTPD_SERVER_OUTPUT): APPLICATION_REQUEST_CONTEXT
 40		do
 41			create Result.make (a_vars, a_input, a_output)
 42		end
 43
 44feature -- Execution
 45
 46	http_header: detachable HTTPD_HEADER
 47
 48	html: detachable HTML_PAGE
 49
 50	html_menu (ctx: like new_request_context): STRING
 51		do
 52			Result := "<div> "
 53					+ "<a href=%"" + ctx.script_url ("/home") + "%">Home</a> "
 54					+ "<a href=%"" + ctx.script_url ("/help") + "%">Help</a> "
 55					+ "<a href=%"" + ctx.script_url ("/test")  + "%">Test</a> "
 56			if ctx.authenticated and then attached ctx.authenticated_identifier as l_id then
 57				Result.append ("<a href=%"" + ctx.script_url ("/private") + "%">"+ l_id + "</a> ")
 58
 59				Result.append ("<a href=%"" + ctx.script_url ("/logout") + "%">Logout</a> ")
 60			else
 61				Result.append ("<a href=%"" + ctx.script_url ("/login") + "%">Login</a> ")
 62			end
 63			Result.append (
 64					  "<a href=%"" + ctx.script_url ("/quit") + "%">Exit</a> "
 65					+ "</div>"
 66				)
 67		end
 68
 69	execute (ctx: like new_request_context)
 70		local
 71			rqst_uri: detachable STRING
 72			l_path_info: detachable STRING
 73		do
 74			logger.log (1, "execute: " + request_count.out)
 75--			if attached ctx.all_variables as vars then
 76--				from
 77--					vars.start
 78--				until
 79--					vars.after
 80--				loop
 81--					logger.log (1, "%T" + vars.key_for_iteration.as_string_8 + "=" + vars.item_for_iteration.as_string_8)
 82--					vars.forth
 83--				end
 84--			end
 85			l_path_info := ctx.path_info
 86			if l_path_info.is_empty then
 87				l_path_info := "/home" --| Default application
 88			end
 89			if l_path_info.starts_with ("/help") then
 90				execute_help_application (ctx)
 91			elseif l_path_info.starts_with ("/home") then
 92				execute_home_application (ctx)
 93			elseif l_path_info.starts_with ("/login") then
 94				execute_login_application (ctx)
 95			elseif l_path_info.starts_with ("/logout") then
 96				execute_logout_application (ctx)
 97			elseif l_path_info.starts_with ("/private") then
 98				execute_private_application (ctx)
 99			elseif l_path_info.starts_with ("/test") then
100				execute_test_application (ctx)
101			elseif l_path_info.starts_with ("/file") or l_path_info.starts_with ("/download") then
102				execute_file_application (ctx)
103			elseif l_path_info.starts_with ("/api/") then
104				execute_api_application (ctx)
105			elseif l_path_info.starts_with ("/quit") then
106				execute_exit_application (ctx)
107			else
108				execute_test_application (ctx)
109			end
110		end
111
112	execute_home_application (ctx: like new_request_context)
113		local
114			h: APPLICATION_HTML_PAGE
115			s: STRING
116		do
117			create h.make ("FCGI Eiffel Application - Home")
118			h.headers.put_refresh (ctx.script_url ("/home"), 1, 200)
119			h.headers.put_content_type_text_html
120			h.body_menu := html_menu (ctx)
121			create s.make_empty
122			s.append_string ("<h1> Welcome to the Eiffel Web Application (request count="+request_count.out+")</h1>%N")
123			s.append_string ("PATH_INFO=" + ctx.path_info + "<br/>%N")
124			h.body_main := s
125			h.compute
126			http_put_string (h.string, ctx)
127			h.recycle
128		end
129
130	execute_login_application (ctx: like new_request_context)
131		local
132			hd: HTTPD_HEADER
133			h: APPLICATION_HTML_PAGE
134			s: STRING
135		do
136			if ctx.authenticated and then attached ctx.authenticated_identifier as l_id then
137				create h.make ("Login ...")
138				h.headers.put_content_type_text_html
139				h.headers.put_redirection (ctx.script_url ("/home"), 0)
140				h.headers.put_cookie ("uuid", "uuid_" + l_id, Void, Void, Void, Void)
141				h.headers.put_cookie ("auth", "yes", Void, Void, Void, Void)
142				h.headers.put_cookie ("user", l_id, Void, Void, Void, Void)
143				h.body_menu := html_menu (ctx)
144				h.body_main.append ("Hello " + l_id + "%N")
145				h.body_main.append ("Cookies:%N" + string_hash_table_string_string (ctx.cookies_variables.new_cursor))
146				http_put_string (h.string, ctx)
147				h.recycle
148			else
149				create hd.make
150				hd.put_status (401)
151				hd.put_header ("WWW-Authenticate: Basic realm=%"Eiffel Auth%"")
152				http_put_string (hd.string, ctx)
153				hd.recycle
154			end
155		end
156
157	execute_logout_application (ctx: like new_request_context)
158		local
159			hd: HTTPD_HEADER
160			h: APPLICATION_HTML_PAGE
161		do
162			if ctx.authenticated and then attached ctx.authenticated_identifier as l_id then
163				create h.make ("Logout ...")
164				h.headers.put_content_type_text_html
165				h.headers.put_cookie ("uuid", "", Void, Void, Void, Void)
166				h.headers.put_cookie ("auth", "lno", Void, Void, Void, Void)
167				h.headers.put_cookie ("user", "", Void, Void, Void, Void)
168				h.body_menu := html_menu (ctx)
169				h.body_main.append ("Bye " + l_id + "%N")
170				h.body_main.append ("Cookies:%N" + string_hash_table_string_string (ctx.cookies_variables.new_cursor))
171				http_put_string (h.string, ctx)
172				h.recycle
173			else
174				create hd.make
175				hd.put_status (401)
176				hd.put_header ("WWW-Authenticate: Basic realm=%"Eiffel Auth%"")
177				hd.put_cookie ("uuid", "", Void, Void, Void, Void)
178				hd.put_cookie ("auth", "logout", Void, Void, Void, Void)
179				hd.put_cookie ("user", "", Void, Void, Void, Void)
180				http_put_string (hd.string, ctx)
181				hd.recycle
182			end
183		end
184
185	execute_api_application (ctx: like new_request_context)
186		local
187			l_path_info: STRING
188			l_query: STRING
189			h: HTTPD_HEADER
190			r: HTML_PAGE
191			s: STRING
192--			j: JSON_
193		do
194--			execute_home_application (ctx)
195			l_path_info := ctx.path_info
196			check l_path_info.starts_with ("/api/") end
197			l_query := l_path_info.substring (("/api").count + 1, l_path_info.count)
198			if l_query.starts_with ("/test.plain") then
199				s := "This is a test for api %"" + l_query + "%".%NBye bye.%N"
200
201				create h.make
202				h.put_content_type_text_plain
203				h.put_content_length (s.count)
204				output.put_string (h.string)
205				output.put_string (s)
206				output.flush
207			elseif l_query.starts_with ("/test.xml") then
208				s := "<doc><text>This is a test for api %"" + l_query + "%".%NBye bye.%N</text></doc>"
209
210				create h.make
211				h.put_content_type_text_xml
212				h.put_content_length (s.count)
213				output.put_string (h.string)
214				output.put_string (s)
215				output.flush
216			elseif l_query.starts_with ("/test.json") then
217				s := "{ %"title%": %"Eiffel Web Sample%", %"text%": %"This is a test for api [" + l_query + "].%NBye bye.%N%" }"
218
219				create h.make
220				h.put_content_type_application_json
221				h.put_content_length (s.count)
222				output.put_string (h.string)
223				output.put_string (s)
224				output.flush
225
226			else
227				create r.make (l_query)
228				r.send (output)
229			end
230		end
231
232	execute_private_application (ctx: like new_request_context)
233		local
234			hd: HTTPD_HEADER
235			h: APPLICATION_HTML_PAGE
236			s: STRING
237		do
238			if not ctx.authenticated then
239				create hd.make
240				hd.put_status (401)
241				hd.put_header ("WWW-Authenticate: Basic realm=%"Eiffel Auth%"")
242				hd.put_redirection (ctx.script_url ("/login"), 0)
243				http_put_string (hd.string, ctx)
244				hd.recycle
245			else
246				create h.make ("FCGI Eiffel Application - Private")
247				h.headers.put_content_type_text_html
248				h.body_menu := html_menu (ctx)
249				s := "<h1> Welcome to the private side of Eiffel Web Application (request count="+request_count.out+")</h1>"
250				s.append_string ("PATH_INFO=" + ctx.path_info + "<br/>")
251				if attached ctx.http_authorization as l_auth then
252					s.append_string ("Auth=" + l_auth + "<br/>")
253				else
254					s.append_string ("Auth= ...<br/>")
255				end
256				s.append ("All var:%N" + string_hash_table_string_string (ctx.variables.new_cursor))
257				s.append ("Cookies:%N" + string_hash_table_string_string (ctx.cookies_variables.new_cursor))
258				h.body_main.append (s)
259				http_put_string (h.string, ctx)
260				h.recycle
261			end
262		end
263
264	execute_file_application (ctx: like new_request_context)
265		local
266			l_path_info: STRING
267			p: INTEGER
268			l_file: STRING
269			r: HTTPD_FILE_RESPONSE
270		do
271			l_path_info := ctx.path_info
272			p := l_path_info.substring_index ("download/", 1)
273			if p > 0 then
274				l_file := l_path_info.substring (p + 9, l_path_info.count)
275				create {HTTPD_DOWNLOAD_RESPONSE} r.make (l_file)
276				r.send (output)
277			else
278				p := l_path_info.substring_index ("file/", 1)
279				if p > 0 then
280					l_file := l_path_info.substring (p + 5, l_path_info.count)
281					create {HTTPD_FILE_RESPONSE} r.make (l_file)
282					r.send (output)
283				else
284					http_put_string (header ("FCGI Eiffel Application - File"), ctx)
285					http_put_string (footer, ctx)
286				end
287			end
288		end
289
290	execute_exit_application (ctx: like new_request_context)
291		do
292			http_put_string (header ("FCGI Eiffel Application - Bye bye"), ctx)
293			http_put_string (html_menu (ctx), ctx)
294			http_put_string ("<h1>Eiffel Web Application - bye bye (request count="+request_count.out+")</h1>", ctx)
295			http_put_string (footer, ctx)
296			http_flush (ctx);
297			(create {EXCEPTIONS}).die (0)
298		end
299
300	execute_help_application (ctx: like new_request_context)
301		do
302			http_put_string (header ("FCGI Eiffel Application - Help"), ctx)
303			http_put_string (html_menu (ctx), ctx)
304			http_put_string ("<h1>Help ...</h1>", ctx)
305			http_put_string (footer, ctx)
306		end
307
308	execute_test_application (ctx: like new_request_context)
309		local
310			rqst_uri: detachable STRING
311			n: INTEGER
312		do
313			http_put_string (header ("FCGI Eiffel Application"), ctx)
314			http_put_string (html_menu (ctx), ctx)
315			if ctx.has_error then
316				http_put_string ("<div>ERROR occurred%N", ctx)
317				print_errors (ctx.error_handler, ctx)
318				http_put_string ("</div>", ctx)
319			end
320			rqst_uri := ctx.request_uri
321			if rqst_uri /= Void then
322				if attached ctx.request_method as l_rqst_method then
323					if l_rqst_method.is_case_insensitive_equal ("GET") then
324						http_put_string ("<div>Method: GET", ctx)
325						http_put_string ("<form id=%"sample_form_1%" name=%"sample_form_1%" action=%"" + rqst_uri + "%" method=%"POST%">%N", ctx)
326						http_put_string ("<input type=%"text%" name=%"fd_text%" value=%"TEXT%">%N", ctx)
327						http_put_string ("<input type=%"text%" name=%"fd_text2%" value=%"TEXT2%">%N", ctx)
328						http_put_string ("<input type=%"text%" name=%"fd_text3%" value=%"TEXT3%">%N", ctx)
329						http_put_string ("<input type=%"text%" name=%"fd_text4%" value=%"TEXT4%">%N", ctx)
330						http_put_string ("<input type=%"text%" name=%"a.b1%" value=%"A.B1%">%N", ctx)
331						http_put_string ("<input type=%"text%" name=%"a.b2%" value=%"A.B2%">%N", ctx)
332						http_put_string ("<input type=%"text%" name=%"a.b3%" value=%"A.B3%">%N", ctx)
333						http_put_string ("<input type=%"text%" name=%"z[a]%" value=%"Z[A]%">%N", ctx)
334						http_put_string ("<input type=%"text%" name=%"z[b]%" value=%"Z[B]%">%N", ctx)
335						http_put_string ("<input type=%"text%" name=%"z[c]%" value=%"Z[C]%">%N", ctx)
336
337						http_put_string ("<input type=%"reset%" name=%"fd_cancel%" value=%"Cancel%">%N", ctx)
338						http_put_string ("<input type=%"submit%" name=%"fd_submit%" value=%"Validate%">%N", ctx)
339						http_put_string ("</form>%N", ctx)
340						http_put_string ("</div>%N", ctx)
341					elseif l_rqst_method.is_case_insensitive_equal ("POST") then
342						http_put_string ("<div>Method: POST", ctx)
343						http_put_string ("<li>type=" + variable ("CONTENT_TYPE", ctx.content_type) + "</li>%N", ctx)
344						http_put_string ("<li>length=" + ctx.content_length.out + "</li>%N", ctx)
345						if
346							ctx.content_length > 0
347						then
348							print_hash_table_string_string (ctx.variables_post.new_cursor, ctx)
349--							http_put_string ("content=[", ctx)
350--							fcgi.read_from_stdin (ctx.content_length)
351--							http_put_string (fcgi.buffer_contents, ctx)
352--							http_put_string ("]", ctx)
353						end
354						http_put_string ("</div>%N", ctx)
355					elseif l_rqst_method.is_case_insensitive_equal ("PUT") then
356						http_put_string ("<h1>Method: " + l_rqst_method + "</h1>%N", ctx)
357					elseif l_rqst_method.is_case_insensitive_equal ("DELETE") then
358						http_put_string ("<h1>Method: " + l_rqst_method + "</h1>%N", ctx)
359					end
360
361					http_put_string ("<div>%N", ctx)
362					http_put_string ("<form id=%"sample_form_2%" name=%"sample_form_2%" action=%"" + rqst_uri + "%" method=%"POST%">%N", ctx)
363					http_put_string ("<input type=%"text%" name=%"fd_text%">%N", ctx)
364					http_put_string ("<input type=%"reset%" name=%"fd_cancel%" value=%"Cancel%">%N", ctx)
365					http_put_string ("<input type=%"submit%" name=%"fd_submit%" value=%"GO%">%N", ctx)
366					http_put_string ("</form>%N", ctx)
367
368					http_put_string ("</div>%N", ctx)
369
370					http_put_string ("<div><form action=%"" + rqst_uri + "%" enctype=%"multipart/form-data%" method=%"POST%">%N", ctx)
371					http_put_string("[
372										<p>
373											Type some text (if you like):<br>
374											<input type="text" name="textline" size="30" value="FooBar">FOOBAR</input>
375										</p>
376										<p>
377										Please specify a file, or a set of files:<br>
378										<input type="file" name="datafile" size="40">
379										</p>
380										<div><input type="submit" value="Send"></div></form>
381							]", ctx)
382				end
383			end
384
385			http_put_string ("<h1>Hello FCGI Eiffel Application</h1>%N", ctx)
386			http_put_string ("Request number " + request_count.out + "<br/>%N", ctx)
387
388			http_put_string ("<ul>GET variables%N", ctx)
389			print_hash_table_string_string (ctx.variables_get.new_cursor, ctx)
390			http_put_string ("</ul>", ctx)
391
392			http_put_string ("<ul>POST variables%N", ctx)
393			print_hash_table_string_string (ctx.variables_post.new_cursor, ctx)
394			http_put_string ("</ul>", ctx)
395
396			if attached ctx.uploaded_files as l_files and then not l_files.is_empty then
397				http_put_string ("<ul>FILES variables%N", ctx)
398				from
399					l_files.start
400				until
401					l_files.after
402				loop
403					http_put_string ("<li><strong>" + l_files.key_for_iteration + "</strong>", ctx)
404					http_put_string (" filename=" + l_files.item_for_iteration.name, ctx)
405					http_put_string (" type=" + l_files.item_for_iteration.type, ctx)
406					http_put_string (" size=" + l_files.item_for_iteration.size.out, ctx)
407					http_put_string (" tmp_basename=" + l_files.item_for_iteration.tmp_basename, ctx)
408					http_put_string (" tmp_name=" + l_files.item_for_iteration.tmp_name, ctx)
409					if attached ctx.path_info as l_path_info then
410						http_put_string ("<img src=%"", ctx)
411						from
412							n := l_path_info.occurrences ('/')
413						until
414							n = 0
415						loop
416						 	http_put_string ("../", ctx)
417						 	n := n - 1
418						end
419						http_put_string (l_files.item_for_iteration.tmp_basename + "%" />", ctx)
420					else
421						http_put_string ("<img src=%"" + l_files.item_for_iteration.tmp_basename + "%" />", ctx)
422					end
423					http_put_string ("<a href=%"" + ctx.script_url ("/download/" + l_files.item_for_iteration.tmp_basename) + "%">", ctx)
424					http_put_string ("<img src=%"" + ctx.script_url ("/file/" + l_files.item_for_iteration.tmp_basename) + "%" />", ctx)
425					http_put_string ("</a>", ctx)
426
427					http_put_string ("</li>%N", ctx)
428					l_files.forth
429				end
430				http_put_string ("</ul>", ctx)
431			end
432
433			http_put_string ("<ul>COOKIE variables%N", ctx)
434			print_hash_table_string_string (ctx.cookies_variables.new_cursor, ctx)
435			http_put_string ("</ul>", ctx)
436
437			http_put_string ("<ul>Environment variables%N", ctx)
438			print_environment_variables (ctx.environment_variables, ctx)
439			http_put_string ("</ul>", ctx)
440			http_put_string (footer, ctx)
441			http_flush (ctx)
442
443			post_execute_ignored := True
444		end
445
446	pre_execute
447		do
448			post_execute_ignored := False
449		end
450
451	post_execute (ctx: detachable like new_request_context)
452		do
453			if not post_execute_ignored then
454				Precursor (ctx)
455			end
456		end
457
458	rescue_execute (ctx: detachable like new_request_context; e: detachable EXCEPTION)
459		do
460			if e /= Void and ctx /= Void then
461				http_put_string ("Exception occurred%N", ctx)
462				http_put_string ("<p>" + e.meaning + "</p", ctx)
463				if attached e.exception_trace as l_trace then
464					http_put_string ("<pre>" + l_trace + "</pre>", ctx)
465				end
466				http_flush (ctx)
467			end
468			post_execute (ctx)
469		end
470
471	post_execute_ignored: BOOLEAN
472
473feature -- Access
474
475	variable (k: STRING; v: detachable STRING): STRING
476		do
477			if v /= Void then
478				Result := v
479			else
480				Result := "$" + k
481			end
482		end
483
484--	variable (vars: HASH_TABLE [STRING, STRING]; n: STRING): STRING
485--		do
486--			if attached vars.item (n) as v then
487--				Result := v
488--			else
489--				Result := "$" + n
490--			end
491--		end
492
493	cookie (key, value: STRING; expiration, path, domain, secure: detachable STRING): STRING
494			-- Set a cookie on the client's machine
495			-- with key 'key' and value 'value'.
496		require
497--			not_yet_sent: not is_sent
498			make_sense: (key /= Void and value /= Void) and then
499						(not key.is_empty and not value.is_empty)
500--			header_is_complete: is_complete_header
501		do
502			Result := "Set-Cookie:" + key + "=" + value
503			if expiration /= Void then
504				Result.append (";expires=" + expiration)
505			end
506			if path /= Void then
507				Result.append (";path=" + path)
508			end
509			if domain /= Void then
510				Result.append (";domain=" + domain)
511			end
512			if secure /= Void then
513				Result.append (";secure=" + secure)
514			end
515		end
516
517	header_auth: STRING
518		do
519			Result := ""
520			Result.append ("Status: 401 Unauthorized%R%N")
521			Result.append ("WWW-Authenticate: Basic realm=%"Eiffel Auth%"%R%N%R%N")
522		end
523
524	header (a_title: STRING): STRING
525		do
526			Result := ""
527			Result.append ("Content-type: text/html%R%N")
528--			Result.append (cookie ("foo", "bar#" + request_count.out, Void, Void, Void, Void))
529			Result.append ("%R%N")
530			Result.append ("%R%N")
531			Result.append ("<html>%N")
532			Result.append ("<head><title>" + a_title + "</title></head>")
533			Result.append ("<body>%N")
534		end
535
536	footer: STRING
537		do
538			Result := "</body>%N</html>%N"
539		end
540
541	print_environment_variables (vars: HASH_TABLE [STRING, STRING]; ctx: like new_request_context)
542		do
543			print_hash_table_string_string (vars.new_cursor, ctx)
544		end
545
546	print_hash_table_string_string (ht: HASH_TABLE_ITERATION_CURSOR [STRING_GENERAL, STRING_GENERAL]; ctx: like new_request_context)
547		do
548			from
549				ht.start
550			until
551				ht.after
552			loop
553				http_put_string ("<li><strong>" + ht.key.as_string_8 + "</strong> = " + ht.item.as_string_8 + "</li>%N", ctx)
554				ht.forth
555			end
556		end
557
558	string_hash_table_string_string (ht: HASH_TABLE_ITERATION_CURSOR [STRING_GENERAL, STRING_GENERAL]): STRING_8
559		do
560			from
561				create Result.make (100)
562				ht.start
563			until
564				ht.after
565			loop
566				Result.append_string ("<li><strong>" + ht.key.as_string_8 + "</strong> = " + ht.item.as_string_8 + "</li>%N")
567				ht.forth
568			end
569		end
570
571	print_errors (hdl: ERROR_HANDLER; ctx: like new_request_context)
572		local
573			v: APPLICATION_ERROR_HTML_PRINTER
574			s: STRING
575		do
576			if attached hdl.as_single_error as e then
577				create s.make (50)
578				create v.make (s)
579				e.process (v)
580				http_put_string (s, ctx)
581			end
582		end
583
584feature -- Constants
585
586	request_method_varname: STRING = "REQUEST_METHOD"
587
588	request_uri_varname: STRING = "REQUEST_URI"
589
590	request_content_type_varname: STRING = "CONTENT_TYPE"
591
592	request_content_length_varname: STRING = "CONTENT_LENGTH"
593
594end