rack-webdav 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 43db150f50bda6ebc40e2fcac2684ab96c1a90ac
4
- data.tar.gz: fe75dfa791f91c6d4489b268c47315ab509b10ff
3
+ metadata.gz: 9025207ede1c1f829fa216898d173661ac29aa2d
4
+ data.tar.gz: e6c001a417788e6a4134493ecb82031467c3ebaa
5
5
  SHA512:
6
- metadata.gz: 296a499b062662184e7da39840918ce7b1892be2a27e5ef8867ef0c068c2f4f7f1522a93332e8478af18b89c1ca457b76a89a6fa3130285134321f0bb3c575a5
7
- data.tar.gz: 238656df1091b804a97b9f2cb398dc4e322c6013266002461d8e382fc5b676f9f794603f43888790b32fc0742c6b48522c7d74086b11c482d27f9dc1a8c92afc
6
+ metadata.gz: 1be317ee0340db32fa1ebf40f663810b58fc50b29a3d08f7c9c745a2912d67849639ac9a4dde236e065119e7f83e90e8fb5b3f69160f90a61e07dd5bb226ac71
7
+ data.tar.gz: e01078ed80e0a6fb2ec0dd99c4c89fa4765a6c1a43d001083935031ac6a9191bd0bc179ec101ab320e8d39d67b5d0526e0b7660098c8b3b12807c47bae140e38
@@ -1,11 +1,11 @@
1
1
  require 'uri'
2
2
 
3
3
  module RackWebDAV
4
-
4
+
5
5
  class Controller
6
6
  include RackWebDAV::HTTPStatus
7
7
  include RackWebDAV::Utils
8
-
8
+
9
9
  attr_reader :request, :response, :resource
10
10
 
11
11
  # request:: Rack::Request
@@ -18,17 +18,17 @@ module RackWebDAV
18
18
  @request = request
19
19
  @response = response
20
20
  @options = options
21
-
21
+
22
22
  @dav_extensions = options.delete(:dav_extensions) || []
23
23
  @always_include_dav_header = options.delete(:always_include_dav_header)
24
-
24
+
25
25
  @resource = resource_class.new(actual_path, implied_path, @request, @response, @options)
26
-
26
+
27
27
  if(@always_include_dav_header)
28
28
  add_dav_header
29
29
  end
30
30
  end
31
-
31
+
32
32
  # s:: string
33
33
  # Escape URL string
34
34
  def url_format(resource)
@@ -38,20 +38,20 @@ module RackWebDAV
38
38
  end
39
39
  ret
40
40
  end
41
-
41
+
42
42
  # s:: string
43
43
  # Unescape URL string
44
- def url_unescape(s)
45
- URI.unescape(s)
44
+ def url_unescape(s, encoding = Encoding::UTF_8)
45
+ URI.decode_www_form_component(s, encoding)
46
46
  end
47
-
47
+
48
48
  def add_dav_header
49
49
  unless(response['Dav'])
50
50
  dav_support = %w(1 2) + @dav_extensions
51
51
  response['Dav'] = dav_support.join(', ')
52
52
  end
53
53
  end
54
-
54
+
55
55
  # Return response to OPTIONS
56
56
  def options
57
57
  add_dav_header
@@ -59,7 +59,7 @@ module RackWebDAV
59
59
  response['Ms-Author-Via'] = 'DAV'
60
60
  OK
61
61
  end
62
-
62
+
63
63
  # Return response to HEAD
64
64
  def head
65
65
  if(resource.exist?)
@@ -71,7 +71,7 @@ module RackWebDAV
71
71
  NotFound
72
72
  end
73
73
  end
74
-
74
+
75
75
  # Return response to GET
76
76
  def get
77
77
  if(resource.exist?)
@@ -117,7 +117,7 @@ module RackWebDAV
117
117
  NotFound
118
118
  end
119
119
  end
120
-
120
+
121
121
  # Return response to MKCOL
122
122
  def mkcol
123
123
  resource.lock_check if resource.supports_locking?
@@ -135,7 +135,7 @@ module RackWebDAV
135
135
  status
136
136
  end
137
137
  end
138
-
138
+
139
139
  # Return response to COPY
140
140
  def copy
141
141
  move(:copy)
@@ -180,7 +180,7 @@ module RackWebDAV
180
180
  end
181
181
  end
182
182
  end
183
-
183
+
184
184
  # Return response to PROPFIND
185
185
  def propfind
186
186
  unless(resource.exist?)
@@ -189,25 +189,28 @@ module RackWebDAV
189
189
  unless(request_document.xpath("//#{ns}propfind/#{ns}allprop").empty?)
190
190
  properties = resource.properties
191
191
  else
192
- check = request_document.xpath("//#{ns}propfind")
193
- if(check && !check.empty?)
194
- properties = request_document.xpath(
195
- "//#{ns}propfind/#{ns}prop"
196
- ).children.find_all{ |item|
197
- item.element?
198
- }.map{ |item|
199
- # We should do this, but Nokogiri transforms prefix w/ null href into
200
- # something valid. Oops.
201
- # TODO: Hacky grep fix that's horrible
202
- hsh = to_element_hash(item)
203
- if(hsh.namespace.nil? && !ns.empty?)
204
- raise BadRequest if request_document.to_s.scan(%r{<#{item.name}[^>]+xmlns=""}).empty?
205
- end
206
- hsh
207
- }.compact
192
+ if request.body.read.bytesize > 0
193
+ request.body.rewind
194
+ check = request_document.xpath("//#{ns}propfind")
195
+ if(check && !check.empty?)
196
+ properties = request_document.xpath(
197
+ "//#{ns}propfind/#{ns}prop"
198
+ ).children.find_all{ |item|
199
+ item.element?
200
+ }.map{ |item|
201
+ # We should do this, but Nokogiri transforms prefix w/ null href into
202
+ # something valid. Oops.
203
+ # TODO: Hacky grep fix that's horrible
204
+ hsh = to_element_hash(item)
205
+ if(hsh.namespace.nil? && !ns.empty?)
206
+ raise BadRequest if request_document.to_s.scan(%r{<#{item.name}[^>]+xmlns=""}).empty?
207
+ end
208
+ hsh
209
+ }.compact
210
+ else
211
+ raise BadRequest
212
+ end
208
213
  else
209
- # XXX: Compatibility for Windows.
210
- # raise BadRequest
211
214
  properties = []
212
215
  end
213
216
  end
@@ -225,7 +228,7 @@ module RackWebDAV
225
228
  end
226
229
  end
227
230
  end
228
-
231
+
229
232
  # Return response to PROPPATCH
230
233
  def proppatch
231
234
  unless(resource.exist?)
@@ -266,7 +269,7 @@ module RackWebDAV
266
269
 
267
270
  # Lock current resource
268
271
  # NOTE: This will pass an argument hash to Resource#lock and
269
- # wait for a success/failure response.
272
+ # wait for a success/failure response.
270
273
  def lock
271
274
  lockinfo = request_document.xpath("//#{ns}lockinfo")
272
275
  asked = {}
@@ -344,29 +347,29 @@ module RackWebDAV
344
347
  end
345
348
  raise Unauthorized unless authed
346
349
  end
347
-
350
+
348
351
  private
349
352
 
350
353
  # Request environment variables
351
354
  def env
352
355
  @request.env
353
356
  end
354
-
357
+
355
358
  # Current request scheme (http/https)
356
359
  def scheme
357
360
  request.scheme
358
361
  end
359
-
362
+
360
363
  # Request host
361
364
  def host
362
365
  request.host
363
366
  end
364
-
367
+
365
368
  # Request port
366
369
  def port
367
370
  request.port
368
371
  end
369
-
372
+
370
373
  # Class of the resource in use
371
374
  def resource_class
372
375
  @options[:resource_class]
@@ -376,12 +379,12 @@ module RackWebDAV
376
379
  def root_uri_path
377
380
  @options[:root_uri_path]
378
381
  end
379
-
382
+
380
383
  # Returns Resource path with root URI removed
381
384
  def implied_path
382
385
  clean_path(@request.path.dup)
383
386
  end
384
-
387
+
385
388
  # x:: request path
386
389
  # Unescapes path and removes root URI if applicable
387
390
  def clean_path(x)
@@ -389,7 +392,7 @@ module RackWebDAV
389
392
  ip.gsub!(/^#{Regexp.escape(root_uri_path)}/, '') if root_uri_path
390
393
  ip
391
394
  end
392
-
395
+
393
396
  # Unescaped request path
394
397
  def actual_path
395
398
  url_unescape(@request.path.dup)
@@ -399,7 +402,7 @@ module RackWebDAV
399
402
  def lock_token
400
403
  env['HTTP_LOCK_TOKEN'] || nil
401
404
  end
402
-
405
+
403
406
  # Requested depth
404
407
  def depth
405
408
  d = env['HTTP_DEPTH']
@@ -415,7 +418,7 @@ module RackWebDAV
415
418
  def http_version
416
419
  env['HTTP_VERSION'] || env['SERVER_PROTOCOL'] || 'HTTP/1.0'
417
420
  end
418
-
421
+
419
422
  # Overwrite is allowed
420
423
  def overwrite
421
424
  env['HTTP_OVERWRITE'].to_s.upcase != 'F'
@@ -434,9 +437,10 @@ module RackWebDAV
434
437
  end
435
438
  with_current_resource ? [resource] + ary : ary
436
439
  end
437
-
440
+
438
441
  # XML parsed request
439
442
  def request_document
443
+ request.body.rewind
440
444
  @request_document ||= Nokogiri.XML(request.body.read)
441
445
  rescue
442
446
  raise BadRequest
@@ -458,7 +462,7 @@ module RackWebDAV
458
462
  end
459
463
  _ns
460
464
  end
461
-
465
+
462
466
  # root_type:: Root tag name
463
467
  # Render XML and set Rack::Response#body= to final XML
464
468
  def render_xml(root_type)
@@ -470,7 +474,7 @@ module RackWebDAV
470
474
  yield xml
471
475
  end
472
476
  end
473
-
477
+
474
478
  if(@options[:pretty_xml])
475
479
  response.body = doc.to_xml
476
480
  else
@@ -481,7 +485,7 @@ module RackWebDAV
481
485
  response["Content-Type"] = 'text/xml; charset="utf-8"'
482
486
  response["Content-Length"] = response.body.size.to_s
483
487
  end
484
-
488
+
485
489
  # block:: block
486
490
  # Creates a multistatus response using #render_xml and
487
491
  # returns the correct status
@@ -489,7 +493,7 @@ module RackWebDAV
489
493
  render_xml(:multistatus, &block)
490
494
  MultiStatus
491
495
  end
492
-
496
+
493
497
  # xml:: Nokogiri::XML::Builder
494
498
  # errors:: Array of errors
495
499
  # Crafts responses for errors
@@ -545,7 +549,7 @@ module RackWebDAV
545
549
  end
546
550
  stats
547
551
  end
548
-
552
+
549
553
  # xml:: Nokogiri::XML::Builder
550
554
  # stats:: Array of stats
551
555
  # Build propstats response
@@ -590,14 +594,12 @@ module RackWebDAV
590
594
  end
591
595
  end
592
596
  end
593
-
597
+
594
598
  # xml:: Nokogiri::XML::Builder
595
599
  # element:: Nokogiri::XML::Element
596
600
  # Converts element into proper text
597
601
  def xml_convert(xml, element)
598
602
  xml.doc.root.add_child(element)
599
603
  end
600
-
601
604
  end
602
-
603
- end
605
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require 'rack-webdav/logger'
2
3
 
3
4
  module RackWebDAV
@@ -181,7 +181,7 @@ module RackWebDAV
181
181
  if(::File.directory?(file_path))
182
182
  MethodNotAllowed
183
183
  else
184
- if(::File.directory?(::File.dirname(file_path)) && !::File.exists?(file_path))
184
+ if(::File.directory?(::File.dirname(file_path)) && !::File.exists?(file_path) && !::File.exists?(file_path.gsub(/\/$/, '')))
185
185
  Dir.mkdir(file_path)
186
186
  Created
187
187
  else
@@ -299,7 +299,12 @@ module RackWebDAV
299
299
  end
300
300
  raise failure
301
301
  else
302
- locks = FileResourceLock.implict_locks(@path).find(:all, :conditions => ["scope = 'exclusive' AND user_id != ?", @user.id])
302
+ if @user.respond_to?(:id)
303
+ locks = FileResourceLock.implict_locks(@path).find(:all, :conditions => ["scope = 'exclusive' AND user_id != ?", @user.id])
304
+ else
305
+ locks = []
306
+ end
307
+
303
308
  if(locks.size > 0)
304
309
  failure = LockFailure.new("Failed to lock: #{@path}")
305
310
  locks.each do |lock|
@@ -13,5 +13,5 @@ module RackWebDAV
13
13
  end
14
14
  end
15
15
 
16
- VERSION = Version.new('0.4.2')
16
+ VERSION = Version.new('0.4.3')
17
17
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-webdav
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koki Oyatsu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-10 00:00:00.000000000 Z
11
+ date: 2017-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -176,7 +176,6 @@ files:
176
176
  - lib/rack-webdav/remote_file.rb
177
177
  - lib/rack-webdav/resource.rb
178
178
  - lib/rack-webdav/resources/file_resource.rb
179
- - lib/rack-webdav/resources/mongo_resource.rb
180
179
  - lib/rack-webdav/utils.rb
181
180
  - lib/rack-webdav/version.rb
182
181
  - rack-webdav.gemspec
@@ -1,341 +0,0 @@
1
- # coding: utf-8
2
- require 'mime/types'
3
-
4
- module RackWebDAV
5
-
6
- class MongoResource < RackWebDAV::Resource
7
-
8
- # @@logger = Rails.logger
9
-
10
- def initialize(public_path, path, request, response, options)
11
- # 'ASCII-8BIT'で渡される場合があるので'UTF-8'を指定しておく
12
- _force_encoding!(public_path)
13
- _force_encoding!(path)
14
- super(public_path, path, request, response, options)
15
- @filesystem = Mongo::GridFileSystem.new(Mongoid.database)
16
- @collection = Mongoid.database.collection('fs.files')
17
- if options[:bson]
18
- @bson = options[:bson]
19
- elsif path.length <= 1
20
- # ルートの場合 (''の場合と'/'の場合がある)
21
- @bson = {'filename' => root + '/'}
22
- else
23
- # ファイルかディレクトリが、パラメータだけでは判断できない。ので \/? が必要。
24
- # だから、ディレクトリと同名のファイルは、作成できない。
25
- @bson = @collection.find_one({:filename => /^#{Regexp.escape(file_path)}\/?$/}) rescue nil
26
- end
27
- end
28
-
29
- def child(bson)
30
- path = remove(bson['filename'], root)
31
- public_path = @options[:root_uri_path] + path
32
- @options[:bson] = bson
33
- self.class.new(public_path, path, @request, @response, @options)
34
- end
35
-
36
- # If this is a collection, return the child resources.
37
- def children
38
- # Dir[file_path + '/*'].map do |path|
39
- # child File.basename(path)
40
- # end
41
- @collection.find({:filename => /^#{Regexp.escape(@bson['filename'])}[^\/]+\/?$/}).map do |bson|
42
- child bson
43
- end
44
- end
45
-
46
- # Is this resource a collection?
47
- def collection?
48
- # File.directory?(file_path)
49
- @bson && _collection?(@bson['filename'])
50
- end
51
-
52
- # Does this recource exist?
53
- def exist?
54
- # File.exist?(file_path)
55
- @bson
56
- end
57
-
58
- # Return the creation time.
59
- def creation_date
60
- # stat.ctime
61
- @bson['uploadDate'] || Date.new
62
- end
63
-
64
- # Return the time of last modification.
65
- def last_modified
66
- # stat.mtime
67
- @bson['uploadDate'] || Date.new
68
- end
69
-
70
- # Set the time of last modification.
71
- def last_modified=(time)
72
- # File.utime(Time.now, time, file_path)
73
- end
74
-
75
- # Return an Etag, an unique hash value for this resource.
76
- def etag
77
- # sprintf('%x-%x-%x', stat.ino, stat.size, stat.mtime.to_i)
78
- @bson['_id'].to_s
79
- end
80
-
81
- # Return the mime type of this resource.
82
- def content_type
83
- # if stat.directory?
84
- # "text/html"
85
- # else
86
- # mime_type(file_path, DefaultMimeTypes)
87
- # end
88
- @bson['contentType'] || "text/html"
89
- end
90
-
91
- # Return the size in bytes for this resource.
92
- def content_length
93
- # stat.size
94
- @bson['length'] || 0
95
- end
96
-
97
- # HTTP GET request.
98
- #
99
- # Write the content of the resource to the response.body.
100
- def get(request, response)
101
- raise NotFound unless exist?
102
- # if stat.directory?
103
- # response.body = ""
104
- # Rack::Directory.new(root).call(request.env)[2].each do |line|
105
- # response.body << line
106
- # end
107
- # response['Content-Length'] = response.body.size.to_s
108
- # else
109
- # file = Rack::File.new(root)
110
- # response.body = file
111
- # end
112
- if collection?
113
- response.body = "<html>"
114
- response.body << "<h2>" + file_path.html_safe + "</h2>"
115
- children.each do |child|
116
- name = child.file_path.html_safe
117
- path = child.public_path
118
- response.body << "<a href='" + path + "'>" + name + "</a>"
119
- response.body << "</br>"
120
- end
121
- response.body << "</html>"
122
- response['Content-Length'] = response.body.size.to_s
123
- response['Content-Type'] = 'text/html'
124
- else
125
- @filesystem.open(file_path, 'r') do |f|
126
- response.body = f
127
- response['Content-Type'] = @bson['contentType']
128
- end
129
- end
130
-
131
- end
132
-
133
- # HTTP PUT request.
134
- #
135
- # Save the content of the request.body.
136
- def put(request, response)
137
- write(request.body)
138
- Created
139
- end
140
-
141
- # HTTP POST request.
142
- #
143
- # Usually forbidden.
144
- def post(request, response)
145
- raise HTTPStatus::Forbidden
146
- end
147
-
148
- # HTTP DELETE request.
149
- #
150
- # Delete this resource.
151
- def delete
152
- # if stat.directory?
153
- # FileUtils.rm_rf(file_path)
154
- # else
155
- # File.unlink(file_path)
156
- # end
157
- if collection?
158
- @collection.find({:filename => /^#{Regexp.escape(@bson['filename'])}/}).each do |bson|
159
- @collection.remove(bson)
160
- end
161
- else
162
- @collection.remove(@bson)
163
- end
164
- NoContent
165
- end
166
-
167
- # HTTP COPY request.
168
- #
169
- # Copy this resource to given destination resource.
170
- def copy(dest, overwrite = false)
171
- # if(dest.path == path)
172
- # Conflict
173
- # elsif(stat.directory?)
174
- # dest.make_collection
175
- # FileUtils.cp_r("#{file_path}/.", "#{dest.send(:file_path)}/")
176
- # OK
177
- # else
178
- # exists = File.exists?(file_path)
179
- # if(exists && !overwrite)
180
- # PreconditionFailed
181
- # else
182
- # open(file_path, "rb") do |file|
183
- # dest.write(file)
184
- # end
185
- # exists ? NoContent : Created
186
- # end
187
- # end
188
-
189
- # ディレクトリなら末尾に「/」をつける。
190
- # (dstにもともと「/」が付いているかどうか、クライアントに依存している)
191
- # CarotDAV : 「/」が付いていない
192
- # TeamFile : 「/」が付いている
193
- dest.collection! if collection?
194
-
195
- src = @bson['filename']
196
- dst = dest.file_path
197
- exists = nil
198
-
199
- @collection.find({:filename => /^#{Regexp.escape(src)}/}).each do |bson|
200
- src_name = bson['filename']
201
- dst_name = dst + src_name.slice(src.length, src_name.length)
202
-
203
- exists = @collection.find_one({:filename => dst_name}) rescue nil
204
-
205
- return PreconditionFailed if (exists && !overwrite && !collection?)
206
-
207
- @filesystem.open(src_name, "r") do |src|
208
- @filesystem.open(dst_name, "w") do |dst|
209
- dst.write(src) if src.file_length > 0
210
- end
211
- end
212
-
213
- @collection.remove(exists) if exists
214
- end
215
-
216
- collection? ? Created : (exists ? NoContent : Created)
217
- end
218
-
219
- # HTTP MOVE request.
220
- #
221
- # Move this resource to given destination resource.
222
- def move(dest, overwrite = false)
223
-
224
- # ディレクトリなら末尾に「/」をつける。
225
- # (dstにもともと「/」が付いているかどうか、クライアントに依存している)
226
- # CarotDAV : 「/」が付いていない
227
- # TeamFile : 「/」が付いている
228
- dest.collection! if collection?
229
-
230
- src = @bson['filename']
231
- dst = dest.file_path
232
- exists = nil
233
-
234
- @collection.find({:filename => /^#{Regexp.escape(src)}/}).each do |bson|
235
- src_name = bson['filename']
236
- dst_name = dst + src_name.slice(src.length, src_name.length)
237
-
238
- exists = @collection.find_one({:filename => dst_name}) rescue nil
239
-
240
- # http://mongoid.org/docs/persistence/atomic.html
241
- # http://rubydoc.info/github/mongoid/mongoid/master/Mongoid/Collection#update-instance_method
242
- @collection.update({'_id' => bson['_id']}, {'$set' => {'filename' => dst_name}}, :safe => true)
243
-
244
- @collection.remove(exists) if exists
245
- end
246
-
247
- collection? ? Created : (exists ? NoContent : Created)
248
- end
249
-
250
- # HTTP MKCOL request.
251
- #
252
- # Create this resource as collection.
253
- def make_collection
254
- # Dir.mkdir(file_path)
255
- # Created
256
-
257
- # ディレクトリなら末尾に「/」をつける。
258
- # (dstにもともと「/」が付いているかどうか、クライアントに依存している)
259
- # CarotDAV : 「/」が付いていない
260
- # TeamFile : 「/」が付いている
261
- collection!
262
-
263
- bson = @collection.find_one({:filename => file_path}) rescue nil
264
-
265
- # 0バイトのファイルを作成しディレクトリの代わりとする
266
- @filesystem.open(file_path, "w") { |f| } if !bson
267
-
268
- # @@logger.error('make_collection : ' + file_path)
269
-
270
- Created
271
- end
272
-
273
- # Write to this resource from given IO.
274
- def write(io)
275
- # tempfile = "#{file_path}.#{Process.pid}.#{object_id}"
276
- # open(tempfile, "wb") do |file|
277
- # while part = io.read(8192)
278
- # file << part
279
- # end
280
- # end
281
- # File.rename(tempfile, file_path)
282
- # ensure
283
- # File.unlink(tempfile) rescue nil
284
-
285
- # 同名のファイルができないように
286
- bson = @collection.find_one({:filename => file_path}) rescue nil
287
-
288
- @filesystem.open(file_path, "w", :content_type => _content_type(file_path)) { |f| f.write(io) }
289
-
290
- # 同名のファイルができないように
291
- @collection.remove(bson) if bson
292
-
293
- end
294
-
295
- protected
296
-
297
- def file_path
298
- root + path
299
- end
300
-
301
- # ファイル名の末尾に「/」を付加してディレクトリ(コレクション)とする
302
- def collection!
303
- path << '/' if !_collection?(path)
304
- end
305
-
306
- private
307
-
308
- def _content_type(filename)
309
- MIME::Types.type_for(filename).first.to_s || 'text/html'
310
- end
311
-
312
- def authenticate(user, pass)
313
- if(options[:username])
314
- options[:username] == user && options[:password] == pass
315
- else
316
- true
317
- end
318
- end
319
-
320
- # path1の先頭からpath2を取り除く
321
- def remove(path1, path2)
322
- path1.slice(path2.length, path1.length)
323
- end
324
-
325
- def root
326
- @options[:root]
327
- end
328
-
329
- # ファイル名の末尾が「/」のファイルをディレクトリ(コレクション)とする
330
- def _collection?(path)
331
- path && path[-1].chr == '/'
332
- end
333
-
334
- # 'ASCII-8BIT'で渡される場合があるので'UTF-8'を指定しておく
335
- def _force_encoding!(str)
336
- str.force_encoding('UTF-8')
337
- end
338
-
339
- end
340
-
341
- end