pione 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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