shopify-cli 1.5.0 → 1.6.0
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.
- checksums.yaml +4 -4
- data/.github/PULL_REQUEST_TEMPLATE.md +1 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.md +9 -0
- data/README.md +39 -7
- data/Rakefile +2 -0
- data/dev.yml +2 -2
- data/docs/_config.yml +1 -18
- data/docs/app/node/commands/index.md +2 -80
- data/docs/app/node/index.md +2 -33
- data/docs/app/rails/commands/index.md +2 -78
- data/docs/app/rails/index.md +2 -34
- data/docs/core/index.md +2 -84
- data/docs/getting-started/index.md +2 -25
- data/docs/getting-started/install/index.md +1 -118
- data/docs/getting-started/migrate/index.md +2 -94
- data/docs/getting-started/uninstall/index.md +2 -35
- data/docs/getting-started/upgrade/index.md +2 -39
- data/docs/help/start-app/index.md +2 -4
- data/docs/index.md +2 -24
- data/install.sh +1 -1
- data/lib/project_types/extension/cli.rb +19 -10
- data/lib/project_types/extension/commands/extension_command.rb +2 -2
- data/lib/project_types/extension/features/argo.rb +117 -0
- data/lib/project_types/extension/forms/create.rb +2 -2
- data/lib/project_types/extension/models/specification.rb +35 -0
- data/lib/project_types/extension/models/specification_handlers/checkout_post_purchase.rb +19 -0
- data/lib/project_types/extension/models/specification_handlers/default.rb +67 -0
- data/lib/project_types/extension/models/specifications.rb +77 -0
- data/lib/project_types/extension/tasks/configure_features.rb +52 -0
- data/lib/project_types/extension/tasks/fetch_specifications.rb +38 -0
- data/lib/project_types/node/commands/create.rb +3 -1
- data/lib/project_types/node/commands/generate.rb +2 -11
- data/lib/project_types/node/messages/messages.rb +9 -44
- data/lib/project_types/rails/commands/create.rb +8 -9
- data/lib/project_types/rails/forms/create.rb +1 -1
- data/lib/project_types/rails/gem.rb +1 -1
- data/lib/project_types/rails/messages/messages.rb +1 -1
- data/lib/project_types/script/cli.rb +7 -4
- data/lib/project_types/script/commands/create.rb +6 -4
- data/lib/project_types/script/commands/push.rb +5 -13
- data/lib/project_types/script/config/extension_points.yml +9 -5
- data/lib/project_types/script/errors.rb +17 -0
- data/lib/project_types/script/forms/create.rb +26 -2
- data/lib/project_types/script/graphql/app_script_update_or_create.graphql +10 -1
- data/lib/project_types/script/layers/application/build_script.rb +9 -4
- data/lib/project_types/script/layers/application/create_script.rb +12 -10
- data/lib/project_types/script/layers/application/extension_points.rb +24 -0
- data/lib/project_types/script/layers/application/push_script.rb +18 -16
- data/lib/project_types/script/layers/domain/errors.rb +4 -0
- data/lib/project_types/script/layers/domain/extension_point.rb +62 -6
- data/lib/project_types/script/layers/domain/metadata.rb +55 -0
- data/lib/project_types/script/layers/domain/push_package.rb +25 -6
- data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +6 -6
- data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +16 -6
- data/lib/project_types/script/layers/infrastructure/extension_point_repository.rb +10 -4
- data/lib/project_types/script/layers/infrastructure/project_creator.rb +2 -1
- data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +25 -13
- data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +72 -0
- data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +59 -0
- data/lib/project_types/script/layers/infrastructure/script_service.rb +7 -1
- data/lib/project_types/script/layers/infrastructure/task_runner.rb +4 -3
- data/lib/project_types/script/messages/messages.rb +39 -8
- data/lib/project_types/script/script_project.rb +25 -16
- data/lib/project_types/script/ui/error_handler.rb +34 -1
- data/lib/project_types/theme/cli.rb +40 -0
- data/lib/project_types/theme/commands/connect.rb +54 -0
- data/lib/project_types/theme/commands/create.rb +48 -0
- data/lib/project_types/theme/commands/deploy.rb +38 -0
- data/lib/project_types/theme/commands/generate.rb +20 -0
- data/lib/project_types/theme/commands/generate/env.rb +79 -0
- data/lib/project_types/theme/commands/push.rb +55 -0
- data/lib/project_types/theme/commands/serve.rb +31 -0
- data/lib/project_types/theme/forms/connect.rb +34 -0
- data/lib/project_types/theme/forms/create.rb +22 -0
- data/lib/project_types/theme/messages/messages.rb +147 -0
- data/lib/project_types/theme/tasks/ensure_themekit_installed.rb +78 -0
- data/lib/project_types/theme/themekit.rb +113 -0
- data/lib/shopify-cli/admin_api.rb +42 -2
- data/lib/shopify-cli/api.rb +27 -24
- data/lib/shopify-cli/commands/system.rb +1 -1
- data/lib/shopify-cli/context.rb +23 -2
- data/lib/shopify-cli/feature.rb +0 -2
- data/lib/shopify-cli/http_request.rb +20 -8
- data/lib/shopify-cli/messages/messages.rb +6 -3
- data/lib/shopify-cli/method_object.rb +104 -0
- data/lib/shopify-cli/partners_api.rb +8 -2
- data/lib/shopify-cli/project_type.rb +1 -1
- data/lib/shopify-cli/resolve_constant.rb +25 -0
- data/lib/shopify-cli/result.rb +432 -0
- data/lib/shopify-cli/shopifolk.rb +3 -2
- data/lib/shopify-cli/tasks/select_org_and_shop.rb +6 -5
- data/lib/shopify-cli/tunnel.rb +7 -1
- data/lib/shopify-cli/version.rb +1 -1
- data/lib/shopify_cli.rb +4 -1
- data/shopify.fish +1 -1
- data/shopify.sh +1 -1
- data/vendor/deps/cli-kit/REVISION +1 -1
- data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +2 -2
- data/vendor/deps/cli-kit/lib/cli/kit/system.rb +3 -3
- data/vendor/deps/cli-ui/REVISION +1 -1
- data/vendor/deps/cli-ui/lib/cli/ui.rb +26 -22
- data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +4 -6
- data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +3 -3
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +8 -9
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +1 -1
- data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +1 -0
- data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +15 -3
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +4 -11
- data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +3 -5
- data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +10 -10
- data/vendor/deps/cli-ui/lib/cli/ui/version.rb +1 -1
- data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +56 -0
- data/vendor/deps/webrick/.gitignore +9 -0
- data/vendor/deps/webrick/Gemfile +3 -0
- data/vendor/deps/webrick/LICENSE.txt +22 -0
- data/vendor/deps/webrick/README.md +61 -0
- data/vendor/deps/webrick/Rakefile +10 -0
- data/vendor/deps/webrick/lib/webrick.rb +232 -0
- data/vendor/deps/webrick/lib/webrick/accesslog.rb +157 -0
- data/vendor/deps/webrick/lib/webrick/cgi.rb +313 -0
- data/vendor/deps/webrick/lib/webrick/compat.rb +36 -0
- data/vendor/deps/webrick/lib/webrick/config.rb +158 -0
- data/vendor/deps/webrick/lib/webrick/cookie.rb +172 -0
- data/vendor/deps/webrick/lib/webrick/htmlutils.rb +30 -0
- data/vendor/deps/webrick/lib/webrick/httpauth.rb +96 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/authenticator.rb +117 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/basicauth.rb +116 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/digestauth.rb +395 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/htdigest.rb +132 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/htgroup.rb +97 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/htpasswd.rb +158 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/userdb.rb +53 -0
- data/vendor/deps/webrick/lib/webrick/httpproxy.rb +354 -0
- data/vendor/deps/webrick/lib/webrick/httprequest.rb +636 -0
- data/vendor/deps/webrick/lib/webrick/httpresponse.rb +564 -0
- data/vendor/deps/webrick/lib/webrick/https.rb +152 -0
- data/vendor/deps/webrick/lib/webrick/httpserver.rb +294 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet.rb +23 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/abstract.rb +152 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/cgi_runner.rb +47 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/cgihandler.rb +126 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/erbhandler.rb +88 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/filehandler.rb +552 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/prochandler.rb +47 -0
- data/vendor/deps/webrick/lib/webrick/httpstatus.rb +194 -0
- data/vendor/deps/webrick/lib/webrick/httputils.rb +512 -0
- data/vendor/deps/webrick/lib/webrick/httpversion.rb +76 -0
- data/vendor/deps/webrick/lib/webrick/log.rb +156 -0
- data/vendor/deps/webrick/lib/webrick/server.rb +381 -0
- data/vendor/deps/webrick/lib/webrick/ssl.rb +215 -0
- data/vendor/deps/webrick/lib/webrick/utils.rb +265 -0
- data/vendor/deps/webrick/lib/webrick/version.rb +18 -0
- data/vendor/deps/webrick/webrick.gemspec +74 -0
- metadata +70 -26
- data/docs/Gemfile +0 -5
- data/docs/Gemfile.lock +0 -258
- data/docs/_data/nav.yml +0 -35
- data/docs/_includes/footer.html +0 -15
- data/docs/_includes/head.html +0 -19
- data/docs/_includes/sidebar_nav.html +0 -22
- data/docs/_includes/toc.html +0 -112
- data/docs/_layouts/default.html +0 -79
- data/docs/css/docs.css +0 -157
- data/docs/images/header.png +0 -0
- data/docs/installing-ruby.md +0 -28
- data/lib/project_types/extension/features/argo/admin.rb +0 -20
- data/lib/project_types/extension/features/argo/base.rb +0 -129
- data/lib/project_types/extension/features/argo/checkout.rb +0 -20
- data/lib/project_types/extension/models/type.rb +0 -81
- data/lib/project_types/extension/models/types/checkout_post_purchase.rb +0 -23
- data/lib/project_types/extension/models/types/product_subscription.rb +0 -24
- data/lib/project_types/node/commands/generate/billing.rb +0 -39
- data/lib/project_types/node/commands/generate/page.rb +0 -59
- data/lib/project_types/node/commands/generate/webhook.rb +0 -37
- data/lib/project_types/script/layers/domain/script.rb +0 -18
- data/lib/project_types/script/layers/infrastructure/script_repository.rb +0 -47
- data/lib/project_types/script/templates/ts/as-pect.config.js +0 -27
- data/lib/project_types/script/templates/ts/as-pect.d.ts +0 -1
@@ -0,0 +1,564 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# httpresponse.rb -- HTTPResponse 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: httpresponse.rb,v 1.45 2003/07/11 11:02:25 gotoyuzo Exp $
|
11
|
+
|
12
|
+
require 'time'
|
13
|
+
require 'uri'
|
14
|
+
require_relative 'httpversion'
|
15
|
+
require_relative 'htmlutils'
|
16
|
+
require_relative 'httputils'
|
17
|
+
require_relative 'httpstatus'
|
18
|
+
|
19
|
+
module WEBrick
|
20
|
+
##
|
21
|
+
# An HTTP response. This is filled in by the service or do_* methods of a
|
22
|
+
# WEBrick HTTP Servlet.
|
23
|
+
|
24
|
+
class HTTPResponse
|
25
|
+
class InvalidHeader < StandardError
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# HTTP Response version
|
30
|
+
|
31
|
+
attr_reader :http_version
|
32
|
+
|
33
|
+
##
|
34
|
+
# Response status code (200)
|
35
|
+
|
36
|
+
attr_reader :status
|
37
|
+
|
38
|
+
##
|
39
|
+
# Response header
|
40
|
+
|
41
|
+
attr_reader :header
|
42
|
+
|
43
|
+
##
|
44
|
+
# Response cookies
|
45
|
+
|
46
|
+
attr_reader :cookies
|
47
|
+
|
48
|
+
##
|
49
|
+
# Response reason phrase ("OK")
|
50
|
+
|
51
|
+
attr_accessor :reason_phrase
|
52
|
+
|
53
|
+
##
|
54
|
+
# Body may be:
|
55
|
+
# * a String;
|
56
|
+
# * an IO-like object that responds to +#read+ and +#readpartial+;
|
57
|
+
# * a Proc-like object that responds to +#call+.
|
58
|
+
#
|
59
|
+
# In the latter case, either #chunked= should be set to +true+,
|
60
|
+
# or <code>header['content-length']</code> explicitly provided.
|
61
|
+
# Example:
|
62
|
+
#
|
63
|
+
# server.mount_proc '/' do |req, res|
|
64
|
+
# res.chunked = true
|
65
|
+
# # or
|
66
|
+
# # res.header['content-length'] = 10
|
67
|
+
# res.body = proc { |out| out.write(Time.now.to_s) }
|
68
|
+
# end
|
69
|
+
|
70
|
+
attr_accessor :body
|
71
|
+
|
72
|
+
##
|
73
|
+
# Request method for this response
|
74
|
+
|
75
|
+
attr_accessor :request_method
|
76
|
+
|
77
|
+
##
|
78
|
+
# Request URI for this response
|
79
|
+
|
80
|
+
attr_accessor :request_uri
|
81
|
+
|
82
|
+
##
|
83
|
+
# Request HTTP version for this response
|
84
|
+
|
85
|
+
attr_accessor :request_http_version
|
86
|
+
|
87
|
+
##
|
88
|
+
# Filename of the static file in this response. Only used by the
|
89
|
+
# FileHandler servlet.
|
90
|
+
|
91
|
+
attr_accessor :filename
|
92
|
+
|
93
|
+
##
|
94
|
+
# Is this a keep-alive response?
|
95
|
+
|
96
|
+
attr_accessor :keep_alive
|
97
|
+
|
98
|
+
##
|
99
|
+
# Configuration for this response
|
100
|
+
|
101
|
+
attr_reader :config
|
102
|
+
|
103
|
+
##
|
104
|
+
# Bytes sent in this response
|
105
|
+
|
106
|
+
attr_reader :sent_size
|
107
|
+
|
108
|
+
##
|
109
|
+
# Creates a new HTTP response object. WEBrick::Config::HTTP is the
|
110
|
+
# default configuration.
|
111
|
+
|
112
|
+
def initialize(config)
|
113
|
+
@config = config
|
114
|
+
@buffer_size = config[:OutputBufferSize]
|
115
|
+
@logger = config[:Logger]
|
116
|
+
@header = Hash.new
|
117
|
+
@status = HTTPStatus::RC_OK
|
118
|
+
@reason_phrase = nil
|
119
|
+
@http_version = HTTPVersion::convert(@config[:HTTPVersion])
|
120
|
+
@body = ''
|
121
|
+
@keep_alive = true
|
122
|
+
@cookies = []
|
123
|
+
@request_method = nil
|
124
|
+
@request_uri = nil
|
125
|
+
@request_http_version = @http_version # temporary
|
126
|
+
@chunked = false
|
127
|
+
@filename = nil
|
128
|
+
@sent_size = 0
|
129
|
+
@bodytempfile = nil
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# The response's HTTP status line
|
134
|
+
|
135
|
+
def status_line
|
136
|
+
"HTTP/#@http_version #@status #@reason_phrase".rstrip << CRLF
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# Sets the response's status to the +status+ code
|
141
|
+
|
142
|
+
def status=(status)
|
143
|
+
@status = status
|
144
|
+
@reason_phrase = HTTPStatus::reason_phrase(status)
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Retrieves the response header +field+
|
149
|
+
|
150
|
+
def [](field)
|
151
|
+
@header[field.downcase]
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Sets the response header +field+ to +value+
|
156
|
+
|
157
|
+
def []=(field, value)
|
158
|
+
@chunked = value.to_s.downcase == 'chunked' if field.downcase == 'transfer-encoding'
|
159
|
+
@header[field.downcase] = value.to_s
|
160
|
+
end
|
161
|
+
|
162
|
+
##
|
163
|
+
# The content-length header
|
164
|
+
|
165
|
+
def content_length
|
166
|
+
if len = self['content-length']
|
167
|
+
return Integer(len)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
##
|
172
|
+
# Sets the content-length header to +len+
|
173
|
+
|
174
|
+
def content_length=(len)
|
175
|
+
self['content-length'] = len.to_s
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# The content-type header
|
180
|
+
|
181
|
+
def content_type
|
182
|
+
self['content-type']
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Sets the content-type header to +type+
|
187
|
+
|
188
|
+
def content_type=(type)
|
189
|
+
self['content-type'] = type
|
190
|
+
end
|
191
|
+
|
192
|
+
##
|
193
|
+
# Iterates over each header in the response
|
194
|
+
|
195
|
+
def each
|
196
|
+
@header.each{|field, value| yield(field, value) }
|
197
|
+
end
|
198
|
+
|
199
|
+
##
|
200
|
+
# Will this response body be returned using chunked transfer-encoding?
|
201
|
+
|
202
|
+
def chunked?
|
203
|
+
@chunked
|
204
|
+
end
|
205
|
+
|
206
|
+
##
|
207
|
+
# Enables chunked transfer encoding.
|
208
|
+
|
209
|
+
def chunked=(val)
|
210
|
+
@chunked = val ? true : false
|
211
|
+
end
|
212
|
+
|
213
|
+
##
|
214
|
+
# Will this response's connection be kept alive?
|
215
|
+
|
216
|
+
def keep_alive?
|
217
|
+
@keep_alive
|
218
|
+
end
|
219
|
+
|
220
|
+
##
|
221
|
+
# Sends the response on +socket+
|
222
|
+
|
223
|
+
def send_response(socket) # :nodoc:
|
224
|
+
begin
|
225
|
+
setup_header()
|
226
|
+
send_header(socket)
|
227
|
+
send_body(socket)
|
228
|
+
rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN => ex
|
229
|
+
@logger.debug(ex)
|
230
|
+
@keep_alive = false
|
231
|
+
rescue Exception => ex
|
232
|
+
@logger.error(ex)
|
233
|
+
@keep_alive = false
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
##
|
238
|
+
# Sets up the headers for sending
|
239
|
+
|
240
|
+
def setup_header() # :nodoc:
|
241
|
+
@reason_phrase ||= HTTPStatus::reason_phrase(@status)
|
242
|
+
@header['server'] ||= @config[:ServerSoftware]
|
243
|
+
@header['date'] ||= Time.now.httpdate
|
244
|
+
|
245
|
+
# HTTP/0.9 features
|
246
|
+
if @request_http_version < "1.0"
|
247
|
+
@http_version = HTTPVersion.new("0.9")
|
248
|
+
@keep_alive = false
|
249
|
+
end
|
250
|
+
|
251
|
+
# HTTP/1.0 features
|
252
|
+
if @request_http_version < "1.1"
|
253
|
+
if chunked?
|
254
|
+
@chunked = false
|
255
|
+
ver = @request_http_version.to_s
|
256
|
+
msg = "chunked is set for an HTTP/#{ver} request. (ignored)"
|
257
|
+
@logger.warn(msg)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# Determine the message length (RFC2616 -- 4.4 Message Length)
|
262
|
+
if @status == 304 || @status == 204 || HTTPStatus::info?(@status)
|
263
|
+
@header.delete('content-length')
|
264
|
+
@body = ""
|
265
|
+
elsif chunked?
|
266
|
+
@header["transfer-encoding"] = "chunked"
|
267
|
+
@header.delete('content-length')
|
268
|
+
elsif %r{^multipart/byteranges} =~ @header['content-type']
|
269
|
+
@header.delete('content-length')
|
270
|
+
elsif @header['content-length'].nil?
|
271
|
+
if @body.respond_to? :readpartial
|
272
|
+
elsif @body.respond_to? :call
|
273
|
+
make_body_tempfile
|
274
|
+
else
|
275
|
+
@header['content-length'] = (@body ? @body.bytesize : 0).to_s
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Keep-Alive connection.
|
280
|
+
if @header['connection'] == "close"
|
281
|
+
@keep_alive = false
|
282
|
+
elsif keep_alive?
|
283
|
+
if chunked? || @header['content-length'] || @status == 304 || @status == 204 || HTTPStatus.info?(@status)
|
284
|
+
@header['connection'] = "Keep-Alive"
|
285
|
+
else
|
286
|
+
msg = "Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true"
|
287
|
+
@logger.warn(msg)
|
288
|
+
@header['connection'] = "close"
|
289
|
+
@keep_alive = false
|
290
|
+
end
|
291
|
+
else
|
292
|
+
@header['connection'] = "close"
|
293
|
+
end
|
294
|
+
|
295
|
+
# Location is a single absoluteURI.
|
296
|
+
if location = @header['location']
|
297
|
+
if @request_uri
|
298
|
+
@header['location'] = @request_uri.merge(location).to_s
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def make_body_tempfile # :nodoc:
|
304
|
+
return if @bodytempfile
|
305
|
+
bodytempfile = Tempfile.create("webrick")
|
306
|
+
if @body.nil?
|
307
|
+
# nothing
|
308
|
+
elsif @body.respond_to? :readpartial
|
309
|
+
IO.copy_stream(@body, bodytempfile)
|
310
|
+
@body.close
|
311
|
+
elsif @body.respond_to? :call
|
312
|
+
@body.call(bodytempfile)
|
313
|
+
else
|
314
|
+
bodytempfile.write @body
|
315
|
+
end
|
316
|
+
bodytempfile.rewind
|
317
|
+
@body = @bodytempfile = bodytempfile
|
318
|
+
@header['content-length'] = bodytempfile.stat.size.to_s
|
319
|
+
end
|
320
|
+
|
321
|
+
def remove_body_tempfile # :nodoc:
|
322
|
+
if @bodytempfile
|
323
|
+
@bodytempfile.close
|
324
|
+
File.unlink @bodytempfile.path
|
325
|
+
@bodytempfile = nil
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
##
|
331
|
+
# Sends the headers on +socket+
|
332
|
+
|
333
|
+
def send_header(socket) # :nodoc:
|
334
|
+
if @http_version.major > 0
|
335
|
+
data = status_line().dup
|
336
|
+
@header.each{|key, value|
|
337
|
+
tmp = key.gsub(/\bwww|^te$|\b\w/){ $&.upcase }
|
338
|
+
data << "#{tmp}: #{check_header(value)}" << CRLF
|
339
|
+
}
|
340
|
+
@cookies.each{|cookie|
|
341
|
+
data << "Set-Cookie: " << check_header(cookie.to_s) << CRLF
|
342
|
+
}
|
343
|
+
data << CRLF
|
344
|
+
socket.write(data)
|
345
|
+
end
|
346
|
+
rescue InvalidHeader => e
|
347
|
+
@header.clear
|
348
|
+
@cookies.clear
|
349
|
+
set_error e
|
350
|
+
retry
|
351
|
+
end
|
352
|
+
|
353
|
+
##
|
354
|
+
# Sends the body on +socket+
|
355
|
+
|
356
|
+
def send_body(socket) # :nodoc:
|
357
|
+
if @body.respond_to? :readpartial then
|
358
|
+
send_body_io(socket)
|
359
|
+
elsif @body.respond_to?(:call) then
|
360
|
+
send_body_proc(socket)
|
361
|
+
else
|
362
|
+
send_body_string(socket)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
##
|
367
|
+
# Redirects to +url+ with a WEBrick::HTTPStatus::Redirect +status+.
|
368
|
+
#
|
369
|
+
# Example:
|
370
|
+
#
|
371
|
+
# res.set_redirect WEBrick::HTTPStatus::TemporaryRedirect
|
372
|
+
|
373
|
+
def set_redirect(status, url)
|
374
|
+
url = URI(url).to_s
|
375
|
+
@body = "<HTML><A HREF=\"#{url}\">#{url}</A>.</HTML>\n"
|
376
|
+
@header['location'] = url
|
377
|
+
raise status
|
378
|
+
end
|
379
|
+
|
380
|
+
##
|
381
|
+
# Creates an error page for exception +ex+ with an optional +backtrace+
|
382
|
+
|
383
|
+
def set_error(ex, backtrace=false)
|
384
|
+
case ex
|
385
|
+
when HTTPStatus::Status
|
386
|
+
@keep_alive = false if HTTPStatus::error?(ex.code)
|
387
|
+
self.status = ex.code
|
388
|
+
else
|
389
|
+
@keep_alive = false
|
390
|
+
self.status = HTTPStatus::RC_INTERNAL_SERVER_ERROR
|
391
|
+
end
|
392
|
+
@header['content-type'] = "text/html; charset=ISO-8859-1"
|
393
|
+
|
394
|
+
if respond_to?(:create_error_page)
|
395
|
+
create_error_page()
|
396
|
+
return
|
397
|
+
end
|
398
|
+
|
399
|
+
if @request_uri
|
400
|
+
host, port = @request_uri.host, @request_uri.port
|
401
|
+
else
|
402
|
+
host, port = @config[:ServerName], @config[:Port]
|
403
|
+
end
|
404
|
+
|
405
|
+
error_body(backtrace, ex, host, port)
|
406
|
+
end
|
407
|
+
|
408
|
+
private
|
409
|
+
|
410
|
+
def check_header(header_value)
|
411
|
+
header_value = header_value.to_s
|
412
|
+
if /[\r\n]/ =~ header_value
|
413
|
+
raise InvalidHeader
|
414
|
+
else
|
415
|
+
header_value
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
# :stopdoc:
|
420
|
+
|
421
|
+
def error_body(backtrace, ex, host, port)
|
422
|
+
@body = +''
|
423
|
+
@body << <<-_end_of_html_
|
424
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
|
425
|
+
<HTML>
|
426
|
+
<HEAD><TITLE>#{HTMLUtils::escape(@reason_phrase)}</TITLE></HEAD>
|
427
|
+
<BODY>
|
428
|
+
<H1>#{HTMLUtils::escape(@reason_phrase)}</H1>
|
429
|
+
#{HTMLUtils::escape(ex.message)}
|
430
|
+
<HR>
|
431
|
+
_end_of_html_
|
432
|
+
|
433
|
+
if backtrace && $DEBUG
|
434
|
+
@body << "backtrace of `#{HTMLUtils::escape(ex.class.to_s)}' "
|
435
|
+
@body << "#{HTMLUtils::escape(ex.message)}"
|
436
|
+
@body << "<PRE>"
|
437
|
+
ex.backtrace.each{|line| @body << "\t#{line}\n"}
|
438
|
+
@body << "</PRE><HR>"
|
439
|
+
end
|
440
|
+
|
441
|
+
@body << <<-_end_of_html_
|
442
|
+
<ADDRESS>
|
443
|
+
#{HTMLUtils::escape(@config[:ServerSoftware])} at
|
444
|
+
#{host}:#{port}
|
445
|
+
</ADDRESS>
|
446
|
+
</BODY>
|
447
|
+
</HTML>
|
448
|
+
_end_of_html_
|
449
|
+
end
|
450
|
+
|
451
|
+
def send_body_io(socket)
|
452
|
+
begin
|
453
|
+
if @request_method == "HEAD"
|
454
|
+
# do nothing
|
455
|
+
elsif chunked?
|
456
|
+
buf = +''
|
457
|
+
begin
|
458
|
+
@body.readpartial(@buffer_size, buf)
|
459
|
+
size = buf.bytesize
|
460
|
+
data = +"#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
|
461
|
+
socket.write(data)
|
462
|
+
data.clear
|
463
|
+
@sent_size += size
|
464
|
+
rescue EOFError
|
465
|
+
break
|
466
|
+
end while true
|
467
|
+
buf.clear
|
468
|
+
socket.write("0#{CRLF}#{CRLF}")
|
469
|
+
else
|
470
|
+
if %r{\Abytes (\d+)-(\d+)/\d+\z} =~ @header['content-range']
|
471
|
+
offset = $1.to_i
|
472
|
+
size = $2.to_i - offset + 1
|
473
|
+
else
|
474
|
+
offset = nil
|
475
|
+
size = @header['content-length']
|
476
|
+
size = size.to_i if size
|
477
|
+
end
|
478
|
+
begin
|
479
|
+
@sent_size = IO.copy_stream(@body, socket, size, offset)
|
480
|
+
rescue NotImplementedError
|
481
|
+
@body.seek(offset, IO::SEEK_SET)
|
482
|
+
@sent_size = IO.copy_stream(@body, socket, size)
|
483
|
+
end
|
484
|
+
end
|
485
|
+
ensure
|
486
|
+
@body.close
|
487
|
+
end
|
488
|
+
remove_body_tempfile
|
489
|
+
end
|
490
|
+
|
491
|
+
def send_body_string(socket)
|
492
|
+
if @request_method == "HEAD"
|
493
|
+
# do nothing
|
494
|
+
elsif chunked?
|
495
|
+
body ? @body.bytesize : 0
|
496
|
+
while buf = @body[@sent_size, @buffer_size]
|
497
|
+
break if buf.empty?
|
498
|
+
size = buf.bytesize
|
499
|
+
data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
|
500
|
+
buf.clear
|
501
|
+
socket.write(data)
|
502
|
+
@sent_size += size
|
503
|
+
end
|
504
|
+
socket.write("0#{CRLF}#{CRLF}")
|
505
|
+
else
|
506
|
+
if @body && @body.bytesize > 0
|
507
|
+
socket.write(@body)
|
508
|
+
@sent_size = @body.bytesize
|
509
|
+
end
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
def send_body_proc(socket)
|
514
|
+
if @request_method == "HEAD"
|
515
|
+
# do nothing
|
516
|
+
elsif chunked?
|
517
|
+
@body.call(ChunkedWrapper.new(socket, self))
|
518
|
+
socket.write("0#{CRLF}#{CRLF}")
|
519
|
+
else
|
520
|
+
size = @header['content-length'].to_i
|
521
|
+
if @bodytempfile
|
522
|
+
@bodytempfile.rewind
|
523
|
+
IO.copy_stream(@bodytempfile, socket)
|
524
|
+
else
|
525
|
+
@body.call(socket)
|
526
|
+
end
|
527
|
+
@sent_size = size
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
class ChunkedWrapper
|
532
|
+
def initialize(socket, resp)
|
533
|
+
@socket = socket
|
534
|
+
@resp = resp
|
535
|
+
end
|
536
|
+
|
537
|
+
def write(buf)
|
538
|
+
return 0 if buf.empty?
|
539
|
+
socket = @socket
|
540
|
+
@resp.instance_eval {
|
541
|
+
size = buf.bytesize
|
542
|
+
data = +"#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
|
543
|
+
socket.write(data)
|
544
|
+
data.clear
|
545
|
+
@sent_size += size
|
546
|
+
size
|
547
|
+
}
|
548
|
+
end
|
549
|
+
|
550
|
+
def <<(*buf)
|
551
|
+
write(buf)
|
552
|
+
self
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
# preserved for compatibility with some 3rd-party handlers
|
557
|
+
def _write_data(socket, data)
|
558
|
+
socket << data
|
559
|
+
end
|
560
|
+
|
561
|
+
# :startdoc:
|
562
|
+
end
|
563
|
+
|
564
|
+
end
|