indexing
description: "[
Filler which can fill a bug report on http://support.eiffel.com
]"
status: "See notice at end of class."
legal: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
BUG_REPORT_FILLER
create
make
feature {NONE} -- Initialization
make is
-- Creation method
do
create login_failed_actions
create curl_failed_actions
end
feature -- Command
fill_report (a_data: BUG_REPORT_DATA) is
-- Fill a bug report with `a_data'.
require
not_void: a_data /= Void
ready: a_data.is_all_data_filled
local
l_html: STRING
l_excep: EXCEPTIONS
l_retry: BOOLEAN
l_stop_retry: BOOLEAN
do
if is_curl_library_exists then
if not l_retry then
init
data := a_data
l_html := login
if is_login_successed (l_html) then
fill_bug_report (html_of_submit_page)
else
login_failed_actions.call (Void)
end
clean_up
else
if not l_stop_retry then
l_stop_retry := True
clean_up
create l_excep
curl_failed_actions.call (["cURL error: " + last_result.out])
else
curl_failed_actions.call (["cURL error: unknown"])
end
end
else
curl_failed_actions.call (["cURL dynamic link library not exists."])
end
rescue
l_retry := True
retry
end
feature -- Query
is_curl_library_exists: BOOLEAN is
-- If cURL dll/so files exits?
do
Result := curl.is_dynamic_library_exists
end
data: BUG_REPORT_DATA
-- Data for bug report.
login_failed_actions: ACTION_SEQUENCE [TUPLE []]
-- Actions performed just after login failed.
curl_failed_actions: ACTION_SEQUENCE [TUPLE [a_tag: STRING]]
-- Actions performed just after curl_easy.perform failed.
last_result: INTEGER
-- Last cURL easy perform result.
feature {NONE} -- Implementation
login: STRING is
-- Login http://support.eiffel.com
-- Result is return HTML
require
not_void: data /= Void
ready: data.is_all_data_filled
local
l_whole_file: CURL_MEMORY_STRUCT
l_view_state_value, l_event_validation: STRING
l_post_string: STRING
do
create l_whole_file.make
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_url, "https://www2.eiffel.com/login/secure/logon.aspx")
curl_easy.setopt_memory_struct (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_writedata, l_whole_file)
easy_perform
l_view_state_value := find_view_state (l_whole_file.string.as_string_8)
l_event_validation := find_event_validation (l_whole_file.string.as_string_8)
url_encoding (l_view_state_value)
url_encoding (l_event_validation)
create l_whole_file.make
--curl_set_header_opt (curl_handle)
l_post_string := post_string_for_login (l_view_state_value, l_event_validation, data.username.as_string_8, data.password.as_string_8)
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_url, "https://www2.eiffel.com/login/secure/logon.aspx")
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_post, 1)
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfields, l_post_string)
curl_easy.setopt_memory_struct (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_writedata, l_whole_file)
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_cookie, "____Pagemain_div__ToggleState=1")
easy_perform
Result := l_whole_file.string.as_string_8
end
fill_bug_report (a_last_html: STRING_GENERAL) is
-- Filling a bug report after login.
require
not_void: a_last_html /= Void
login:
local
l_view_state, l_validation: STRING
l_final_url_location: STRING
l_last_html, l_result_string: STRING_GENERAL
do
-- Post for preview
l_last_html := post_for_preview (a_last_html)
-- Get HTML of confirm page, so we can get VIEWSTAE and EVENTVALIDATION value for next step.
l_last_html := html_of_confirm_page (l_last_html)
-- Final submit
l_final_url_location := find_location (a_last_html.as_string_8)
-- We need this page to find the latest VIEWSTATE and EVENTVALIDATION value.
l_result_string := html_of_final_submit_page ("https://www2.eiffel.com" + l_final_url_location)
l_view_state := find_view_state (l_result_string.as_string_8)
l_validation := find_event_validation (l_result_string.as_string_8)
url_encoding (l_view_state)
url_encoding (l_validation)
final_submit ("https://www2.eiffel.com" + l_final_url_location, post_string_for_final_submit (l_view_state, l_validation), "Referer: " + "https://www2.eiffel.com" + l_final_url_location)
end
post_for_preview (a_last_html: STRING_GENERAL): STRING_GENERAL is
-- Post bug report data, then we can go to the bug report preview page.
require
exists: curl_handle /= default_pointer
not_void: a_last_html /= Void
local
l_view_state, l_validation: STRING
l_event_target: STRING
l_form: CURL_FORM
l_memory: CURL_MEMORY_STRUCT
do
l_view_state := (find_view_state (a_last_html.as_string_8))
l_validation := (find_event_validation (a_last_html.as_string_8))
l_event_target := ("ctl00$ctl00$default_main_content$main_content$category_list")
l_form := form_for_bug_report (l_view_state, l_validation, l_event_target)
create l_memory.make
setopt_with_form (l_memory, l_form)
easy_perform
Result := l_memory.string
end
final_submit (a_target_url: STRING; a_post_url_string: STRING; a_refer_header: STRING) is
-- Final step of submitting a bug report.
require
exists: curl_handle /= default_pointer
not_void: a_target_url /= Void
not_void: a_post_url_string /= Void
not_void: a_refer_header /= Void
local
l_data: CURL_MEMORY_STRUCT
do
create l_data.make
curl_easy.setopt_memory_struct (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_writedata, l_data)
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_url, a_target_url)
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_post, 1)
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfields, a_post_url_string)
easy_perform
end
feature {NONE} -- Html contents
html_of_submit_page: STRING_GENERAL is
-- Web content of bug report page.
require
not_void: curl_handle /= default_pointer
local
l_data: CURL_MEMORY_STRUCT
do
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_url, "https://www2.eiffel.com/support/protected/problem_report_form.aspx")
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_post, 0)
create l_data.make
curl_easy.setopt_memory_struct (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_writedata, l_data)
easy_perform
Result := l_data.string
end
html_of_confirm_page (a_last_html: STRING_GENERAL): STRING_GENERAL is
-- HTML of bug report submit confirm page.
require
not_void: a_last_html /= Void
not_void: curl_handle /= default_pointer
local
l_view_state, l_validation: STRING
l_event_target: STRING
l_result_string: STRING
l_form: CURL_FORM
l_result_html: CURL_MEMORY_STRUCT
do
l_result_string := a_last_html.as_string_8
l_view_state := (find_view_state (l_result_string))
l_validation := (find_event_validation (l_result_string))
l_event_target := ""
l_form := form_for_bug_report (l_view_state, l_validation, l_event_target)
create l_result_html.make
setopt_with_form (l_result_html, l_form)
easy_perform
Result := l_result_html.string
end
html_of_final_submit_page (a_final_sutmit_page: STRING): STRING_GENERAL is
-- HTML content of final bug report submit confirm page.
require
not_void: curl_handle /= default_pointer
not_void: a_final_sutmit_page /= Void
local
l_result_html: CURL_MEMORY_STRUCT
do
create l_result_html.make
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_post, 0)
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_url, a_final_sutmit_page)
curl_easy.setopt_memory_struct (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_writedata, l_result_html)
easy_perform
Result := l_result_html.string
end
feature {NONE} -- Finding in html
find_view_state (a_string: STRING): STRING is
-- Find __VIEWSTATE value in `a_string'.
require
not_void: a_string /= Void
local
l_matcher: RX_PCRE_MATCHER
do
create l_matcher.make
l_matcher.compile ("")
l_matcher.match (a_string)
if l_matcher.has_matched then
Result := l_matcher.captured_substring (1)
l_matcher.next_match
check no_more: not l_matcher.has_matched end
end
end
find_location (a_string: STRING): STRING is
-- Find href in `a_string'.
require
not_void: a_string /= Void
local
l_matcher: RX_PCRE_MATCHER
do
create l_matcher.make
l_matcher.compile ("here")
l_matcher.match (a_string)
if l_matcher.has_matched then
Result := l_matcher.captured_substring (1)
l_matcher.next_match
check no_more: not l_matcher.has_matched end
end
end
find_event_validation (a_string: STRING): STRING is
-- Find EVENT_VALIDATION value in `a_string'.
require
not_void: a_string /= Void
local
l_matcher: RX_PCRE_MATCHER
do
create l_matcher.make
l_matcher.compile ("")
l_matcher.match (a_string)
if l_matcher.has_matched then
Result := l_matcher.captured_substring (1)
l_matcher.next_match
check no_more: not l_matcher.has_matched end
end
end
is_login_successed (a_html: STRING): BOOLEAN is
-- Find if account information redirection codes exist in return HTML
require
not_void: a_html /= Void
local
l_matcher: RX_PCRE_MATCHER
do
create l_matcher.make
l_matcher.compile ("Object\smoved\sto\shere")
l_matcher.match (a_html)
Result := l_matcher.has_matched
end
feature {NONE} -- cURL level implementations
init is
-- Prepare cURL environment.
local
l_file: RAW_FILE
do
curl.global_init
curl_handle := curl_easy.init
debug ("cURL")
curl_easy.set_debug_function (curl_handle)
end
curl_easy.set_write_function (curl_handle)
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_cookiefile, "cookie.txt")
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_ssl_verifypeer, 0)
create l_file.make_create_read_write (temp_file)
l_file.close
ensure
exists: curl_handle /= default_pointer
end
easy_perform is
-- Perform a cURL action.
require
not_void: curl_handle /= default_pointer
do
last_result := curl_easy.perform (curl_handle)
if last_result /= {CURL_CODES}.curle_ok then
(create {EXCEPTIONS}).raise ("cURL error: " + last_result.out)
end
end
setopt_with_form (a_data: CURL_MEMORY_STRUCT; a_formpost: CURL_FORM) is
-- Set options with `a_formpost'.
require
not_void_and_exists: a_formpost /= Void and then a_formpost.is_exists
not_void: curl_handle /= default_pointer
do
curl_easy.setopt_memory_struct (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_writedata, a_data)
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_cookie, "____Pagemain_div__ToggleState=1; ____Pagemain_id__ToggleState=1")
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_url, "https://www2.eiffel.com/support/protected/problem_report_form.aspx")
curl_easy.setopt_form (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httppost, a_formpost)
end
form_for_bug_report (a_view_state_value: STRING; a_event_validation_value: STRING; a_event_target: STRING): CURL_FORM is
-- Create a form for bug report submit.
require
not_void: a_view_state_value /= Void
not_void: a_event_validation_value /= Void
not_void: a_event_target /= Void
local
l_last_form: CURL_FORM
do
create Result.make
create l_last_form.make
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "__EVENTTARGET", {CURL_FORM_CONSTANTS}.curlform_copycontents, "a_event_target", {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "__EVENTARGUMENT", {CURL_FORM_CONSTANTS}.curlform_copycontents, "", {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "__LASTFOCUS", {CURL_FORM_CONSTANTS}.curlform_copycontents, "", {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "__VIEWSTATE", {CURL_FORM_CONSTANTS}.curlform_copycontents, a_view_state_value, {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$category_list", {CURL_FORM_CONSTANTS}.curlform_copycontents, "24", {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$severity_list", {CURL_FORM_CONSTANTS}.curlform_copycontents, "3", {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$class_list", {CURL_FORM_CONSTANTS}.curlform_copycontents, "1", {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$priority_list", {CURL_FORM_CONSTANTS}.curlform_copycontents, "3", {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$release_text", {CURL_FORM_CONSTANTS}.curlform_copycontents, data.release, {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$confidential_list", {CURL_FORM_CONSTANTS}.curlform_copycontents, "True", {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$environment_text", {CURL_FORM_CONSTANTS}.curlform_copycontents, data.environment, {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$synopsis_text", {CURL_FORM_CONSTANTS}.curlform_copycontents, data.synopsis, {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$attachments_table$uploaded_file", {CURL_FORM_CONSTANTS}.curlform_file, temp_file, {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$description_text", {CURL_FORM_CONSTANTS}.curlform_copycontents, data.description, {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$to_reproduce_text", {CURL_FORM_CONSTANTS}.curlform_copycontents, "", {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "ctl00$ctl00$default_main_content$main_content$submit_button", {CURL_FORM_CONSTANTS}.curlform_copycontents, "Preview", {CURL_FORM_CONSTANTS}.curlform_end)
curl.formadd_string_string (Result, l_last_form, {CURL_FORM_CONSTANTS}.curlform_copyname, "__EVENTVALIDATION", {CURL_FORM_CONSTANTS}.curlform_copycontents, a_event_validation_value, {CURL_FORM_CONSTANTS}.curlform_end)
ensure
exist: Result /= Void and then Result.is_exists
end
post_string_for_login (a_view_state, a_event_validation: STRING; a_username, a_password: STRING): STRING is
-- Create post string for login page.
require
not_void: a_view_state /= Void
not_void: a_event_validation /= Void
not_void: a_username /= Void
not_void: a_password /= Void
do
create Result.make_empty
Result.append ("__EVENTTARGET=")
Result.append ("&")
Result.append ("__EVENTARGUMENT=")
Result.append ("&")
Result.append ("__VIEWSTATE=" + a_view_state)
Result.append ("&")
Result.append ("ctl00%%24ctl00%%24default_main_content%%24main_content%%24display_username=")
Result.append ("&")
Result.append ("ctl00%%24ctl00%%24default_main_content%%24main_content%%24register_username=" + a_username)
Result.append ("&")
Result.append ("ctl00%%24ctl00%%24default_main_content%%24main_content%%24display_password=")
Result.append ("&")
Result.append ("ctl00%%24ctl00%%24default_main_content%%24main_content%%24register_password=" + a_password)
Result.append ("&")
Result.append ("ctl00%%24ctl00%%24default_main_content%%24main_content%%24login_button=Login")
Result.append ("&")
Result.append ("__EVENTVALIDATION=" + a_event_validation)
ensure
not_void: Result /= Void
end
post_string_for_final_submit (a_view_state, a_event_validation: STRING): STRING is
-- Post strings for final bug report submit.
require
not_void: a_view_state /= Void
not_viod: a_event_validation /= Void
do
create Result.make_empty
Result.append ("__EVENTTARGET=ctl00%%24ctl00%%24default_main_content%%24main_content%%24SubmitLink")
Result.append ("&")
Result.append ("__EVENTARGUMENT=")
Result.append ("&")
Result.append ("__VIEWSTATE=" + a_view_state)
Result.append ("&")
Result.append ("__EVENTVALIDATION=" + a_event_validation)
ensure
not_void: Result /= Void
end
clean_up is
-- Clean up resources.
local
l_file: RAW_FILE
do
if curl_handle /= default_pointer then
curl_easy.cleanup (curl_handle)
curl_handle := default_pointer
end
create l_file.make_open_read (temp_file)
if l_file.exists then
l_file.close
l_file.delete
end
ensure
cleared: curl_handle = default_pointer
file_deleted:
end
url_encoding (a_string: STRING) is
-- Simple URL encoding.
-- Only replace / and + for the moment.
require
not_void: a_string /= Void
do
a_string.replace_substring_all ("/", "%%2F")
a_string.replace_substring_all ("+", "%%2B")
ensure
replaced: not a_string.has_substring ("/")
replaced: not a_string.has_substring ("+")
end
feature {NONE} -- Implementation attributes
curl: CURL_EXTERNALS is
-- cURL externals.
once
create Result
ensure
not_void: Result /= Void
end
curl_easy: CURL_EASY_EXTERNALS is
-- cURL easy externals.
once
create Result
ensure
not_void: Result /= Void
end
temp_file: STRING is "bug_report_tmp.txt"
-- Temp file name.
curl_handle: POINTER
-- cURL C handle.
invariant
not_void: login_failed_actions /= Void
not_void: curl_failed_actions /= Void
indexing
copyright: "Copyright (c) 1984-2007, Eiffel Software"
license: "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)"
licensing_options: "http://www.eiffel.com/licensing"
copying: "[
This file is part of Eiffel Software's Eiffel Development Environment.
Eiffel Software's Eiffel Development Environment 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, version 2 of the License
(available at the URL listed under "license" above).
Eiffel Software's Eiffel Development Environment is
distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with Eiffel Software's Eiffel Development
Environment; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
]"
source: "[
Eiffel Software
356 Storke Road, Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end