goliath 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of goliath might be problematic. Click here for more details.
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.yardopts +2 -0
- data/Gemfile +3 -0
- data/LICENSE +66 -0
- data/README.md +86 -0
- data/Rakefile +18 -0
- data/examples/activerecord/config/srv.rb +7 -0
- data/examples/activerecord/srv.rb +37 -0
- data/examples/async_upload.rb +34 -0
- data/examples/conf_test.rb +27 -0
- data/examples/config/conf_test.rb +12 -0
- data/examples/config/echo.rb +1 -0
- data/examples/config/http_log.rb +7 -0
- data/examples/config/shared.rb +5 -0
- data/examples/custom_server.rb +57 -0
- data/examples/echo.rb +37 -0
- data/examples/gziped.rb +40 -0
- data/examples/hello_world.rb +10 -0
- data/examples/http_log.rb +85 -0
- data/examples/rack_routes.rb +44 -0
- data/examples/stream.rb +37 -0
- data/examples/valid.rb +19 -0
- data/goliath.gemspec +41 -0
- data/lib/goliath.rb +38 -0
- data/lib/goliath/api.rb +165 -0
- data/lib/goliath/application.rb +90 -0
- data/lib/goliath/connection.rb +94 -0
- data/lib/goliath/constants.rb +51 -0
- data/lib/goliath/env.rb +92 -0
- data/lib/goliath/goliath.rb +49 -0
- data/lib/goliath/headers.rb +37 -0
- data/lib/goliath/http_status_codes.rb +44 -0
- data/lib/goliath/plugins/latency.rb +33 -0
- data/lib/goliath/rack/default_mime_type.rb +30 -0
- data/lib/goliath/rack/default_response_format.rb +33 -0
- data/lib/goliath/rack/formatters/html.rb +90 -0
- data/lib/goliath/rack/formatters/json.rb +42 -0
- data/lib/goliath/rack/formatters/xml.rb +90 -0
- data/lib/goliath/rack/heartbeat.rb +23 -0
- data/lib/goliath/rack/jsonp.rb +38 -0
- data/lib/goliath/rack/params.rb +30 -0
- data/lib/goliath/rack/render.rb +66 -0
- data/lib/goliath/rack/tracer.rb +31 -0
- data/lib/goliath/rack/validation/boolean_value.rb +59 -0
- data/lib/goliath/rack/validation/default_params.rb +46 -0
- data/lib/goliath/rack/validation/numeric_range.rb +59 -0
- data/lib/goliath/rack/validation/request_method.rb +33 -0
- data/lib/goliath/rack/validation/required_param.rb +54 -0
- data/lib/goliath/rack/validation/required_value.rb +58 -0
- data/lib/goliath/rack/validation_error.rb +38 -0
- data/lib/goliath/request.rb +199 -0
- data/lib/goliath/response.rb +93 -0
- data/lib/goliath/runner.rb +236 -0
- data/lib/goliath/server.rb +149 -0
- data/lib/goliath/test_helper.rb +118 -0
- data/lib/goliath/version.rb +4 -0
- data/spec/integration/async_request_processing.rb +23 -0
- data/spec/integration/echo_spec.rb +27 -0
- data/spec/integration/keepalive_spec.rb +28 -0
- data/spec/integration/pipelining_spec.rb +43 -0
- data/spec/integration/valid_spec.rb +24 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/unit/connection_spec.rb +59 -0
- data/spec/unit/env_spec.rb +55 -0
- data/spec/unit/headers_spec.rb +53 -0
- data/spec/unit/rack/default_mime_type_spec.rb +34 -0
- data/spec/unit/rack/formatters/json_spec.rb +54 -0
- data/spec/unit/rack/formatters/xml_spec.rb +66 -0
- data/spec/unit/rack/heartbeat_spec.rb +47 -0
- data/spec/unit/rack/params_spec.rb +94 -0
- data/spec/unit/rack/render_spec.rb +87 -0
- data/spec/unit/rack/validation/boolean_value_spec.rb +54 -0
- data/spec/unit/rack/validation/default_params_spec.rb +71 -0
- data/spec/unit/rack/validation/numeric_range_spec.rb +96 -0
- data/spec/unit/rack/validation/request_method_spec.rb +47 -0
- data/spec/unit/rack/validation/required_param_spec.rb +92 -0
- data/spec/unit/rack/validation/required_value_spec.rb +99 -0
- data/spec/unit/rack/validation_error_spec.rb +40 -0
- data/spec/unit/request_spec.rb +59 -0
- data/spec/unit/response_spec.rb +35 -0
- data/spec/unit/runner_spec.rb +129 -0
- data/spec/unit/server_spec.rb +137 -0
- metadata +409 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
module Goliath
|
2
|
+
# The main execution class for Goliath. This will execute in the at_exit
|
3
|
+
# handler to run the server.
|
4
|
+
#
|
5
|
+
# @private
|
6
|
+
class Application
|
7
|
+
# Most of this stuff is straight out of sinatra.
|
8
|
+
|
9
|
+
# Set of caller regex's to be skippe when looking for our API file
|
10
|
+
CALLERS_TO_IGNORE = [ # :nodoc:
|
11
|
+
/\/goliath(\/(application))?\.rb$/, # all goliath code
|
12
|
+
/rubygems\/custom_require\.rb$/, # rubygems require hacks
|
13
|
+
/bundler(\/runtime)?\.rb/, # bundler require hacks
|
14
|
+
/<internal:/ # internal in ruby >= 1.9.2
|
15
|
+
]
|
16
|
+
|
17
|
+
# @todo add rubinius (and hopefully other VM impls) ignore patterns ...
|
18
|
+
CALLERS_TO_IGNORE.concat(RUBY_IGNORE_CALLERS) if defined?(RUBY_IGNORE_CALLERS)
|
19
|
+
|
20
|
+
# Like Kernel#caller but excluding certain magic entries and without
|
21
|
+
# line / method information; the resulting array contains filenames only.
|
22
|
+
def self.caller_files
|
23
|
+
caller_locations.map { |file, line| file }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Like caller_files, but containing Arrays rather than strings with the
|
27
|
+
# first element being the file, and the second being the line.
|
28
|
+
def self.caller_locations
|
29
|
+
caller(1).
|
30
|
+
map { |line| line.split(/:(?=\d|in )/)[0,2] }.
|
31
|
+
reject { |file, line| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Find the app_file that was used to execute the application
|
35
|
+
#
|
36
|
+
# @return [String] The app file
|
37
|
+
def self.app_file
|
38
|
+
c = caller_files.first
|
39
|
+
c = $0 if !c || c.empty?
|
40
|
+
c
|
41
|
+
end
|
42
|
+
|
43
|
+
# Execute the application
|
44
|
+
#
|
45
|
+
# @return [Nil]
|
46
|
+
def self.run!
|
47
|
+
file = File.basename(app_file, '.rb')
|
48
|
+
klass = Kernel.const_get(camel_case(file))
|
49
|
+
api = klass.new
|
50
|
+
|
51
|
+
runner = Goliath::Runner.new(ARGV, api)
|
52
|
+
runner.load_app do
|
53
|
+
klass.middlewares.each do |mw|
|
54
|
+
use(*(mw[0..1].compact), &mw[2])
|
55
|
+
end
|
56
|
+
|
57
|
+
# If you use map you can't use run as
|
58
|
+
# the rack builder will blowup.
|
59
|
+
if klass.maps.empty?
|
60
|
+
run api
|
61
|
+
else
|
62
|
+
klass.maps.each do |mp|
|
63
|
+
map(mp.first, &mp.last)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
runner.load_plugins(klass.plugins)
|
69
|
+
runner.run
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Convert a string to camel case
|
75
|
+
#
|
76
|
+
# @param str [String] The string to convert
|
77
|
+
# @return [String] The camel cased string
|
78
|
+
def self.camel_case(str)
|
79
|
+
return str if str !~ /_/ && str =~ /[A-Z]+.*/
|
80
|
+
|
81
|
+
str.split('_').map { |e| e.capitalize }.join
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
at_exit do
|
86
|
+
if $!.nil? && $0 == Goliath::Application.app_file
|
87
|
+
Application.run!
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'http/parser'
|
2
|
+
require 'goliath/env'
|
3
|
+
|
4
|
+
module Goliath
|
5
|
+
# The Goliath::Connection class handles sending and receiving data
|
6
|
+
# from the client.
|
7
|
+
#
|
8
|
+
# @private
|
9
|
+
class Connection < EM::Connection
|
10
|
+
include Constants
|
11
|
+
|
12
|
+
attr_accessor :app, :api, :port, :logger, :status, :config, :options
|
13
|
+
attr_reader :parser
|
14
|
+
|
15
|
+
AsyncResponse = [-1, {}, []].freeze
|
16
|
+
|
17
|
+
def post_init
|
18
|
+
@current = nil
|
19
|
+
@requests = []
|
20
|
+
@pending = []
|
21
|
+
|
22
|
+
@parser = Http::Parser.new
|
23
|
+
@parser.on_headers_complete = proc do |h|
|
24
|
+
|
25
|
+
env = Goliath::Env.new
|
26
|
+
env[OPTIONS] = options
|
27
|
+
env[SERVER_PORT] = port.to_s
|
28
|
+
env[LOGGER] = logger
|
29
|
+
env[OPTIONS] = options
|
30
|
+
env[STATUS] = status
|
31
|
+
env[CONFIG] = config
|
32
|
+
env[REMOTE_ADDR] = remote_address
|
33
|
+
|
34
|
+
env[ASYNC_HEADERS] = @api.method(:on_headers) if @api.respond_to? :on_headers
|
35
|
+
env[ASYNC_BODY] = @api.method(:on_body) if @api.respond_to? :on_body
|
36
|
+
env[ASYNC_CLOSE] = @api.method(:on_close) if @api.respond_to? :on_close
|
37
|
+
|
38
|
+
r = Goliath::Request.new(@app, self, env)
|
39
|
+
r.parse_header(h, @parser)
|
40
|
+
|
41
|
+
@requests.push(r)
|
42
|
+
end
|
43
|
+
|
44
|
+
@parser.on_body = proc do |data|
|
45
|
+
@requests.first.parse(data)
|
46
|
+
end
|
47
|
+
|
48
|
+
@parser.on_message_complete = proc do
|
49
|
+
req = @requests.shift
|
50
|
+
|
51
|
+
if @current.nil?
|
52
|
+
@current = req
|
53
|
+
@current.succeed
|
54
|
+
else
|
55
|
+
@pending.push(req)
|
56
|
+
end
|
57
|
+
|
58
|
+
req.process
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def receive_data(data)
|
63
|
+
begin
|
64
|
+
@parser << data
|
65
|
+
rescue HTTP::Parser::Error => e
|
66
|
+
terminate_request(false)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def unbind
|
71
|
+
@requests.map {|r| r.close }
|
72
|
+
@pending.map {|r| r.close }
|
73
|
+
@current.close if @current
|
74
|
+
end
|
75
|
+
|
76
|
+
def terminate_request(keep_alive)
|
77
|
+
if req = @pending.shift
|
78
|
+
@current = req
|
79
|
+
@current.succeed
|
80
|
+
else
|
81
|
+
@current.close
|
82
|
+
@current = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
close_connection_after_writing rescue nil if !keep_alive
|
86
|
+
end
|
87
|
+
|
88
|
+
def remote_address
|
89
|
+
Socket.unpack_sockaddr_in(get_peername)[1]
|
90
|
+
rescue Exception
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Goliath
|
2
|
+
# Constants used by the system to access data.
|
3
|
+
module Constants
|
4
|
+
INITIAL_BODY = ''
|
5
|
+
# Force external_encoding of request's body to ASCII_8BIT
|
6
|
+
INITIAL_BODY.encode!(Encoding::ASCII_8BIT) if INITIAL_BODY.respond_to?(:encode)
|
7
|
+
|
8
|
+
SERVER_SOFTWARE = 'SERVER_SOFTWARE'
|
9
|
+
SERVER = 'Goliath'
|
10
|
+
|
11
|
+
HTTP_PREFIX = 'HTTP_'
|
12
|
+
LOCALHOST = 'localhost'
|
13
|
+
LOGGER = 'logger'
|
14
|
+
STATUS = 'status'
|
15
|
+
CONFIG = 'config'
|
16
|
+
OPTIONS = 'options'
|
17
|
+
|
18
|
+
RACK_INPUT = 'rack.input'
|
19
|
+
RACK_VERSION = 'rack.version'
|
20
|
+
RACK_ERRORS = 'rack.errors'
|
21
|
+
RACK_MULTITHREAD = 'rack.multithread'
|
22
|
+
RACK_MULTIPROCESS = 'rack.multiprocess'
|
23
|
+
RACK_RUN_ONCE = 'rack.run_once'
|
24
|
+
RACK_VERSION_NUM = [1, 0]
|
25
|
+
|
26
|
+
ASYNC_CALLBACK = 'async.callback'
|
27
|
+
ASYNC_HEADERS = 'async.headers'
|
28
|
+
ASYNC_BODY = 'async.body'
|
29
|
+
ASYNC_CLOSE = 'async.close'
|
30
|
+
|
31
|
+
STREAM_START = 'stream.start'
|
32
|
+
STREAM_SEND = 'stream.send'
|
33
|
+
STREAM_CLOSE = 'stream.close'
|
34
|
+
|
35
|
+
SERVER_NAME = 'SERVER_NAME'
|
36
|
+
SERVER_PORT = 'SERVER_PORT'
|
37
|
+
SCRIPT_NAME = 'SCRIPT_NAME'
|
38
|
+
REMOTE_ADDR = 'REMOTE_ADDR'
|
39
|
+
CONTENT_LENGTH = 'CONTENT_LENGTH'
|
40
|
+
REQUEST_METHOD = 'REQUEST_METHOD'
|
41
|
+
REQUEST_URI = 'REQUEST_URI'
|
42
|
+
QUERY_STRING = 'QUERY_STRING'
|
43
|
+
HTTP_VERSION = 'HTTP_VERSION'
|
44
|
+
REQUEST_PATH = 'REQUEST_PATH'
|
45
|
+
PATH_INFO = 'PATH_INFO'
|
46
|
+
FRAGMENT = 'FRAGMENT'
|
47
|
+
CONNECTION = 'CONNECTION'
|
48
|
+
|
49
|
+
GOLIATH_ENV = 'goliath.env'
|
50
|
+
end
|
51
|
+
end
|
data/lib/goliath/env.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'goliath/constants'
|
2
|
+
|
3
|
+
module Goliath
|
4
|
+
# Holds information for the current request.
|
5
|
+
#
|
6
|
+
# Goliath::Env also provides access to the logger, configuration information
|
7
|
+
# and anything else set into the config data during initialization.
|
8
|
+
class Env < Hash
|
9
|
+
include Constants
|
10
|
+
|
11
|
+
# Create a new Goliath::Env object
|
12
|
+
#
|
13
|
+
# @return [Goliath::Env] The Goliath::Env object
|
14
|
+
def initialize
|
15
|
+
self[SERVER_SOFTWARE] = SERVER
|
16
|
+
self[SERVER_NAME] = LOCALHOST
|
17
|
+
self[RACK_VERSION] = RACK_VERSION_NUM
|
18
|
+
self[RACK_ERRORS] = STDERR
|
19
|
+
self[RACK_MULTITHREAD] = false
|
20
|
+
self[RACK_MULTIPROCESS] = false
|
21
|
+
self[RACK_RUN_ONCE] = false
|
22
|
+
|
23
|
+
self[:start_time] = Time.now.to_f
|
24
|
+
self[:time] = Time.now.to_f
|
25
|
+
self[:trace] = []
|
26
|
+
end
|
27
|
+
|
28
|
+
# Add a trace timer with the given name into the environment. The tracer will
|
29
|
+
# provide information on the amount of time since the previous call to {#trace}
|
30
|
+
# or since the Goliath::Env object was initialized.
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# trace("initialize hash")
|
34
|
+
# ....
|
35
|
+
# trace("Do something else")
|
36
|
+
#
|
37
|
+
# @param name [String] The name of the trace to add
|
38
|
+
def trace(name)
|
39
|
+
self[:trace].push([name, "%.2f" % ((Time.now.to_f - self[:time]) * 1000)])
|
40
|
+
self[:time] = Time.now.to_f
|
41
|
+
end
|
42
|
+
|
43
|
+
# Retrieve the tracer stats for this request environment. This can then be
|
44
|
+
# returned in the headers hash to in development to provide some simple
|
45
|
+
# timing information for the various API components.
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# [200, {}, {:meta => {:trace => env.trace_stats}}, {}]
|
49
|
+
#
|
50
|
+
# @return [Array] Array of [name, time] pairs with a Total entry added.d
|
51
|
+
def trace_stats
|
52
|
+
self[:trace] + [['total', self[:trace].collect { |s| s[1].to_f }.inject(:+).to_s]]
|
53
|
+
end
|
54
|
+
|
55
|
+
# If the API is a streaming API this will send the provided data to the client.
|
56
|
+
# There will be no processing done on the data when this is called so it's the
|
57
|
+
# APIs responsibility to have the data formatted as needed.
|
58
|
+
#
|
59
|
+
# @param data [String] The data to send to the client.
|
60
|
+
def stream_send(data)
|
61
|
+
self[STREAM_SEND].call(data)
|
62
|
+
end
|
63
|
+
|
64
|
+
# If the API is a streaming API this will be executed by the API to signal that
|
65
|
+
# the stream is complete. This will close the connection with the client.
|
66
|
+
def stream_close
|
67
|
+
self[STREAM_CLOSE].call
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param name [Symbol] The method to check if we respond to it.
|
71
|
+
# @return [Boolean] True if the Env responds to the method, false otherwise
|
72
|
+
def respond_to?(name)
|
73
|
+
return true if has_key?(name.to_s)
|
74
|
+
return true if self['config'] && self['config'].has_key?(name.to_s)
|
75
|
+
super
|
76
|
+
end
|
77
|
+
|
78
|
+
# The Goliath::Env will provide any of it's keys as a method. It will also provide
|
79
|
+
# any of the keys in the config object as methods. The methods will return
|
80
|
+
# the value of the key. If the key doesn't exist in either hash this will
|
81
|
+
# fall back to the standard method_missing implementation.
|
82
|
+
#
|
83
|
+
# @param name [Symbol] The method to look for
|
84
|
+
# @param args The arguments
|
85
|
+
# @param blk A block
|
86
|
+
def method_missing(name, *args, &blk)
|
87
|
+
return self[name.to_s] if has_key?(name.to_s)
|
88
|
+
return self['config'][name.to_s] if self['config'] && self['config'].has_key?(name.to_s)
|
89
|
+
super(name, *args, &blk)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'http/parser'
|
3
|
+
require 'async_rack'
|
4
|
+
|
5
|
+
# The Goliath Framework
|
6
|
+
module Goliath
|
7
|
+
module_function
|
8
|
+
|
9
|
+
@env = 'development'
|
10
|
+
|
11
|
+
# Retrieves the current goliath environment
|
12
|
+
#
|
13
|
+
# @return [String] the current environment
|
14
|
+
def env
|
15
|
+
@env
|
16
|
+
end
|
17
|
+
|
18
|
+
# Sets the current goliath environment
|
19
|
+
#
|
20
|
+
# @param [String] env the environment string of [dev|prod|test]
|
21
|
+
def env=(env)
|
22
|
+
case(env)
|
23
|
+
when 'dev' then @env = 'development'
|
24
|
+
when 'prod' then @env = 'production'
|
25
|
+
when 'test' then @env = 'test'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Determines if we are in the production environment
|
30
|
+
#
|
31
|
+
# @return [Boolean] true if current environemnt is production, false otherwise
|
32
|
+
def prod?
|
33
|
+
@env == 'production'
|
34
|
+
end
|
35
|
+
|
36
|
+
# Determines if we are in the development environment
|
37
|
+
#
|
38
|
+
# @return [Boolean] true if current environemnt is development, false otherwise
|
39
|
+
def dev?
|
40
|
+
@env == 'development'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Determines if we are in the test environment
|
44
|
+
#
|
45
|
+
# @return [Boolean] true if current environemnt is test, false otherwise
|
46
|
+
def test?
|
47
|
+
@env == 'test'
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Goliath
|
2
|
+
# @private
|
3
|
+
class Headers
|
4
|
+
HEADER_FORMAT = "%s: %s\r\n".freeze
|
5
|
+
ALLOWED_DUPLICATES = %w(Set-Cookie Set-Cookie2 Warning WWW-Authenticate).freeze
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@sent = {}
|
9
|
+
@out = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def []=(key, value)
|
13
|
+
return if @sent.has_key?(key) && !(ALLOWED_DUPLICATES.include?(key))
|
14
|
+
|
15
|
+
value = case value
|
16
|
+
when Time then value.httpdate
|
17
|
+
when NilClass then return
|
18
|
+
else value.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
@sent[key] = value
|
22
|
+
@out << HEADER_FORMAT % [key, value]
|
23
|
+
end
|
24
|
+
|
25
|
+
def [](key)
|
26
|
+
@sent[key]
|
27
|
+
end
|
28
|
+
|
29
|
+
def has_key?(key)
|
30
|
+
@sent[key] ? true : false
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
@out.join
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Goliath
|
2
|
+
# Every standard HTTP code mapped to the appropriate message.
|
3
|
+
#
|
4
|
+
# @author Mongrel.
|
5
|
+
HTTP_STATUS_CODES = {
|
6
|
+
100 => 'Continue',
|
7
|
+
101 => 'Switching Protocols',
|
8
|
+
200 => 'OK',
|
9
|
+
201 => 'Created',
|
10
|
+
202 => 'Accepted',
|
11
|
+
203 => 'Non-Authoritative Information',
|
12
|
+
204 => 'No Content',
|
13
|
+
205 => 'Reset Content',
|
14
|
+
206 => 'Partial Content',
|
15
|
+
300 => 'Multiple Choices',
|
16
|
+
301 => 'Moved Permanently',
|
17
|
+
302 => 'Moved Temporarily',
|
18
|
+
303 => 'See Other',
|
19
|
+
304 => 'Not Modified',
|
20
|
+
305 => 'Use Proxy',
|
21
|
+
400 => 'Bad Request',
|
22
|
+
401 => 'Unauthorized',
|
23
|
+
402 => 'Payment Required',
|
24
|
+
403 => 'Forbidden',
|
25
|
+
404 => 'Not Found',
|
26
|
+
405 => 'Method Not Allowed',
|
27
|
+
406 => 'Not Acceptable',
|
28
|
+
407 => 'Proxy Authentication Required',
|
29
|
+
408 => 'Request Time-out',
|
30
|
+
409 => 'Conflict',
|
31
|
+
410 => 'Gone',
|
32
|
+
411 => 'Length Required',
|
33
|
+
412 => 'Precondition Failed',
|
34
|
+
413 => 'Request Entity Too Large',
|
35
|
+
414 => 'Request-URI Too Large',
|
36
|
+
415 => 'Unsupported Media Type',
|
37
|
+
500 => 'Internal Server Error',
|
38
|
+
501 => 'Not Implemented',
|
39
|
+
502 => 'Bad Gateway',
|
40
|
+
503 => 'Service Unavailable',
|
41
|
+
504 => 'Gateway Time-out',
|
42
|
+
505 => 'HTTP Version not supported'
|
43
|
+
}
|
44
|
+
end
|