shopify-cli 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.github/PULL_REQUEST_TEMPLATE.md +1 -0
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +9 -0
  5. data/README.md +39 -7
  6. data/Rakefile +2 -0
  7. data/dev.yml +2 -2
  8. data/docs/_config.yml +1 -18
  9. data/docs/app/node/commands/index.md +2 -80
  10. data/docs/app/node/index.md +2 -33
  11. data/docs/app/rails/commands/index.md +2 -78
  12. data/docs/app/rails/index.md +2 -34
  13. data/docs/core/index.md +2 -84
  14. data/docs/getting-started/index.md +2 -25
  15. data/docs/getting-started/install/index.md +1 -118
  16. data/docs/getting-started/migrate/index.md +2 -94
  17. data/docs/getting-started/uninstall/index.md +2 -35
  18. data/docs/getting-started/upgrade/index.md +2 -39
  19. data/docs/help/start-app/index.md +2 -4
  20. data/docs/index.md +2 -24
  21. data/install.sh +1 -1
  22. data/lib/project_types/extension/cli.rb +19 -10
  23. data/lib/project_types/extension/commands/extension_command.rb +2 -2
  24. data/lib/project_types/extension/features/argo.rb +117 -0
  25. data/lib/project_types/extension/forms/create.rb +2 -2
  26. data/lib/project_types/extension/models/specification.rb +35 -0
  27. data/lib/project_types/extension/models/specification_handlers/checkout_post_purchase.rb +19 -0
  28. data/lib/project_types/extension/models/specification_handlers/default.rb +67 -0
  29. data/lib/project_types/extension/models/specifications.rb +77 -0
  30. data/lib/project_types/extension/tasks/configure_features.rb +52 -0
  31. data/lib/project_types/extension/tasks/fetch_specifications.rb +38 -0
  32. data/lib/project_types/node/commands/create.rb +3 -1
  33. data/lib/project_types/node/commands/generate.rb +2 -11
  34. data/lib/project_types/node/messages/messages.rb +9 -44
  35. data/lib/project_types/rails/commands/create.rb +8 -9
  36. data/lib/project_types/rails/forms/create.rb +1 -1
  37. data/lib/project_types/rails/gem.rb +1 -1
  38. data/lib/project_types/rails/messages/messages.rb +1 -1
  39. data/lib/project_types/script/cli.rb +7 -4
  40. data/lib/project_types/script/commands/create.rb +6 -4
  41. data/lib/project_types/script/commands/push.rb +5 -13
  42. data/lib/project_types/script/config/extension_points.yml +9 -5
  43. data/lib/project_types/script/errors.rb +17 -0
  44. data/lib/project_types/script/forms/create.rb +26 -2
  45. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +10 -1
  46. data/lib/project_types/script/layers/application/build_script.rb +9 -4
  47. data/lib/project_types/script/layers/application/create_script.rb +12 -10
  48. data/lib/project_types/script/layers/application/extension_points.rb +24 -0
  49. data/lib/project_types/script/layers/application/push_script.rb +18 -16
  50. data/lib/project_types/script/layers/domain/errors.rb +4 -0
  51. data/lib/project_types/script/layers/domain/extension_point.rb +62 -6
  52. data/lib/project_types/script/layers/domain/metadata.rb +55 -0
  53. data/lib/project_types/script/layers/domain/push_package.rb +25 -6
  54. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +6 -6
  55. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +16 -6
  56. data/lib/project_types/script/layers/infrastructure/extension_point_repository.rb +10 -4
  57. data/lib/project_types/script/layers/infrastructure/project_creator.rb +2 -1
  58. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +25 -13
  59. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +72 -0
  60. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +59 -0
  61. data/lib/project_types/script/layers/infrastructure/script_service.rb +7 -1
  62. data/lib/project_types/script/layers/infrastructure/task_runner.rb +4 -3
  63. data/lib/project_types/script/messages/messages.rb +39 -8
  64. data/lib/project_types/script/script_project.rb +25 -16
  65. data/lib/project_types/script/ui/error_handler.rb +34 -1
  66. data/lib/project_types/theme/cli.rb +40 -0
  67. data/lib/project_types/theme/commands/connect.rb +54 -0
  68. data/lib/project_types/theme/commands/create.rb +48 -0
  69. data/lib/project_types/theme/commands/deploy.rb +38 -0
  70. data/lib/project_types/theme/commands/generate.rb +20 -0
  71. data/lib/project_types/theme/commands/generate/env.rb +79 -0
  72. data/lib/project_types/theme/commands/push.rb +55 -0
  73. data/lib/project_types/theme/commands/serve.rb +31 -0
  74. data/lib/project_types/theme/forms/connect.rb +34 -0
  75. data/lib/project_types/theme/forms/create.rb +22 -0
  76. data/lib/project_types/theme/messages/messages.rb +147 -0
  77. data/lib/project_types/theme/tasks/ensure_themekit_installed.rb +78 -0
  78. data/lib/project_types/theme/themekit.rb +113 -0
  79. data/lib/shopify-cli/admin_api.rb +42 -2
  80. data/lib/shopify-cli/api.rb +27 -24
  81. data/lib/shopify-cli/commands/system.rb +1 -1
  82. data/lib/shopify-cli/context.rb +23 -2
  83. data/lib/shopify-cli/feature.rb +0 -2
  84. data/lib/shopify-cli/http_request.rb +20 -8
  85. data/lib/shopify-cli/messages/messages.rb +6 -3
  86. data/lib/shopify-cli/method_object.rb +104 -0
  87. data/lib/shopify-cli/partners_api.rb +8 -2
  88. data/lib/shopify-cli/project_type.rb +1 -1
  89. data/lib/shopify-cli/resolve_constant.rb +25 -0
  90. data/lib/shopify-cli/result.rb +432 -0
  91. data/lib/shopify-cli/shopifolk.rb +3 -2
  92. data/lib/shopify-cli/tasks/select_org_and_shop.rb +6 -5
  93. data/lib/shopify-cli/tunnel.rb +7 -1
  94. data/lib/shopify-cli/version.rb +1 -1
  95. data/lib/shopify_cli.rb +4 -1
  96. data/shopify.fish +1 -1
  97. data/shopify.sh +1 -1
  98. data/vendor/deps/cli-kit/REVISION +1 -1
  99. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +2 -2
  100. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +3 -3
  101. data/vendor/deps/cli-ui/REVISION +1 -1
  102. data/vendor/deps/cli-ui/lib/cli/ui.rb +26 -22
  103. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +4 -6
  104. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +3 -3
  105. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +8 -9
  106. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +1 -1
  107. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +1 -0
  108. data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +15 -3
  109. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +4 -11
  110. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +3 -5
  111. data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +10 -10
  112. data/vendor/deps/cli-ui/lib/cli/ui/version.rb +1 -1
  113. data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +56 -0
  114. data/vendor/deps/webrick/.gitignore +9 -0
  115. data/vendor/deps/webrick/Gemfile +3 -0
  116. data/vendor/deps/webrick/LICENSE.txt +22 -0
  117. data/vendor/deps/webrick/README.md +61 -0
  118. data/vendor/deps/webrick/Rakefile +10 -0
  119. data/vendor/deps/webrick/lib/webrick.rb +232 -0
  120. data/vendor/deps/webrick/lib/webrick/accesslog.rb +157 -0
  121. data/vendor/deps/webrick/lib/webrick/cgi.rb +313 -0
  122. data/vendor/deps/webrick/lib/webrick/compat.rb +36 -0
  123. data/vendor/deps/webrick/lib/webrick/config.rb +158 -0
  124. data/vendor/deps/webrick/lib/webrick/cookie.rb +172 -0
  125. data/vendor/deps/webrick/lib/webrick/htmlutils.rb +30 -0
  126. data/vendor/deps/webrick/lib/webrick/httpauth.rb +96 -0
  127. data/vendor/deps/webrick/lib/webrick/httpauth/authenticator.rb +117 -0
  128. data/vendor/deps/webrick/lib/webrick/httpauth/basicauth.rb +116 -0
  129. data/vendor/deps/webrick/lib/webrick/httpauth/digestauth.rb +395 -0
  130. data/vendor/deps/webrick/lib/webrick/httpauth/htdigest.rb +132 -0
  131. data/vendor/deps/webrick/lib/webrick/httpauth/htgroup.rb +97 -0
  132. data/vendor/deps/webrick/lib/webrick/httpauth/htpasswd.rb +158 -0
  133. data/vendor/deps/webrick/lib/webrick/httpauth/userdb.rb +53 -0
  134. data/vendor/deps/webrick/lib/webrick/httpproxy.rb +354 -0
  135. data/vendor/deps/webrick/lib/webrick/httprequest.rb +636 -0
  136. data/vendor/deps/webrick/lib/webrick/httpresponse.rb +564 -0
  137. data/vendor/deps/webrick/lib/webrick/https.rb +152 -0
  138. data/vendor/deps/webrick/lib/webrick/httpserver.rb +294 -0
  139. data/vendor/deps/webrick/lib/webrick/httpservlet.rb +23 -0
  140. data/vendor/deps/webrick/lib/webrick/httpservlet/abstract.rb +152 -0
  141. data/vendor/deps/webrick/lib/webrick/httpservlet/cgi_runner.rb +47 -0
  142. data/vendor/deps/webrick/lib/webrick/httpservlet/cgihandler.rb +126 -0
  143. data/vendor/deps/webrick/lib/webrick/httpservlet/erbhandler.rb +88 -0
  144. data/vendor/deps/webrick/lib/webrick/httpservlet/filehandler.rb +552 -0
  145. data/vendor/deps/webrick/lib/webrick/httpservlet/prochandler.rb +47 -0
  146. data/vendor/deps/webrick/lib/webrick/httpstatus.rb +194 -0
  147. data/vendor/deps/webrick/lib/webrick/httputils.rb +512 -0
  148. data/vendor/deps/webrick/lib/webrick/httpversion.rb +76 -0
  149. data/vendor/deps/webrick/lib/webrick/log.rb +156 -0
  150. data/vendor/deps/webrick/lib/webrick/server.rb +381 -0
  151. data/vendor/deps/webrick/lib/webrick/ssl.rb +215 -0
  152. data/vendor/deps/webrick/lib/webrick/utils.rb +265 -0
  153. data/vendor/deps/webrick/lib/webrick/version.rb +18 -0
  154. data/vendor/deps/webrick/webrick.gemspec +74 -0
  155. metadata +70 -26
  156. data/docs/Gemfile +0 -5
  157. data/docs/Gemfile.lock +0 -258
  158. data/docs/_data/nav.yml +0 -35
  159. data/docs/_includes/footer.html +0 -15
  160. data/docs/_includes/head.html +0 -19
  161. data/docs/_includes/sidebar_nav.html +0 -22
  162. data/docs/_includes/toc.html +0 -112
  163. data/docs/_layouts/default.html +0 -79
  164. data/docs/css/docs.css +0 -157
  165. data/docs/images/header.png +0 -0
  166. data/docs/installing-ruby.md +0 -28
  167. data/lib/project_types/extension/features/argo/admin.rb +0 -20
  168. data/lib/project_types/extension/features/argo/base.rb +0 -129
  169. data/lib/project_types/extension/features/argo/checkout.rb +0 -20
  170. data/lib/project_types/extension/models/type.rb +0 -81
  171. data/lib/project_types/extension/models/types/checkout_post_purchase.rb +0 -23
  172. data/lib/project_types/extension/models/types/product_subscription.rb +0 -24
  173. data/lib/project_types/node/commands/generate/billing.rb +0 -39
  174. data/lib/project_types/node/commands/generate/page.rb +0 -59
  175. data/lib/project_types/node/commands/generate/webhook.rb +0 -37
  176. data/lib/project_types/script/layers/domain/script.rb +0 -18
  177. data/lib/project_types/script/layers/infrastructure/script_repository.rb +0 -47
  178. data/lib/project_types/script/templates/ts/as-pect.config.js +0 -27
  179. data/lib/project_types/script/templates/ts/as-pect.d.ts +0 -1
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+ #--
3
+ # HTTPVersion.rb -- presentation of HTTP version
4
+ #
5
+ # Author: IPR -- Internet Programming with Ruby -- writers
6
+ # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: httpversion.rb,v 1.5 2002/09/21 12:23:37 gotoyuzo Exp $
10
+
11
+ module WEBrick
12
+
13
+ ##
14
+ # Represents an HTTP protocol version
15
+
16
+ class HTTPVersion
17
+ include Comparable
18
+
19
+ ##
20
+ # The major protocol version number
21
+
22
+ attr_accessor :major
23
+
24
+ ##
25
+ # The minor protocol version number
26
+
27
+ attr_accessor :minor
28
+
29
+ ##
30
+ # Converts +version+ into an HTTPVersion
31
+
32
+ def self.convert(version)
33
+ version.is_a?(self) ? version : new(version)
34
+ end
35
+
36
+ ##
37
+ # Creates a new HTTPVersion from +version+.
38
+
39
+ def initialize(version)
40
+ case version
41
+ when HTTPVersion
42
+ @major, @minor = version.major, version.minor
43
+ when String
44
+ if /^(\d+)\.(\d+)$/ =~ version
45
+ @major, @minor = $1.to_i, $2.to_i
46
+ end
47
+ end
48
+ if @major.nil? || @minor.nil?
49
+ raise ArgumentError,
50
+ format("cannot convert %s into %s", version.class, self.class)
51
+ end
52
+ end
53
+
54
+ ##
55
+ # Compares this version with +other+ according to the HTTP specification
56
+ # rules.
57
+
58
+ def <=>(other)
59
+ unless other.is_a?(self.class)
60
+ other = self.class.new(other)
61
+ end
62
+ if (ret = @major <=> other.major) == 0
63
+ return @minor <=> other.minor
64
+ end
65
+ return ret
66
+ end
67
+
68
+ ##
69
+ # The HTTP version as show in the HTTP request and response. For example,
70
+ # "1.1"
71
+
72
+ def to_s
73
+ format("%d.%d", @major, @minor)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+ #--
3
+ # log.rb -- Log Class
4
+ #
5
+ # Author: IPR -- Internet Programming with Ruby -- writers
6
+ # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
7
+ # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
8
+ # reserved.
9
+ #
10
+ # $IPR: log.rb,v 1.26 2002/10/06 17:06:10 gotoyuzo Exp $
11
+
12
+ module WEBrick
13
+
14
+ ##
15
+ # A generic logging class
16
+
17
+ class BasicLog
18
+
19
+ # Fatal log level which indicates a server crash
20
+
21
+ FATAL = 1
22
+
23
+ # Error log level which indicates a recoverable error
24
+
25
+ ERROR = 2
26
+
27
+ # Warning log level which indicates a possible problem
28
+
29
+ WARN = 3
30
+
31
+ # Information log level which indicates possibly useful information
32
+
33
+ INFO = 4
34
+
35
+ # Debugging error level for messages used in server development or
36
+ # debugging
37
+
38
+ DEBUG = 5
39
+
40
+ # log-level, messages above this level will be logged
41
+ attr_accessor :level
42
+
43
+ ##
44
+ # Initializes a new logger for +log_file+ that outputs messages at +level+
45
+ # or higher. +log_file+ can be a filename, an IO-like object that
46
+ # responds to #<< or nil which outputs to $stderr.
47
+ #
48
+ # If no level is given INFO is chosen by default
49
+
50
+ def initialize(log_file=nil, level=nil)
51
+ @level = level || INFO
52
+ case log_file
53
+ when String
54
+ @log = File.open(log_file, "a+")
55
+ @log.sync = true
56
+ @opened = true
57
+ when NilClass
58
+ @log = $stderr
59
+ else
60
+ @log = log_file # requires "<<". (see BasicLog#log)
61
+ end
62
+ end
63
+
64
+ ##
65
+ # Closes the logger (also closes the log device associated to the logger)
66
+ def close
67
+ @log.close if @opened
68
+ @log = nil
69
+ end
70
+
71
+ ##
72
+ # Logs +data+ at +level+ if the given level is above the current log
73
+ # level.
74
+
75
+ def log(level, data)
76
+ if @log && level <= @level
77
+ data += "\n" if /\n\Z/ !~ data
78
+ @log << data
79
+ end
80
+ end
81
+
82
+ ##
83
+ # Synonym for log(INFO, obj.to_s)
84
+ def <<(obj)
85
+ log(INFO, obj.to_s)
86
+ end
87
+
88
+ # Shortcut for logging a FATAL message
89
+ def fatal(msg) log(FATAL, "FATAL " + format(msg)); end
90
+ # Shortcut for logging an ERROR message
91
+ def error(msg) log(ERROR, "ERROR " + format(msg)); end
92
+ # Shortcut for logging a WARN message
93
+ def warn(msg) log(WARN, "WARN " + format(msg)); end
94
+ # Shortcut for logging an INFO message
95
+ def info(msg) log(INFO, "INFO " + format(msg)); end
96
+ # Shortcut for logging a DEBUG message
97
+ def debug(msg) log(DEBUG, "DEBUG " + format(msg)); end
98
+
99
+ # Will the logger output FATAL messages?
100
+ def fatal?; @level >= FATAL; end
101
+ # Will the logger output ERROR messages?
102
+ def error?; @level >= ERROR; end
103
+ # Will the logger output WARN messages?
104
+ def warn?; @level >= WARN; end
105
+ # Will the logger output INFO messages?
106
+ def info?; @level >= INFO; end
107
+ # Will the logger output DEBUG messages?
108
+ def debug?; @level >= DEBUG; end
109
+
110
+ private
111
+
112
+ ##
113
+ # Formats +arg+ for the logger
114
+ #
115
+ # * If +arg+ is an Exception, it will format the error message and
116
+ # the back trace.
117
+ # * If +arg+ responds to #to_str, it will return it.
118
+ # * Otherwise it will return +arg+.inspect.
119
+ def format(arg)
120
+ if arg.is_a?(Exception)
121
+ +"#{arg.class}: #{AccessLog.escape(arg.message)}\n\t" <<
122
+ arg.backtrace.join("\n\t") << "\n"
123
+ elsif arg.respond_to?(:to_str)
124
+ AccessLog.escape(arg.to_str)
125
+ else
126
+ arg.inspect
127
+ end
128
+ end
129
+ end
130
+
131
+ ##
132
+ # A logging class that prepends a timestamp to each message.
133
+
134
+ class Log < BasicLog
135
+ # Format of the timestamp which is applied to each logged line. The
136
+ # default is <tt>"[%Y-%m-%d %H:%M:%S]"</tt>
137
+ attr_accessor :time_format
138
+
139
+ ##
140
+ # Same as BasicLog#initialize
141
+ #
142
+ # You can set the timestamp format through #time_format
143
+ def initialize(log_file=nil, level=nil)
144
+ super(log_file, level)
145
+ @time_format = "[%Y-%m-%d %H:%M:%S]"
146
+ end
147
+
148
+ ##
149
+ # Same as BasicLog#log
150
+ def log(level, data)
151
+ tmp = Time.now.strftime(@time_format)
152
+ tmp << " " << data
153
+ super(level, tmp)
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,381 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # server.rb -- GenericServer Class
4
+ #
5
+ # Author: IPR -- Internet Programming with Ruby -- writers
6
+ # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
7
+ # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
8
+ # reserved.
9
+ #
10
+ # $IPR: server.rb,v 1.62 2003/07/22 19:20:43 gotoyuzo Exp $
11
+
12
+ require 'socket'
13
+ require_relative 'config'
14
+ require_relative 'log'
15
+
16
+ module WEBrick
17
+
18
+ ##
19
+ # Server error exception
20
+
21
+ class ServerError < StandardError; end
22
+
23
+ ##
24
+ # Base server class
25
+
26
+ class SimpleServer
27
+
28
+ ##
29
+ # A SimpleServer only yields when you start it
30
+
31
+ def SimpleServer.start
32
+ yield
33
+ end
34
+ end
35
+
36
+ ##
37
+ # A generic module for daemonizing a process
38
+
39
+ class Daemon
40
+
41
+ ##
42
+ # Performs the standard operations for daemonizing a process. Runs a
43
+ # block, if given.
44
+
45
+ def Daemon.start
46
+ Process.daemon
47
+ File.umask(0)
48
+ yield if block_given?
49
+ end
50
+ end
51
+
52
+ ##
53
+ # Base TCP server class. You must subclass GenericServer and provide a #run
54
+ # method.
55
+
56
+ class GenericServer
57
+
58
+ ##
59
+ # The server status. One of :Stop, :Running or :Shutdown
60
+
61
+ attr_reader :status
62
+
63
+ ##
64
+ # The server configuration
65
+
66
+ attr_reader :config
67
+
68
+ ##
69
+ # The server logger. This is independent from the HTTP access log.
70
+
71
+ attr_reader :logger
72
+
73
+ ##
74
+ # Tokens control the number of outstanding clients. The
75
+ # <code>:MaxClients</code> configuration sets this.
76
+
77
+ attr_reader :tokens
78
+
79
+ ##
80
+ # Sockets listening for connections.
81
+
82
+ attr_reader :listeners
83
+
84
+ ##
85
+ # Creates a new generic server from +config+. The default configuration
86
+ # comes from +default+.
87
+
88
+ def initialize(config={}, default=Config::General)
89
+ @config = default.dup.update(config)
90
+ @status = :Stop
91
+ @config[:Logger] ||= Log::new
92
+ @logger = @config[:Logger]
93
+
94
+ @tokens = Thread::SizedQueue.new(@config[:MaxClients])
95
+ @config[:MaxClients].times{ @tokens.push(nil) }
96
+
97
+ webrickv = WEBrick::VERSION
98
+ rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
99
+ @logger.info("WEBrick #{webrickv}")
100
+ @logger.info("ruby #{rubyv}")
101
+
102
+ @listeners = []
103
+ @shutdown_pipe = nil
104
+ unless @config[:DoNotListen]
105
+ raise ArgumentError, "Port must an integer" unless @config[:Port].to_s == @config[:Port].to_i.to_s
106
+
107
+ @config[:Port] = @config[:Port].to_i
108
+ if @config[:Listen]
109
+ warn(":Listen option is deprecated; use GenericServer#listen", uplevel: 1)
110
+ end
111
+ listen(@config[:BindAddress], @config[:Port])
112
+ if @config[:Port] == 0
113
+ @config[:Port] = @listeners[0].addr[1]
114
+ end
115
+ end
116
+ end
117
+
118
+ ##
119
+ # Retrieves +key+ from the configuration
120
+
121
+ def [](key)
122
+ @config[key]
123
+ end
124
+
125
+ ##
126
+ # Adds listeners from +address+ and +port+ to the server. See
127
+ # WEBrick::Utils::create_listeners for details.
128
+
129
+ def listen(address, port)
130
+ @listeners += Utils::create_listeners(address, port)
131
+ end
132
+
133
+ ##
134
+ # Starts the server and runs the +block+ for each connection. This method
135
+ # does not return until the server is stopped from a signal handler or
136
+ # another thread using #stop or #shutdown.
137
+ #
138
+ # If the block raises a subclass of StandardError the exception is logged
139
+ # and ignored. If an IOError or Errno::EBADF exception is raised the
140
+ # exception is ignored. If an Exception subclass is raised the exception
141
+ # is logged and re-raised which stops the server.
142
+ #
143
+ # To completely shut down a server call #shutdown from ensure:
144
+ #
145
+ # server = WEBrick::GenericServer.new
146
+ # # or WEBrick::HTTPServer.new
147
+ #
148
+ # begin
149
+ # server.start
150
+ # ensure
151
+ # server.shutdown
152
+ # end
153
+
154
+ def start(&block)
155
+ raise ServerError, "already started." if @status != :Stop
156
+ server_type = @config[:ServerType] || SimpleServer
157
+
158
+ setup_shutdown_pipe
159
+
160
+ server_type.start{
161
+ @logger.info \
162
+ "#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
163
+ @status = :Running
164
+ call_callback(:StartCallback)
165
+
166
+ shutdown_pipe = @shutdown_pipe
167
+
168
+ thgroup = ThreadGroup.new
169
+ begin
170
+ while @status == :Running
171
+ begin
172
+ sp = shutdown_pipe[0]
173
+ if svrs = IO.select([sp, *@listeners])
174
+ if svrs[0].include? sp
175
+ # swallow shutdown pipe
176
+ buf = String.new
177
+ nil while String ===
178
+ sp.read_nonblock([sp.nread, 8].max, buf, exception: false)
179
+ break
180
+ end
181
+ svrs[0].each{|svr|
182
+ @tokens.pop # blocks while no token is there.
183
+ if sock = accept_client(svr)
184
+ unless config[:DoNotReverseLookup].nil?
185
+ sock.do_not_reverse_lookup = !!config[:DoNotReverseLookup]
186
+ end
187
+ th = start_thread(sock, &block)
188
+ th[:WEBrickThread] = true
189
+ thgroup.add(th)
190
+ else
191
+ @tokens.push(nil)
192
+ end
193
+ }
194
+ end
195
+ rescue Errno::EBADF, Errno::ENOTSOCK, IOError => ex
196
+ # if the listening socket was closed in GenericServer#shutdown,
197
+ # IO::select raise it.
198
+ rescue StandardError => ex
199
+ msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
200
+ @logger.error msg
201
+ rescue Exception => ex
202
+ @logger.fatal ex
203
+ raise
204
+ end
205
+ end
206
+ ensure
207
+ cleanup_shutdown_pipe(shutdown_pipe)
208
+ cleanup_listener
209
+ @status = :Shutdown
210
+ @logger.info "going to shutdown ..."
211
+ thgroup.list.each{|th| th.join if th[:WEBrickThread] }
212
+ call_callback(:StopCallback)
213
+ @logger.info "#{self.class}#start done."
214
+ @status = :Stop
215
+ end
216
+ }
217
+ end
218
+
219
+ ##
220
+ # Stops the server from accepting new connections.
221
+
222
+ def stop
223
+ if @status == :Running
224
+ @status = :Shutdown
225
+ end
226
+
227
+ alarm_shutdown_pipe {|f| f.write_nonblock("\0")}
228
+ end
229
+
230
+ ##
231
+ # Shuts down the server and all listening sockets. New listeners must be
232
+ # provided to restart the server.
233
+
234
+ def shutdown
235
+ stop
236
+
237
+ alarm_shutdown_pipe(&:close)
238
+ end
239
+
240
+ ##
241
+ # You must subclass GenericServer and implement \#run which accepts a TCP
242
+ # client socket
243
+
244
+ def run(sock)
245
+ @logger.fatal "run() must be provided by user."
246
+ end
247
+
248
+ private
249
+
250
+ # :stopdoc:
251
+
252
+ ##
253
+ # Accepts a TCP client socket from the TCP server socket +svr+ and returns
254
+ # the client socket.
255
+
256
+ def accept_client(svr)
257
+ case sock = svr.to_io.accept_nonblock(exception: false)
258
+ when :wait_readable
259
+ nil
260
+ else
261
+ if svr.respond_to?(:start_immediately)
262
+ sock = OpenSSL::SSL::SSLSocket.new(sock, ssl_context)
263
+ sock.sync_close = true
264
+ # we cannot do OpenSSL::SSL::SSLSocket#accept here because
265
+ # a slow client can prevent us from accepting connections
266
+ # from other clients
267
+ end
268
+ sock
269
+ end
270
+ rescue Errno::ECONNRESET, Errno::ECONNABORTED,
271
+ Errno::EPROTO, Errno::EINVAL
272
+ nil
273
+ rescue StandardError => ex
274
+ msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
275
+ @logger.error msg
276
+ nil
277
+ end
278
+
279
+ ##
280
+ # Starts a server thread for the client socket +sock+ that runs the given
281
+ # +block+.
282
+ #
283
+ # Sets the socket to the <code>:WEBrickSocket</code> thread local variable
284
+ # in the thread.
285
+ #
286
+ # If any errors occur in the block they are logged and handled.
287
+
288
+ def start_thread(sock, &block)
289
+ Thread.start{
290
+ begin
291
+ Thread.current[:WEBrickSocket] = sock
292
+ begin
293
+ addr = sock.peeraddr
294
+ @logger.debug "accept: #{addr[3]}:#{addr[1]}"
295
+ rescue SocketError
296
+ @logger.debug "accept: <address unknown>"
297
+ raise
298
+ end
299
+ if sock.respond_to?(:sync_close=) && @config[:SSLStartImmediately]
300
+ WEBrick::Utils.timeout(@config[:RequestTimeout]) do
301
+ begin
302
+ sock.accept # OpenSSL::SSL::SSLSocket#accept
303
+ rescue Errno::ECONNRESET, Errno::ECONNABORTED,
304
+ Errno::EPROTO, Errno::EINVAL
305
+ Thread.exit
306
+ end
307
+ end
308
+ end
309
+ call_callback(:AcceptCallback, sock)
310
+ block ? block.call(sock) : run(sock)
311
+ rescue Errno::ENOTCONN
312
+ @logger.debug "Errno::ENOTCONN raised"
313
+ rescue ServerError => ex
314
+ msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
315
+ @logger.error msg
316
+ rescue Exception => ex
317
+ @logger.error ex
318
+ ensure
319
+ @tokens.push(nil)
320
+ Thread.current[:WEBrickSocket] = nil
321
+ if addr
322
+ @logger.debug "close: #{addr[3]}:#{addr[1]}"
323
+ else
324
+ @logger.debug "close: <address unknown>"
325
+ end
326
+ sock.close
327
+ end
328
+ }
329
+ end
330
+
331
+ ##
332
+ # Calls the callback +callback_name+ from the configuration with +args+
333
+
334
+ def call_callback(callback_name, *args)
335
+ @config[callback_name]&.call(*args)
336
+ end
337
+
338
+ def setup_shutdown_pipe
339
+ return @shutdown_pipe ||= IO.pipe
340
+ end
341
+
342
+ def cleanup_shutdown_pipe(shutdown_pipe)
343
+ @shutdown_pipe = nil
344
+ shutdown_pipe&.each(&:close)
345
+ end
346
+
347
+ def alarm_shutdown_pipe
348
+ _, pipe = @shutdown_pipe # another thread may modify @shutdown_pipe.
349
+ if pipe
350
+ if !pipe.closed?
351
+ begin
352
+ yield pipe
353
+ rescue IOError # closed by another thread.
354
+ end
355
+ end
356
+ end
357
+ end
358
+
359
+ def cleanup_listener
360
+ @listeners.each{|s|
361
+ if @logger.debug?
362
+ addr = s.addr
363
+ @logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
364
+ end
365
+ begin
366
+ s.shutdown
367
+ rescue Errno::ENOTCONN
368
+ # when `Errno::ENOTCONN: Socket is not connected' on some platforms,
369
+ # call #close instead of #shutdown.
370
+ # (ignore @config[:ShutdownSocketWithoutClose])
371
+ s.close
372
+ else
373
+ unless @config[:ShutdownSocketWithoutClose]
374
+ s.close
375
+ end
376
+ end
377
+ }
378
+ @listeners.clear
379
+ end
380
+ end # end of GenericServer
381
+ end