http-cookie 1.0.0.pre12 → 1.0.4

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
- SHA1:
3
- metadata.gz: 2a70ec83e62018ae7621d1eb7ba75f08eea1d696
4
- data.tar.gz: 9ed2b81801d89bb7adf3f6d97b087421406f4acf
2
+ SHA256:
3
+ metadata.gz: 6e3fc7cc6e374fa6bdd53c2a32cae8b8856615df4aad76fe496ab6375738652e
4
+ data.tar.gz: 0132bb41158fa3bf84a0adf2fcf7226115a1126efbc12c879f465a8c2114215b
5
5
  SHA512:
6
- metadata.gz: f1ba260a8757b9076df6645368f761005cc665ef1c4ae357f102982132ed66253ae7cb49d163430bd3070225524c0cd4a988b2abbc4252e3e68e8376eea68542
7
- data.tar.gz: bca8c545043e5b4975e32350dcf37f1519a183e3d207bb2692313863104884750ef656ed568106b69beab35e53b0536c36b677846255b1d477af95d022c74bfe
6
+ metadata.gz: 341c0b9947ed005f8c73030ad7b5380aa19d76cbfc2f3f09ac69207a9a5b33e62f0094f6b68b98ad839f110c565f7afc08a9ff504c82affe736a8bcb55908e05
7
+ data.tar.gz: c4346ce6bae86a394c72b38f079c3c272205df3b7453c630e1dc3fc1ae7dec7ee0f652c9b5f2b12151fb6b7b402a5fbc41b832c051cf17102bd1cd584f72b461
data/.travis.yml CHANGED
@@ -1,17 +1,21 @@
1
+ sudo: false
1
2
  language: ruby
3
+ cache: bundler
2
4
  rvm:
3
5
  - 1.8.7
4
6
  - ree
5
- - 1.9.2
6
7
  - 1.9.3
7
8
  - 2.0.0
9
+ - 2.1
10
+ - 2.2
11
+ - 2.3.0
8
12
  - ruby-head
9
- - jruby-18mode
10
- - jruby-19mode
11
- - jruby-head
12
- - rbx-18mode
13
- - rbx-19mode
13
+ - jruby-1.7
14
+ - jruby-9
15
+ - rbx-2
14
16
  matrix:
15
17
  allow_failures:
16
- - rvm: rbx-18mode
17
- - rvm: rbx-19mode
18
+ - rvm: ruby-head
19
+ - rvm: rbx-2
20
+ before_install:
21
+ - gem update bundler
data/CHANGELOG.md ADDED
@@ -0,0 +1,29 @@
1
+ ## Unreleased
2
+
3
+ - Support Mozilla's cookie storage format up to version 7.
4
+
5
+ - Fix the time representation with creationTime and lastAccessed in
6
+ MozillaStore. (#8)
7
+
8
+ ## 1.0.3 (2016-09-30)
9
+
10
+ - Treat comma as normal character in HTTP::Cookie.cookie_value_to_hash
11
+ instead of key-value pair separator. This should fix the problem
12
+ described in CVE-2016-7401.
13
+
14
+ ## 1.0.2 (2013-09-10)
15
+
16
+ - Fix HTTP::Cookie.parse so that it does not raise ArgumentError
17
+ when it finds a bad name or value that is parsable but considered
18
+ invalid.
19
+
20
+ ## 1.0.1 (2013-04-21)
21
+
22
+ - Minor error handling improvements and documentation updates.
23
+
24
+ - Argument error regarding specifying store/saver classes no longer
25
+ raises IndexError, but either ArgumentError or TypeError.
26
+
27
+ ## 1.0.0 (2013-04-17)
28
+
29
+ - Initial Release.
data/README.md CHANGED
@@ -8,6 +8,34 @@ It was originally a part of the
8
8
  separated as an independent library in the hope of serving as a common
9
9
  component that is reusable from any HTTP related piece of software.
10
10
 
11
+ The following is an incomplete list of its features:
12
+
13
+ * Its behavior is highly compatible with that of today's major web
14
+ browsers.
15
+
16
+ * It is based on and conforms to RFC 6265 (the latest standard for the
17
+ HTTP cookie mechanism) to a high extent, with real world conventions
18
+ deeply in mind.
19
+
20
+ * It takes eTLD (effective TLD, also known as "Public Suffix") into
21
+ account just as major browsers do, to reject cookies with an eTLD
22
+ domain like "org", "co.jp", or "appspot.com". This feature is
23
+ brought to you by the domain_name gem.
24
+
25
+ * The number of cookies and the size are properly capped so that a
26
+ cookie store does not get flooded.
27
+
28
+ * It supports the legacy Netscape cookies.txt format for
29
+ serialization, maximizing the interoperability with other
30
+ implementations.
31
+
32
+ * It supports the cookies.sqlite format adopted by Mozilla Firefox for
33
+ backend store database which can be shared among multiple program
34
+ instances.
35
+
36
+ * It is relatively easy to add a new serialization format or a backend
37
+ store because of its modular API.
38
+
11
39
  ## Installation
12
40
 
13
41
  Add this line to your application's `Gemfile`:
data/http-cookie.gemspec CHANGED
@@ -13,9 +13,10 @@ Gem::Specification.new do |gem|
13
13
  'Mike Dalessio' => 'mike.dalessio@gmail.com',
14
14
  }.instance_eval { [keys, values] }
15
15
 
16
- gem.description = %q{A Ruby library to handle HTTP Cookies}
17
- gem.summary = %q{A Ruby library to handle HTTP Cookies}
16
+ gem.description = %q{HTTP::Cookie is a Ruby library to handle HTTP Cookies based on RFC 6265. It has with security, standards compliance and compatibility in mind, to behave just the same as today's major web browsers. It has builtin support for the legacy cookies.txt and the latest cookies.sqlite formats of Mozilla Firefox, and its modular API makes it easy to add support for a new backend store.}
17
+ gem.summary = %q{A Ruby library to handle HTTP Cookies based on RFC 6265}
18
18
  gem.homepage = "https://github.com/sparklemotion/http-cookie"
19
+ gem.license = "MIT"
19
20
 
20
21
  gem.files = `git ls-files`.split($/)
21
22
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -26,8 +27,9 @@ Gem::Specification.new do |gem|
26
27
  gem.add_runtime_dependency("domain_name", ["~> 0.5"])
27
28
  gem.add_development_dependency("sqlite3", ["~> 1.3.3"]) unless defined?(JRUBY_VERSION)
28
29
  gem.add_development_dependency("bundler", [">= 1.2.0"])
29
- gem.add_development_dependency("test-unit", [">= 2.4.3"])
30
- gem.add_development_dependency("rake", [">= 0.9.2.2"])
31
- gem.add_development_dependency("rdoc", ["> 2.4.2"])
30
+ gem.add_development_dependency("test-unit", [">= 2.4.3", *("< 3" if RUBY_VERSION < "1.9")])
31
+ gem.add_development_dependency("rake", [">= 0.9.2.2", *("< 11" if RUBY_VERSION < "1.9")])
32
+ gem.add_development_dependency("rdoc", RUBY_VERSION > "1.9" ? "> 2.4.2" : "~> 2.4.2")
32
33
  gem.add_development_dependency("simplecov", [">= 0"])
34
+ gem.add_development_dependency("json", ["< 2"]) if RUBY_VERSION < "2.0"
33
35
  end
data/lib/http/cookie.rb CHANGED
@@ -87,7 +87,7 @@ class HTTP::Cookie
87
87
  # The Expires attribute value as a Time object.
88
88
  #
89
89
  # The setter method accepts a Time object, a string representation
90
- # of date/time, or `nil`.
90
+ # of date/time that Time.parse can understand, or `nil`.
91
91
  #
92
92
  # Setting this value resets #max_age to nil. When #max_age is
93
93
  # non-nil, #expires returns `created_at + max_age`.
@@ -111,12 +111,11 @@ class HTTP::Cookie
111
111
  # new(**attr_hash)
112
112
  #
113
113
  # Creates a cookie object. For each key of `attr_hash`, the setter
114
- # is called if defined. Each key can be either a symbol or a
115
- # string of downcased attribute names.
116
- #
117
- # This methods accepts any attribute name for which a setter method
118
- # is defined. Beware, however, any error (typically ArgumentError)
119
- # a setter method raises will be passed through.
114
+ # is called if defined and any error (typically ArgumentError or
115
+ # TypeError) that is raised will be passed through. Each key can be
116
+ # either a downcased symbol or a string that may be mixed case.
117
+ # Support for the latter may, however, be obsoleted in future when
118
+ # Ruby 2.0's keyword syntax is adopted.
120
119
  #
121
120
  # If `value` is omitted or it is nil, an expiration cookie is
122
121
  # created unless `max_age` or `expires` (`expires_at`) is given.
@@ -129,7 +128,7 @@ class HTTP::Cookie
129
128
  # new("name" => "uid", "value" => "a12345", "Domain" => 'www.example.org')
130
129
  #
131
130
  def initialize(*args)
132
- @origin = @domain = @path =
131
+ @name = @origin = @domain = @path =
133
132
  @expires = @max_age = nil
134
133
  @for_domain = @secure = @httponly = false
135
134
  @session = true
@@ -157,8 +156,8 @@ class HTTP::Cookie
157
156
  end
158
157
  for_domain = false
159
158
  domain = max_age = origin = nil
160
- attr_hash.each_pair { |key, val|
161
- case key.to_sym
159
+ attr_hash.each_pair { |okey, val|
160
+ case key ||= okey
162
161
  when :name
163
162
  self.name = val
164
163
  when :value
@@ -175,28 +174,26 @@ class HTTP::Cookie
175
174
  # Let max_age take precedence over expires
176
175
  max_age = val
177
176
  when :expires, :expires_at
178
- self.expires = val
177
+ self.expires = val unless max_age
179
178
  when :httponly, :httponly?
180
179
  @httponly = val
181
180
  when :secure, :secure?
182
181
  @secure = val
183
- when /[A-Z]/
184
- warn "keyword should be downcased: #{key}" if $VERBOSE
185
- key = key.downcase
186
- redo
187
182
  when Symbol
188
183
  setter = :"#{key}="
189
184
  if respond_to?(setter)
190
185
  __send__(setter, val)
191
186
  else
192
- warn "unknown keyword: #{key}" if $VERBOSE
187
+ warn "unknown attribute name: #{okey.inspect}" if $VERBOSE
188
+ next
193
189
  end
194
190
  when String
195
- key = key.to_sym
191
+ warn "use downcased symbol for keyword: #{okey.inspect}" if $VERBOSE
192
+ key = key.downcase.to_sym
196
193
  redo
197
194
  else
198
- key = key.to_s
199
- redo
195
+ warn "invalid keyword ignored: #{okey.inspect}" if $VERBOSE
196
+ next
200
197
  end
201
198
  }
202
199
  if @name.nil?
@@ -284,14 +281,21 @@ class HTTP::Cookie
284
281
  Scanner.new(set_cookie, logger).scan_set_cookie { |name, value, attrs|
285
282
  break if name.nil? || name.empty?
286
283
 
287
- cookie = new(name, value)
284
+ begin
285
+ cookie = new(name, value)
286
+ rescue => e
287
+ logger.warn("Invalid name or value: #{e}") if logger
288
+ next
289
+ end
288
290
  cookie.created_at = created_at if created_at
289
291
  attrs.each { |aname, avalue|
290
292
  begin
291
293
  case aname
292
294
  when 'domain'
293
295
  cookie.for_domain = true
294
- cookie.domain = avalue # This may negate @for_domain
296
+ # The following may negate @for_domain if the value is
297
+ # an eTLD or IP address, hence this order.
298
+ cookie.domain = avalue
295
299
  when 'path'
296
300
  cookie.path = avalue
297
301
  when 'expires'
@@ -343,7 +347,7 @@ class HTTP::Cookie
343
347
  attr_reader :name
344
348
 
345
349
  # See #name.
346
- def name=(name)
350
+ def name= name
347
351
  name = (String.try_convert(name) or
348
352
  raise TypeError, "#{name.class} is not a String")
349
353
  if name.empty?
@@ -360,7 +364,7 @@ class HTTP::Cookie
360
364
  attr_reader :value
361
365
 
362
366
  # See #value.
363
- def value=(value)
367
+ def value= value
364
368
  if value.nil?
365
369
  self.expires = UNIX_EPOCH
366
370
  return @value = ''
@@ -379,7 +383,7 @@ class HTTP::Cookie
379
383
  attr_reader :domain
380
384
 
381
385
  # See #domain.
382
- def domain=(domain)
386
+ def domain= domain
383
387
  case domain
384
388
  when nil
385
389
  @for_domain = false
@@ -437,7 +441,7 @@ class HTTP::Cookie
437
441
  attr_reader :path
438
442
 
439
443
  # See #path.
440
- def path=(path)
444
+ def path= path
441
445
  path = (String.try_convert(path) or
442
446
  raise TypeError, "#{path.class} is not a String")
443
447
  @path = path.start_with?('/') ? path : '/'
@@ -446,10 +450,11 @@ class HTTP::Cookie
446
450
  attr_reader :origin
447
451
 
448
452
  # See #origin.
449
- def origin=(origin)
453
+ def origin= origin
450
454
  return origin if origin == @origin
451
455
  @origin.nil? or
452
456
  raise ArgumentError, "origin cannot be changed once it is set"
457
+ # Delay setting @origin because #domain= or #path= may fail
453
458
  origin = URI(origin)
454
459
  if URI::HTTP === origin
455
460
  self.domain ||= origin.host
@@ -482,7 +487,7 @@ class HTTP::Cookie
482
487
  end
483
488
 
484
489
  # See #expires.
485
- def expires=(t)
490
+ def expires= t
486
491
  case t
487
492
  when nil, Time
488
493
  else
@@ -499,8 +504,7 @@ class HTTP::Cookie
499
504
  attr_reader :max_age
500
505
 
501
506
  # See #max_age.
502
- def max_age=(sec)
503
- @expires = nil
507
+ def max_age= sec
504
508
  case sec
505
509
  when Integer, nil
506
510
  else
@@ -510,6 +514,7 @@ class HTTP::Cookie
510
514
  raise ArgumentError, "invalid Max-Age: #{sec.inspect}"
511
515
  sec = str.to_i
512
516
  end
517
+ @expires = nil
513
518
  if @session = sec.nil?
514
519
  @max_age = nil
515
520
  else
@@ -603,7 +608,7 @@ class HTTP::Cookie
603
608
  if @domain
604
609
  string << "; Domain=#{@domain}"
605
610
  else
606
- raise "for_domain is specified but domain is known"
611
+ raise "for_domain is specified but domain is unknown"
607
612
  end
608
613
  end
609
614
  if @path
@@ -611,7 +616,7 @@ class HTTP::Cookie
611
616
  string << "; Path=#{@path}"
612
617
  end
613
618
  else
614
- raise "path is known"
619
+ raise "path is unknown"
615
620
  end
616
621
  if @max_age
617
622
  string << "; Max-Age=#{@max_age}"
@@ -635,7 +640,7 @@ class HTTP::Cookie
635
640
 
636
641
  # Compares the cookie with another. When there are many cookies with
637
642
  # the same name for a URL, the value of the smallest must be used.
638
- def <=>(other)
643
+ def <=> other
639
644
  # RFC 6265 5.4
640
645
  # Precedence: 1. longer path 2. older creation
641
646
  (@name <=> other.name).nonzero? ||
@@ -1,5 +1,5 @@
1
1
  class Array
2
- def select!
2
+ def select! # :yield: x
3
3
  i = 0
4
4
  each_with_index { |x, j|
5
5
  yield x or next
@@ -10,6 +10,10 @@ class Array
10
10
  self[i..-1] = []
11
11
  self
12
12
  end unless method_defined?(:select!)
13
+
14
+ def sort_by!(&block) # :yield: x
15
+ replace(sort_by(&block))
16
+ end unless method_defined?(:sort_by!)
13
17
  end
14
18
 
15
19
  class Hash
@@ -50,7 +50,7 @@ class HTTP::Cookie::Scanner < StringScanner
50
50
  }
51
51
  end
52
52
 
53
- def scan_value
53
+ def scan_value(comma_as_separator = false)
54
54
  ''.tap { |s|
55
55
  case
56
56
  when scan(/[^,;"]+/)
@@ -59,7 +59,9 @@ class HTTP::Cookie::Scanner < StringScanner
59
59
  # RFC 6265 2.2
60
60
  # A cookie-value may be DQUOTE'd.
61
61
  s << scan_dquoted
62
- when check(/;|#{RE_COOKIE_COMMA}/o)
62
+ when check(/;/)
63
+ break
64
+ when comma_as_separator && check(RE_COOKIE_COMMA)
63
65
  break
64
66
  else
65
67
  s << getch
@@ -68,12 +70,12 @@ class HTTP::Cookie::Scanner < StringScanner
68
70
  }
69
71
  end
70
72
 
71
- def scan_name_value
73
+ def scan_name_value(comma_as_separator = false)
72
74
  name = scan_name
73
75
  if skip(/\=/)
74
- value = scan_value
76
+ value = scan_value(comma_as_separator)
75
77
  else
76
- scan_value
78
+ scan_value(comma_as_separator)
77
79
  value = nil
78
80
  end
79
81
  [name, value]
@@ -152,13 +154,6 @@ class HTTP::Cookie::Scanner < StringScanner
152
154
  end
153
155
 
154
156
  def scan_set_cookie
155
- unless block_given?
156
- scan_set_cookie { |*values|
157
- return values
158
- }
159
- return
160
- end
161
-
162
157
  # RFC 6265 4.1.1 & 5.2
163
158
  until eos?
164
159
  start = pos
@@ -166,7 +161,7 @@ class HTTP::Cookie::Scanner < StringScanner
166
161
 
167
162
  skip_wsp
168
163
 
169
- name, value = scan_name_value
164
+ name, value = scan_name_value(true)
170
165
  if value.nil?
171
166
  @logger.warn("Cookie definition lacks a name-value pair.") if @logger
172
167
  elsif name.empty?
@@ -183,7 +178,7 @@ class HTTP::Cookie::Scanner < StringScanner
183
178
  break
184
179
  when skip(/;/)
185
180
  skip_wsp
186
- aname, avalue = scan_name_value
181
+ aname, avalue = scan_name_value(true)
187
182
  next if aname.empty? || value.nil?
188
183
  aname.downcase!
189
184
  case aname
@@ -221,24 +216,16 @@ class HTTP::Cookie::Scanner < StringScanner
221
216
  end
222
217
 
223
218
  def scan_cookie
224
- unless block_given?
225
- scan_cookie { |*values|
226
- return values
227
- }
228
- return
229
- end
230
-
231
219
  # RFC 6265 4.1.1 & 5.4
232
220
  until eos?
233
221
  skip_wsp
234
222
 
235
- name, value = scan_name_value
223
+ # Do not treat comma in a Cookie header value as separator; see CVE-2016-7401
224
+ name, value = scan_name_value(false)
236
225
 
237
226
  yield name, value if value
238
227
 
239
- # The comma is used as separator for concatenating multiple
240
- # values of a header.
241
- skip(/[;,]/)
228
+ skip(/;/)
242
229
  end
243
230
  end
244
231
  end