pione 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +1 -0
  3. data/History.txt +7 -0
  4. data/example/DeferredChoice/DeferredChoice.pione +14 -7
  5. data/{misc → example/DeferredChoice/bin}/ui.xml +11 -6
  6. data/example/DeferredChoice/pione-package.json +1 -1
  7. data/example/DeferredChoiceWithPage/DeferredChoiceWithPage.pione +47 -0
  8. data/example/DeferredChoiceWithPage/etc/index.html +22 -0
  9. data/example/DeferredChoiceWithPage/pione-package.json +18 -0
  10. data/example/Interaction/Interaction.pione +27 -0
  11. data/example/Interaction/bin/show-environment.cgi +45 -0
  12. data/example/Interaction/etc/.hidden-file.txt +1 -0
  13. data/example/Interaction/etc/cgi.html +46 -0
  14. data/example/Interaction/etc/create-files.html +51 -0
  15. data/example/Interaction/etc/delete-files.html +31 -0
  16. data/example/Interaction/etc/get-files.html +21 -0
  17. data/example/Interaction/etc/index.html +18 -0
  18. data/example/Interaction/etc/list-files.html +36 -0
  19. data/example/Interaction/pione-package.json +24 -0
  20. data/lib/pione/agent/job-manager.rb +19 -3
  21. data/lib/pione/agent/logger.rb +9 -9
  22. data/lib/pione/agent/messenger.rb +3 -2
  23. data/lib/pione/agent/task-worker.rb +32 -10
  24. data/lib/pione/command/option.rb +18 -0
  25. data/lib/pione/command/pione-client.rb +51 -22
  26. data/lib/pione/command/pione-interactive.rb +128 -55
  27. data/lib/pione/command/pione-package-build.rb +3 -3
  28. data/lib/pione/command/pione-task-worker.rb +23 -10
  29. data/lib/pione/command/pione-tuple-space-provider.rb +8 -8
  30. data/lib/pione/command/spawner.rb +28 -1
  31. data/lib/pione/front/interactive-front.rb +76 -0
  32. data/lib/pione/global/interactive-variable.rb +26 -0
  33. data/lib/pione/log/message-log-receiver.rb +4 -2
  34. data/lib/pione/model/task-worker-broker-model.rb +7 -1
  35. data/lib/pione/package/package-archiver.rb +16 -9
  36. data/lib/pione/package/package-handler.rb +6 -0
  37. data/lib/pione/package/package-info.rb +4 -0
  38. data/lib/pione/package/package-reader.rb +2 -4
  39. data/lib/pione/package/package-scanner.rb +23 -3
  40. data/lib/pione/rule-engine.rb +48 -19
  41. data/lib/pione/rule-engine/action-handler.rb +29 -5
  42. data/lib/pione/rule-engine/basic-handler.rb +27 -19
  43. data/lib/pione/test-helper/command-helper.rb +1 -1
  44. data/lib/pione/tuple-space/tuple-definition.yml +2 -3
  45. data/lib/pione/tuple-space/tuple-space-server.rb +8 -0
  46. data/lib/pione/util/cgi.rb +326 -0
  47. data/lib/pione/version.rb +1 -1
  48. data/lib/rootage/normalizer.rb +4 -0
  49. data/lib/rootage/option.rb +11 -4
  50. data/test/agent/spec_logger.rb +0 -1
  51. data/test/agent/spec_messenger.rb +1 -1
  52. data/test/command/spec_pione-client.rb +4 -4
  53. data/test/log/spec_message-log.rb +1 -1
  54. data/test/rule-engine/spec_action-handler.rb +25 -5
  55. data/test/rule-engine/spec_empty-handler.rb +36 -3
  56. data/test/rule-engine/spec_flow-handler.rb +90 -7
  57. metadata +22 -72
  58. data/misc/test-drb-stop-service.rb +0 -34
  59. data/misc/test-many-waiters-client.rb +0 -56
  60. data/misc/test-many-waiters-server.rb +0 -14
@@ -1,27 +1,56 @@
1
1
  module Pione
2
2
  # RuleEngine is a namespace for rule engine classes.
3
3
  module RuleEngine
4
- def self.make(space, env, package_id, rule_name, inputs, param_set, domain_id, caller_id)
5
- rule_definition = env.rule_get(Lang::RuleExpr.new(rule_name, package_id))
6
- handler =
7
- case rule_definition
8
- when Lang::FlowRuleDefinition ; FlowHandler
9
- when Lang::ActionRuleDefinition; ActionHandler
10
- when Lang::EmptyRuleDefinition ; EmptyHandler
11
- when Lang::RootRuleDefinition ; RootHandler
4
+ require 'pione/rule-engine/engine-exception'
5
+ require 'pione/rule-engine/data-finder'
6
+ require 'pione/rule-engine/basic-handler'
7
+ require 'pione/rule-engine/update-criteria'
8
+ require 'pione/rule-engine/flow-handler'
9
+ require 'pione/rule-engine/action-handler'
10
+ require 'pione/rule-engine/root-handler'
11
+ require 'pione/rule-engine/system-handler'
12
+ require 'pione/rule-engine/empty-handler'
13
+
14
+ # Relation from rule definition to the handler.
15
+ HANDLER = {
16
+ Lang::FlowRuleDefinition => FlowHandler,
17
+ Lang::ActionRuleDefinition => ActionHandler,
18
+ Lang::EmptyRuleDefinition => EmptyHandler,
19
+ Lang::RootRuleDefinition => RootHandler
20
+ }
21
+
22
+ # Make a rule handler with target rule's informations.
23
+ #
24
+ # @param [Hash.new] param
25
+ # @option param [String] :package_id
26
+ # package ID
27
+ # @option param [String] :rule_name
28
+ # rule name
29
+ # @option param [Array] :inputs
30
+ # input data
31
+ # @option param [Object] :param_set
32
+ # parameter set
33
+ # @option param [String] :domain_id
34
+ # domain ID
35
+ # @option param [String] :caller_id
36
+ # caller ID
37
+ # @option param [URI] :request_from
38
+ # URI that the client requested the job from
39
+ # @option param [String] :session_id
40
+ # session ID
41
+ def self.make(param)
42
+ # check requisite parameters
43
+ requisites = [:tuple_space, :env, :package_id, :rule_name, :inputs, :param_set, :domain_id, :caller_id]
44
+ requisites.each do |requisite|
45
+ unless param.has_key?(requisite)
46
+ raise ArgumentError.new("parameter '%s' is requisite for rule engine." % requisite)
12
47
  end
13
- handler.new(space, env, package_id, rule_name, rule_definition, inputs, param_set, domain_id, caller_id)
48
+ end
49
+
50
+ # make a rule handler
51
+ rule_definition = param[:env].rule_get(Lang::RuleExpr.new(param[:rule_name], param[:package_id]))
52
+ HANDLER[rule_definition.class].new(param.merge(rule_definition: rule_definition))
14
53
  end
15
54
  end
16
55
  end
17
56
 
18
- require 'pione/rule-engine/engine-exception'
19
- require 'pione/rule-engine/data-finder'
20
- require 'pione/rule-engine/basic-handler'
21
- require 'pione/rule-engine/update-criteria'
22
- require 'pione/rule-engine/flow-handler'
23
- require 'pione/rule-engine/action-handler'
24
- require 'pione/rule-engine/root-handler'
25
- require 'pione/rule-engine/system-handler'
26
- require 'pione/rule-engine/empty-handler'
27
-
@@ -8,8 +8,8 @@ module Pione
8
8
 
9
9
  attr_reader :working_directory
10
10
 
11
- def initialize(*args)
12
- super(*args)
11
+ def initialize(param)
12
+ super(param)
13
13
  @working_directory = Location[Global.working_directory_generator.mkdir]
14
14
  @env.variable_set(
15
15
  Lang::Variable.new("__WORKING_DIRECTORY__"),
@@ -22,7 +22,7 @@ module Pione
22
22
  # prepare input files
23
23
  setup_working_directory
24
24
  # prepare shell script
25
- write_shell_script {|path| call_shell_script(path) }
25
+ write_shell_script {|path| call_shell_script(path)}
26
26
  # collect outputs
27
27
  outputs = collect_outputs
28
28
  # write output data
@@ -68,16 +68,30 @@ module Pione
68
68
  bin.entries.each do |entry|
69
69
  dest = @working_directory + "bin" + entry.basename
70
70
  unless dest.exist?
71
+ # copy and set executable flag
71
72
  entry.copy(dest)
72
73
  dest.path.chmod(0700)
73
74
  end
74
75
  end
75
76
  end
77
+
78
+ # FIXME: should not copy files in the package each time
79
+ file_dir = @base_location + "package" + "etc"
80
+ if file_dir.exist?
81
+ file_dir.entries.each do |entry|
82
+ dest = @working_directory + "etc" + entry.basename
83
+ unless dest.exist?
84
+ # copy and unset executable flag
85
+ entry.copy(dest)
86
+ dest.path.chmod(0600)
87
+ end
88
+ end
89
+ end
76
90
  end
77
91
 
78
92
  # Write the action into a shell script.
79
93
  def write_shell_script(&b)
80
- file = @working_directory + "__pione-action__.sh"
94
+ file = @working_directory + "__pione__.sh"
81
95
  content = @rule_definition.action_context.eval(@env).content
82
96
  sh = Util::EmbededExprExpander.expand(@env, content)
83
97
 
@@ -113,7 +127,17 @@ module Pione
113
127
  err = ".stderr"
114
128
 
115
129
  # execute command
116
- `cd #{@working_directory.path}; PATH=#{(@working_directory + "bin").path}:$PATH ; ./#{scriptname} > #{out} 2> #{err}`
130
+ # `cd #{}; PATH=#{(@working_directory + "bin").path}:$PATH; ./#{scriptname} > #{out} 2> #{err}`
131
+ callee_env = {
132
+ "PATH" => (@working_directory + "bin").path.to_s + ";" + ENV["PATH"],
133
+ "PIONE_SESSION_ID" => @session_id,
134
+ "PIONE_REQUEST_FROM" => @request_from.to_s,
135
+ "PIONE_CLIENT_UI" => @client_ui.to_s
136
+ }
137
+ command = "./#{scriptname} > #{out} 2> #{err}"
138
+ options = {:chdir => @working_directory.path.to_s}
139
+
140
+ system(callee_env, command, options)
117
141
 
118
142
  # the case the script has errored
119
143
  unless $?.success?
@@ -22,26 +22,32 @@ module Pione
22
22
  attr_reader :caller_id # from domain
23
23
 
24
24
  # Create a new handler for rule.
25
- def initialize(space, env, package_id, rule_name, rule_definition, inputs, param_set, domain_id, caller_id)
25
+ #
26
+ # @param [Hash] param
27
+ # see `RuleEngine.make`
28
+ def initialize(param)
26
29
  ### set tuple space server
27
- set_tuple_space(space)
30
+ set_tuple_space(param[:tuple_space])
28
31
 
29
32
  ### set informations
30
- @plain_env = env
31
- @env = setup_env(env, param_set)
32
- @package_id = package_id
33
- @rule_name = rule_name
34
- @rule_definition = rule_definition
35
- @rule_condition = rule_definition.rule_condition_context.eval(@env)
36
- @inputs = inputs
33
+ @plain_env = param[:env]
34
+ @env = setup_env(param[:env], param[:param_set])
35
+ @package_id = param[:package_id]
36
+ @rule_name = param[:rule_name]
37
+ @rule_definition = param[:rule_definition]
38
+ @rule_condition = @rule_definition.rule_condition_context.eval(@env)
39
+ @inputs = param[:inputs]
37
40
  @outputs = []
38
- @param_set = param_set
39
- @digest = Util::TaskDigest.generate(package_id, rule_name, inputs, param_set)
41
+ @param_set = param[:param_set]
42
+ @digest = Util::TaskDigest.generate(@package_id, @rule_name, @inputs, @param_set)
40
43
  @base_location = read!(TupleSpace::BaseLocationTuple.any).location
41
44
  @dry_run = begin read!(TupleSpace::DryRunTuple.any).availability rescue false end
42
- @domain_id = domain_id
45
+ @domain_id = param[:domain_id]
43
46
  @domain_location = make_location("", @domain_id)
44
- @caller_id = caller_id
47
+ @caller_id = param[:caller_id]
48
+ @request_from = param[:request_from]
49
+ @session_id = param[:session_id]
50
+ @client_ui = param[:client_ui]
45
51
  end
46
52
 
47
53
  # Handle the rule and return the outputs.
@@ -54,12 +60,14 @@ module Pione
54
60
  user_message(@digest, 0, "==>")
55
61
  debug_message("caller: %s" % @caller_id)
56
62
 
57
- # save domain log
58
- Log::DomainLog.new(self).save
63
+ unless @domain_id == "root"
64
+ # save domain log
65
+ Log::DomainLog.new(self).save
59
66
 
60
- # save a domain dump file
61
- domain_dump_location = @working_directory ? @working_directory :@domain_location
62
- System::DomainDump.new(env.dumpable).write(domain_dump_location)
67
+ # save a domain dump file
68
+ domain_dump_location = @working_directory ? @working_directory :@domain_location
69
+ System::DomainDump.new(env.dumpable).write(domain_dump_location)
70
+ end
63
71
 
64
72
  # execute the rule
65
73
  outputs = execute
@@ -96,7 +104,7 @@ module Pione
96
104
  # the location
97
105
  def make_location(name, domain_id)
98
106
  if domain_id == "root"
99
- return @base_location + "./%s" % name
107
+ return @base_location + "./output/%s" % name
100
108
  else
101
109
  # make relative path
102
110
  pakcage_id, rule_name, task_id = domain_id.split(":")
@@ -11,7 +11,7 @@ module Pione
11
11
  def self.test(context, &b)
12
12
  # with client mode
13
13
  new(context: context).tap do |runner|
14
- runner.default_arguments = ["-o", runner.base.path.to_s]
14
+ runner.default_arguments = ["--base", runner.base.path.to_s]
15
15
  b.call(runner)
16
16
  end
17
17
  end
@@ -10,9 +10,8 @@ AgentTuple:
10
10
 
11
11
  AttributeTuple:
12
12
  - attribute
13
- - key: # attribute name
14
- "String"
15
- - value # attribute value
13
+ - key: String # attribute name
14
+ - value # attribute value
16
15
 
17
16
  BaseLocationTuple:
18
17
  - base_location
@@ -191,6 +191,14 @@ module Pione
191
191
  end
192
192
  end
193
193
 
194
+ def attribute(name)
195
+ if tuple = read!(TupleSpace::AttributeTuple.new(key: name))
196
+ return tuple.value
197
+ else
198
+ return nil
199
+ end
200
+ end
201
+
194
202
  def inspect
195
203
  "#<Pione::TupleSpace::TupleSpaceServer:%s>" % object_id
196
204
  end
@@ -0,0 +1,326 @@
1
+ module Pione
2
+ module Util
3
+ module CGIUtils
4
+ def self.decode(string)
5
+ URI.decode_www_form_component(string)
6
+ end
7
+ end
8
+
9
+ # CGIInfo is a store of CGI meta-variables based on RFC3875.
10
+ class CGIInfo
11
+ # CGI meta-variable "AUTH_TYPE"
12
+ attr_accessor :auth_type
13
+
14
+ # CGI meta-variable "CONTENT_LENGTH"
15
+ attr_accessor :content_length
16
+
17
+ # CGI meta-variable "CONTENT_TYPE"
18
+ attr_accessor :content_type
19
+
20
+ # CGI meta-variable "GATEWAY_INTERFACE"
21
+ attr_accessor :gateway_interface
22
+
23
+ # CGI meta-variable "PATH_INFO"
24
+ attr_accessor :path_info
25
+
26
+ # CGI meta-variable "PATH_TRANSLATED"
27
+ attr_accessor :path_translated
28
+
29
+ # CGI meta-variable "QUERY_STRING"
30
+ attr_accessor :query_string
31
+
32
+ # CGI meta-variable "REMOTE_ADDR"
33
+ attr_accessor :remote_addr
34
+
35
+ # CGI meta-variable "REMOTE_HOST"
36
+ attr_accessor :remote_host
37
+
38
+ # CGI meta-variable "REMOTE_IDENT"
39
+ attr_accessor :remote_ident
40
+
41
+ # CGI meta-variable "REMOTE_USER"
42
+ attr_accessor :remote_user
43
+
44
+ # CGI meta-variable "REQUEST_METHOD"
45
+ attr_accessor :request_method
46
+
47
+ # CGI meta-variable "SCRIPT_NAME"
48
+ attr_accessor :script_name
49
+
50
+ # CGI meta-variable "SERVER_NAME"
51
+ attr_accessor :server_name
52
+
53
+ # CGI meta-variable "SERVER_PORT"
54
+ attr_accessor :server_port
55
+
56
+ # CGI meta-variable "SERVER_PROTOCOL"
57
+ attr_accessor :server_protocol
58
+
59
+ # CGI meta-variable "SERVER_SOFTWARE"
60
+ attr_accessor :server_software
61
+
62
+ # HTTP specific variable table
63
+ attr_accessor :http_header
64
+
65
+ # request body
66
+ attr_accessor :body
67
+
68
+ def initialize
69
+ @auth_type = nil
70
+ @content_length = nil
71
+ @content_type = nil
72
+ @gateway_interface = "CGI/1.1"
73
+ @path_info = nil
74
+ @path_translated = nil
75
+ @query_string = nil
76
+ @remote_addr = nil
77
+ @remote_host = nil
78
+ @remote_ident = nil
79
+ @remote_user = nil
80
+ @request_method = nil
81
+ @script_name = nil
82
+ @server_name = nil
83
+ @server_port = nil
84
+ @server_protocol = "HTTP/1.1"
85
+ @server_software = "PIONE/%s" % Pione::VERSION
86
+ @body = nil
87
+ @http_header = Hash.new
88
+ end
89
+
90
+ # Create environment variables.
91
+ # @return [Hash]
92
+ # environment variables
93
+ def create_env
94
+ env = Hash.new
95
+
96
+ # store CGI meta-variables
97
+ env["AUTH_TYPE"] = @auth_type if @auth_type
98
+ env["CONTENT_LENGTH"] = @content_length if @content_length
99
+ env["CONTENT_TYPE"] = @content_type if @content_type
100
+ env["GATEWAY_INTERFACE"] = @gateway_interface
101
+ env["PATH_INFO"] = @path_info
102
+ env["PATH_TRANSLATED"] = @path_translated
103
+ env["QUERY_STRING"] = @query_string
104
+ env["REMOTE_ADDR"] = @remote_addr
105
+ env["REMOTE_HOST"] = @remote_host
106
+ env["REMOTE_IDENT"] = @remote_ident if @remote_ident
107
+ env["REMOTE_USER"] = @remote_user if @remote_user
108
+ env["REQUEST_METHOD"] = @request_method.to_s
109
+ env["SCRIPT_NAME"] = @script_name
110
+ env["SERVER_NAME"] = @server_name
111
+ env["SERVER_PORT"] = @server_port
112
+ env["SERVER_PROTOCOL"] = @server_protocol
113
+ env["SERVER_SOFTWARE"] = @server_software
114
+
115
+ # store HTTP specific variables
116
+ @http_header.each do |key, val|
117
+ env["HTTP_%s" % key] = val
118
+ end
119
+
120
+ return env
121
+ end
122
+
123
+ def create_arguments
124
+ unless @query_string.include?("=")
125
+ return @query_string.split("+").map do |arg|
126
+ begin
127
+ CGIUtils.decode(arg)
128
+ rescue
129
+ raise CGIError.failed_to_decode(@query_string)
130
+ end
131
+ end
132
+ end
133
+
134
+ return []
135
+ end
136
+ end
137
+
138
+ # CGIExecutor is a execution helper for CGI programs.
139
+ class CGIExecutor
140
+ # @param [Pathname] cgi_path
141
+ # path of the CGI program
142
+ # @param [CGIInfo] cgi_info
143
+ # various informations for CGI program
144
+ def initialize(cgi_path, cgi_info, chdir, timeout)
145
+ @cgi_path = cgi_path
146
+ @cgi_info = cgi_info
147
+ @chdir = chdir
148
+ @timeout = timeout
149
+ @umask = 077
150
+ @cgi_stdin = Temppath.create
151
+ @cgi_stdout = Temppath.create
152
+ @pid = nil
153
+ end
154
+
155
+ # Execute the CGI program.
156
+ def exec
157
+ unless @cgi_path.exist?
158
+ raise CGIError.not_exist(@cgi_path)
159
+ end
160
+
161
+ env = @cgi_info.create_env
162
+ options = create_options
163
+ args = @cgi_info.create_arguments
164
+
165
+ Timeout.timeout(@timeout) do
166
+ @pid = Kernel.spawn(env, @cgi_path.to_s, *args, options)
167
+ Process.waitpid(@pid)
168
+ if @cgi_stdout.exist?
169
+ return analyze_response(Location[@cgi_stdout].read)
170
+ else
171
+ raise CGIError.response_not_found
172
+ end
173
+ end
174
+ rescue Timeout::Error
175
+ if @pid
176
+ begin
177
+ Process.kill(15, @pid)
178
+ rescue
179
+ ensure
180
+ CGIError.timeouted
181
+ end
182
+ end
183
+ rescue Errno::EACCES => e
184
+ CGIError.cannot_execute_cgi(@cgi_path)
185
+ end
186
+
187
+ private
188
+
189
+ def nph?
190
+ Pathname.new(@cgi_path).basename.to_s.start_with?("nph-")
191
+ end
192
+
193
+ def create_options
194
+ options = Hash.new
195
+ options[:chdir] = @chdir.path.to_s
196
+ options[:umask] = @umask
197
+ if @cgi_info.body
198
+ Location[@cgi_stdin].write(@cgi_info.body)
199
+ options[:in] = @cgi_stdin.to_s
200
+ end
201
+ options[:out] = @cgi_stdout.to_s
202
+ return options
203
+ end
204
+
205
+ def analyze_response(stdout)
206
+ cgi_response = CGIResponse.new
207
+
208
+ if nph?
209
+ cgi_response.nph = true
210
+ cgi_response.body = stdout
211
+ else
212
+ cgi_response.nph = false
213
+
214
+ # parse headers
215
+ headers, body = stdout.split(/\r\n\r\n|\r\r|\n\n/, 2)
216
+ header = headers.split(/\r\n|\r|\n/).each_with_object(Hash.new) do |line, table|
217
+ name, value = line.split(/:[\s\t]*/, 2)
218
+ if name.nil? or name.size == 0 or /\s/.match(name) or value.nil?
219
+ raise CGIError.invalid_response_header(line)
220
+ else
221
+ table[name.downcase] = value
222
+ end
223
+ end
224
+
225
+ # content-type
226
+ if header.has_key?("content-type")
227
+ cgi_response.content_type = header["content-type"]
228
+ else
229
+ raise CGIError.content_type_not_found
230
+ end
231
+
232
+ # location
233
+ if header["location"]
234
+ begin
235
+ uri = URI.parse(header["location"])
236
+ cgi_response.location = header["location"]
237
+ rescue
238
+ raise CGIError.invalid_location(header["location"])
239
+ end
240
+ end
241
+
242
+ # status
243
+ if header["status"]
244
+ code, reason_phrase = status.split(/\s+/, 2)
245
+ if /\d\d\d/.match(code)
246
+ cgi_response.status_code = code
247
+ cgi_response.reason_phrase = reason_phrase
248
+ else
249
+ raise CGIError.invalid_status(code)
250
+ end
251
+ end
252
+
253
+ # body
254
+ cgi_response.body = body
255
+ end
256
+
257
+ return cgi_response
258
+ end
259
+ end
260
+
261
+ class CGIResponse
262
+ attr_accessor :nph
263
+ attr_accessor :content_type
264
+ attr_accessor :location
265
+ attr_accessor :status_code
266
+ attr_accessor :reason_phrase
267
+ attr_accessor :body
268
+
269
+ def initialize
270
+ @nph = false
271
+ @content_type = nil
272
+ @location = nil
273
+ @status_code = 200
274
+ @reason_phrase = nil
275
+ @body = nil
276
+ end
277
+
278
+ def nph?
279
+ @nph
280
+ end
281
+
282
+ def valid?
283
+ not(@content_type.nil?)
284
+ end
285
+ end
286
+
287
+ # CGIError is an error class for occuring errors of CGI execution.
288
+ class CGIError < StandardError
289
+ def self.not_exist(path)
290
+ new("CGI program not exist at %s." % path)
291
+ end
292
+
293
+ def self.failed_to_decode(string)
294
+ new("Failed to decode the string as URL: %s" % string)
295
+ end
296
+
297
+ def self.invalid_response_header(line)
298
+ new("Inlivad CGI response header has found: \"%s\"" % line)
299
+ end
300
+
301
+ def self.content_type_not_found
302
+ new("Requisite CGI response header \"Content-Type\" has not found.")
303
+ end
304
+
305
+ def self.invalid_location(value)
306
+ new("Invalid location has found: \"%s\"" % value)
307
+ end
308
+
309
+ def self.invalid_status(code)
310
+ new("Invalid status code has found: \"%s\"" % code)
311
+ end
312
+
313
+ def self.response_not_found
314
+ "No CGI response."
315
+ end
316
+
317
+ def self.cannot_execute_cgi(cgi_path)
318
+ "Cannot execute the CGI: %s" % cgi_path.to_s
319
+ end
320
+
321
+ def self.timeouted
322
+ "CGI exectuion has been timeouted."
323
+ end
324
+ end
325
+ end
326
+ end