mechanize 2.14.1 → 2.14.2

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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -1
  3. data/lib/mechanize/directory_saver.rb +2 -1
  4. data/lib/mechanize/file_saver.rb +2 -0
  5. data/lib/mechanize/parser.rb +33 -3
  6. data/lib/mechanize/test_case.rb +2 -9
  7. data/lib/mechanize/version.rb +1 -1
  8. metadata +3 -172
  9. data/.autotest +0 -6
  10. data/.github/dependabot.yml +0 -11
  11. data/.github/workflows/ci.yml +0 -43
  12. data/.github/workflows/upstream.yml +0 -51
  13. data/.gitignore +0 -15
  14. data/.yardopts +0 -8
  15. data/Gemfile +0 -12
  16. data/Rakefile +0 -56
  17. data/examples/flickr_upload.rb +0 -22
  18. data/examples/latest_user_agents.rb +0 -100
  19. data/examples/mech-dump.rb +0 -5
  20. data/examples/proxy_req.rb +0 -7
  21. data/examples/rubygems.rb +0 -23
  22. data/examples/spider.rb +0 -22
  23. data/examples/wikipedia_links_to_philosophy.rb +0 -158
  24. data/mechanize.gemspec +0 -74
  25. data/test/data/htpasswd +0 -1
  26. data/test/data/server.crt +0 -16
  27. data/test/data/server.csr +0 -12
  28. data/test/data/server.key +0 -15
  29. data/test/data/server.pem +0 -15
  30. data/test/test_mechanize.rb +0 -1382
  31. data/test/test_mechanize_cookie.rb +0 -559
  32. data/test/test_mechanize_cookie_jar.rb +0 -615
  33. data/test/test_mechanize_directory_saver.rb +0 -60
  34. data/test/test_mechanize_download.rb +0 -102
  35. data/test/test_mechanize_element_not_found_error.rb +0 -16
  36. data/test/test_mechanize_file.rb +0 -118
  37. data/test/test_mechanize_file_connection.rb +0 -40
  38. data/test/test_mechanize_file_request.rb +0 -26
  39. data/test/test_mechanize_file_response.rb +0 -48
  40. data/test/test_mechanize_file_saver.rb +0 -22
  41. data/test/test_mechanize_form.rb +0 -1025
  42. data/test/test_mechanize_form_check_box.rb +0 -49
  43. data/test/test_mechanize_form_encoding.rb +0 -110
  44. data/test/test_mechanize_form_field.rb +0 -78
  45. data/test/test_mechanize_form_file_upload.rb +0 -21
  46. data/test/test_mechanize_form_image_button.rb +0 -13
  47. data/test/test_mechanize_form_keygen.rb +0 -34
  48. data/test/test_mechanize_form_multi_select_list.rb +0 -98
  49. data/test/test_mechanize_form_option.rb +0 -60
  50. data/test/test_mechanize_form_radio_button.rb +0 -96
  51. data/test/test_mechanize_form_select_list.rb +0 -81
  52. data/test/test_mechanize_form_textarea.rb +0 -53
  53. data/test/test_mechanize_headers.rb +0 -36
  54. data/test/test_mechanize_history.rb +0 -104
  55. data/test/test_mechanize_http_agent.rb +0 -2145
  56. data/test/test_mechanize_http_auth_challenge.rb +0 -64
  57. data/test/test_mechanize_http_auth_realm.rb +0 -56
  58. data/test/test_mechanize_http_auth_store.rb +0 -233
  59. data/test/test_mechanize_http_content_disposition_parser.rb +0 -167
  60. data/test/test_mechanize_http_www_authenticate_parser.rb +0 -204
  61. data/test/test_mechanize_image.rb +0 -9
  62. data/test/test_mechanize_link.rb +0 -171
  63. data/test/test_mechanize_page.rb +0 -295
  64. data/test/test_mechanize_page_encoding.rb +0 -215
  65. data/test/test_mechanize_page_frame.rb +0 -17
  66. data/test/test_mechanize_page_image.rb +0 -191
  67. data/test/test_mechanize_page_link.rb +0 -377
  68. data/test/test_mechanize_page_meta_refresh.rb +0 -151
  69. data/test/test_mechanize_parser.rb +0 -316
  70. data/test/test_mechanize_pluggable_parser.rb +0 -68
  71. data/test/test_mechanize_redirect_limit_reached_error.rb +0 -25
  72. data/test/test_mechanize_redirect_not_get_or_head_error.rb +0 -15
  73. data/test/test_mechanize_response_read_error.rb +0 -29
  74. data/test/test_mechanize_subclass.rb +0 -23
  75. data/test/test_mechanize_util.rb +0 -144
  76. data/test/test_mechanize_xml_file.rb +0 -30
  77. data/test/test_multi_select.rb +0 -120
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01e9dae7534053b14ad6ab963f43aaf4fd6475bae450ddbe78d2dc690ab0d541
4
- data.tar.gz: ab9674181ce7e7a023b1e58f72c30cb84898358aa09294612b4aeee26cc5057e
3
+ metadata.gz: 88e582acc05ea06598dcdde3bd7feeaa34b865a9f14cbdb471867e011615d746
4
+ data.tar.gz: 0b6ef8790866784501313c7b8485bba98bda4665ae520f6cd7fef3c24e99f9a0
5
5
  SHA512:
6
- metadata.gz: fc6571d503c3c2cbf2e22a6c9af5b75b3479bceaf008e3480e55d7a6ebaf9d5673c3cb61ec64fc29b6081e802afa6b2f5ec321d6247119bda822825a32f4248b
7
- data.tar.gz: d2188a092148a8ea10865d1cf8e07a8f8a08c6c30760e191efa3a6af3a756821e95e525c116396000c063ba0ec670325900af4b5cb099c222cbfc6d71c5b26b3
6
+ metadata.gz: 22c3ccf0b548e92b4ff08a9144156d301d80bbf93e64302db5d8efdbdeb3f54dd1f8ddd827cc09382064134ec3f4488ae8f63ac3ad0c75b5aa536046e62dd8ad
7
+ data.tar.gz: 0a810214b4812af939185ccd63a73bb4adebff45afc0d94e5f931702c928e7949a21b09655dc16e36ecfd1e8e7c3d328e7c9912291373ac4d7cfb08f84ea0c5a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Mechanize CHANGELOG
2
2
 
3
+ ## 2.14.2 / 2026-10-26
4
+
5
+ ### Security
6
+
7
+ * A malicious server can no longer make `Mechanize::FileSaver`, or `Mechanize::DirectorySaver` with `decode_filename: true`, write files outside the save directory. Only applications that register one of these as a pluggable parser are affected. [GHSA-hxgc-9476-fc65](https://github.com/sparklemotion/mechanize/security/advisories/GHSA-hxgc-9476-fc65)
8
+
9
+ ### Improved
10
+
11
+ * The gem no longer packages the test suite, the test certificates, or the example scripts, which makes it about a third smaller. It still packages `test/htdocs/`, which `Mechanize::TestCase` needs. (#667) @yuri-zubov
12
+ * `Mechanize::TestCase` fake responses work with `net-http` 0.10.0 and later, which reads response lines with `Net::BufferedIO#readuntil`. Previously a chunked response body raised `NoMethodError`. The fake socket is now a `Net::BufferedIO`, like a real one, so `read_body` yields fragments of at most 16 KiB, and a body shorter than its `Content-Length` raises `EOFError` when `ignore_eof` is false.
13
+
14
+
3
15
  ## 2.14.1 / 2026-08-22
4
16
 
5
17
  ### Security
@@ -1147,4 +1159,3 @@ Mechanize is now under the MIT license
1147
1159
  * Added a response code exception
1148
1160
  * Thanks to Brian Ellin (brianellin@gmail.com) for:
1149
1161
  Added support for CA files, and support for 301 response codes
1150
-
@@ -64,8 +64,9 @@ class Mechanize::DirectorySaver < Mechanize::Download
64
64
 
65
65
  super
66
66
 
67
- @filename = CGI.unescape(@filename) if self.class.decode_filename?
67
+ @filename = CGI.unescape(@filename).tr('/\\', '_') if self.class.decode_filename?
68
68
  path = File.join directory, @filename
69
+ ensure_within directory, path
69
70
 
70
71
  if self.class.overwrite?
71
72
  save! path
@@ -25,6 +25,8 @@ class Mechanize::FileSaver < Mechanize::Download
25
25
 
26
26
  super
27
27
 
28
+ ensure_within Dir.pwd, @uri.host
29
+ ensure_within @uri.host, @filename
28
30
  save @filename
29
31
  end
30
32
 
@@ -108,10 +108,10 @@ module Mechanize::Parser
108
108
  handled = false
109
109
 
110
110
  if @uri then
111
- uri = @uri
112
- uri += 'index.html' if uri.path.end_with? '/'
111
+ uri_path = remove_dot_segments @uri.path
112
+ uri_path += 'index.html' if uri_path.end_with? '/'
113
113
 
114
- path = uri.path.split(/\//)
114
+ path = uri_path.split(/\//)
115
115
  filename = path.pop || 'index.html'
116
116
  else
117
117
  path = []
@@ -163,6 +163,36 @@ module Mechanize::Parser
163
163
  @response
164
164
  end
165
165
 
166
+ ##
167
+ # Resolves "." and ".." segments in the absolute +path+ as RFC 3986 section
168
+ # 5.2.4 does, without reparsing it as a URI.
169
+
170
+ def remove_dot_segments path
171
+ segments = path.split '/', -1
172
+
173
+ resolved = segments.each_with_object [] do |segment, result|
174
+ case segment
175
+ when '.' then next
176
+ when '..' then result.pop unless result == ['']
177
+ else result << segment
178
+ end
179
+ end
180
+
181
+ resolved << '' if ['.', '..'].include? segments.last
182
+ resolved.join '/'
183
+ end
184
+
185
+ ##
186
+ # Raises Mechanize::Error unless +path+ is inside +directory+.
187
+
188
+ def ensure_within directory, path
189
+ directory = File.join File.expand_path(directory), ''
190
+
191
+ return if File.expand_path(path).start_with? directory
192
+
193
+ raise Mechanize::Error, "refusing to save #{path} outside #{directory}"
194
+ end
195
+
166
196
  ##
167
197
  # Finds a free filename based on +filename+, but is not race-free
168
198
 
@@ -262,15 +262,8 @@ class Net::HTTP # :nodoc:
262
262
  response['Content-Type'] ||= 'text/html'
263
263
  response['Content-Length'] = res['Content-Length'] || res.body.length.to_s
264
264
 
265
- io = StringIO.new(res.body)
266
- response.instance_variable_set :@socket, io
267
- def io.read clen, dest = nil, _ = nil
268
- if dest then
269
- dest << super(clen)
270
- else
271
- super clen
272
- end
273
- end
265
+ socket = Net::BufferedIO.new(StringIO.new(res.body))
266
+ response.instance_variable_set :@socket, socket
274
267
 
275
268
  body_exist = req.response_body_permitted? &&
276
269
  response_klass.body_permitted?
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  class Mechanize
3
- VERSION = "2.14.1"
3
+ VERSION = "2.14.2"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mechanize
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.14.1
4
+ version: 2.14.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Hodel
@@ -238,27 +238,12 @@ extra_rdoc_files:
238
238
  - README.md
239
239
  - SECURITY.md
240
240
  files:
241
- - ".autotest"
242
- - ".github/dependabot.yml"
243
- - ".github/workflows/ci.yml"
244
- - ".github/workflows/upstream.yml"
245
- - ".gitignore"
246
- - ".yardopts"
247
241
  - CHANGELOG.md
248
242
  - EXAMPLES.rdoc
249
243
  - GUIDE.rdoc
250
- - Gemfile
251
244
  - LICENSE.txt
252
245
  - README.md
253
- - Rakefile
254
246
  - SECURITY.md
255
- - examples/flickr_upload.rb
256
- - examples/latest_user_agents.rb
257
- - examples/mech-dump.rb
258
- - examples/proxy_req.rb
259
- - examples/rubygems.rb
260
- - examples/spider.rb
261
- - examples/wikipedia_links_to_philosophy.rb
262
247
  - lib/mechanize.rb
263
248
  - lib/mechanize/chunked_termination_error.rb
264
249
  - lib/mechanize/content_type_error.rb
@@ -349,12 +334,6 @@ files:
349
334
  - lib/mechanize/util.rb
350
335
  - lib/mechanize/version.rb
351
336
  - lib/mechanize/xml_file.rb
352
- - mechanize.gemspec
353
- - test/data/htpasswd
354
- - test/data/server.crt
355
- - test/data/server.csr
356
- - test/data/server.key
357
- - test/data/server.pem
358
337
  - test/htdocs/alt_text.html
359
338
  - test/htdocs/bad_form_test.html
360
339
  - test/htdocs/button.jpg
@@ -402,54 +381,6 @@ files:
402
381
  - test/htdocs/tc_textarea.html
403
382
  - test/htdocs/test_click.html
404
383
  - test/htdocs/unusual______.html
405
- - test/test_mechanize.rb
406
- - test/test_mechanize_cookie.rb
407
- - test/test_mechanize_cookie_jar.rb
408
- - test/test_mechanize_directory_saver.rb
409
- - test/test_mechanize_download.rb
410
- - test/test_mechanize_element_not_found_error.rb
411
- - test/test_mechanize_file.rb
412
- - test/test_mechanize_file_connection.rb
413
- - test/test_mechanize_file_request.rb
414
- - test/test_mechanize_file_response.rb
415
- - test/test_mechanize_file_saver.rb
416
- - test/test_mechanize_form.rb
417
- - test/test_mechanize_form_check_box.rb
418
- - test/test_mechanize_form_encoding.rb
419
- - test/test_mechanize_form_field.rb
420
- - test/test_mechanize_form_file_upload.rb
421
- - test/test_mechanize_form_image_button.rb
422
- - test/test_mechanize_form_keygen.rb
423
- - test/test_mechanize_form_multi_select_list.rb
424
- - test/test_mechanize_form_option.rb
425
- - test/test_mechanize_form_radio_button.rb
426
- - test/test_mechanize_form_select_list.rb
427
- - test/test_mechanize_form_textarea.rb
428
- - test/test_mechanize_headers.rb
429
- - test/test_mechanize_history.rb
430
- - test/test_mechanize_http_agent.rb
431
- - test/test_mechanize_http_auth_challenge.rb
432
- - test/test_mechanize_http_auth_realm.rb
433
- - test/test_mechanize_http_auth_store.rb
434
- - test/test_mechanize_http_content_disposition_parser.rb
435
- - test/test_mechanize_http_www_authenticate_parser.rb
436
- - test/test_mechanize_image.rb
437
- - test/test_mechanize_link.rb
438
- - test/test_mechanize_page.rb
439
- - test/test_mechanize_page_encoding.rb
440
- - test/test_mechanize_page_frame.rb
441
- - test/test_mechanize_page_image.rb
442
- - test/test_mechanize_page_link.rb
443
- - test/test_mechanize_page_meta_refresh.rb
444
- - test/test_mechanize_parser.rb
445
- - test/test_mechanize_pluggable_parser.rb
446
- - test/test_mechanize_redirect_limit_reached_error.rb
447
- - test/test_mechanize_redirect_not_get_or_head_error.rb
448
- - test/test_mechanize_response_read_error.rb
449
- - test/test_mechanize_subclass.rb
450
- - test/test_mechanize_util.rb
451
- - test/test_mechanize_xml_file.rb
452
- - test/test_multi_select.rb
453
384
  homepage: https://github.com/sparklemotion/mechanize
454
385
  licenses:
455
386
  - MIT
@@ -476,107 +407,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
476
407
  - !ruby/object:Gem::Version
477
408
  version: '0'
478
409
  requirements: []
479
- rubygems_version: 4.0.16
410
+ rubygems_version: 4.0.20
480
411
  specification_version: 4
481
412
  summary: The Mechanize library is used for automating interaction with websites
482
- test_files:
483
- - test/data/htpasswd
484
- - test/data/server.crt
485
- - test/data/server.csr
486
- - test/data/server.key
487
- - test/data/server.pem
488
- - test/htdocs/alt_text.html
489
- - test/htdocs/bad_form_test.html
490
- - test/htdocs/button.jpg
491
- - test/htdocs/canonical_uri.html
492
- - test/htdocs/dir with spaces/foo.html
493
- - test/htdocs/empty_form.html
494
- - test/htdocs/file_upload.html
495
- - test/htdocs/find_link.html
496
- - test/htdocs/form_multi_select.html
497
- - test/htdocs/form_multival.html
498
- - test/htdocs/form_no_action.html
499
- - test/htdocs/form_no_input_name.html
500
- - test/htdocs/form_order_test.html
501
- - test/htdocs/form_select.html
502
- - test/htdocs/form_set_fields.html
503
- - test/htdocs/form_test.html
504
- - test/htdocs/frame_referer_test.html
505
- - test/htdocs/frame_test.html
506
- - test/htdocs/google.html
507
- - test/htdocs/index.html
508
- - test/htdocs/link with space.html
509
- - test/htdocs/meta_cookie.html
510
- - test/htdocs/no_title_test.html
511
- - test/htdocs/noindex.html
512
- - test/htdocs/rails_3_encoding_hack_form_test.html
513
- - test/htdocs/relative/tc_relative_links.html
514
- - test/htdocs/robots.html
515
- - test/htdocs/tc_bad_charset.html
516
- - test/htdocs/tc_bad_links.html
517
- - test/htdocs/tc_base_link.html
518
- - test/htdocs/tc_blank_form.html
519
- - test/htdocs/tc_charset.html
520
- - test/htdocs/tc_checkboxes.html
521
- - test/htdocs/tc_encoded_links.html
522
- - test/htdocs/tc_field_precedence.html
523
- - test/htdocs/tc_follow_meta.html
524
- - test/htdocs/tc_follow_meta_loop_1.html
525
- - test/htdocs/tc_follow_meta_loop_2.html
526
- - test/htdocs/tc_form_action.html
527
- - test/htdocs/tc_links.html
528
- - test/htdocs/tc_meta_in_body.html
529
- - test/htdocs/tc_pretty_print.html
530
- - test/htdocs/tc_referer.html
531
- - test/htdocs/tc_relative_links.html
532
- - test/htdocs/tc_textarea.html
533
- - test/htdocs/test_click.html
534
- - test/htdocs/unusual______.html
535
- - test/test_mechanize.rb
536
- - test/test_mechanize_cookie.rb
537
- - test/test_mechanize_cookie_jar.rb
538
- - test/test_mechanize_directory_saver.rb
539
- - test/test_mechanize_download.rb
540
- - test/test_mechanize_element_not_found_error.rb
541
- - test/test_mechanize_file.rb
542
- - test/test_mechanize_file_connection.rb
543
- - test/test_mechanize_file_request.rb
544
- - test/test_mechanize_file_response.rb
545
- - test/test_mechanize_file_saver.rb
546
- - test/test_mechanize_form.rb
547
- - test/test_mechanize_form_check_box.rb
548
- - test/test_mechanize_form_encoding.rb
549
- - test/test_mechanize_form_field.rb
550
- - test/test_mechanize_form_file_upload.rb
551
- - test/test_mechanize_form_image_button.rb
552
- - test/test_mechanize_form_keygen.rb
553
- - test/test_mechanize_form_multi_select_list.rb
554
- - test/test_mechanize_form_option.rb
555
- - test/test_mechanize_form_radio_button.rb
556
- - test/test_mechanize_form_select_list.rb
557
- - test/test_mechanize_form_textarea.rb
558
- - test/test_mechanize_headers.rb
559
- - test/test_mechanize_history.rb
560
- - test/test_mechanize_http_agent.rb
561
- - test/test_mechanize_http_auth_challenge.rb
562
- - test/test_mechanize_http_auth_realm.rb
563
- - test/test_mechanize_http_auth_store.rb
564
- - test/test_mechanize_http_content_disposition_parser.rb
565
- - test/test_mechanize_http_www_authenticate_parser.rb
566
- - test/test_mechanize_image.rb
567
- - test/test_mechanize_link.rb
568
- - test/test_mechanize_page.rb
569
- - test/test_mechanize_page_encoding.rb
570
- - test/test_mechanize_page_frame.rb
571
- - test/test_mechanize_page_image.rb
572
- - test/test_mechanize_page_link.rb
573
- - test/test_mechanize_page_meta_refresh.rb
574
- - test/test_mechanize_parser.rb
575
- - test/test_mechanize_pluggable_parser.rb
576
- - test/test_mechanize_redirect_limit_reached_error.rb
577
- - test/test_mechanize_redirect_not_get_or_head_error.rb
578
- - test/test_mechanize_response_read_error.rb
579
- - test/test_mechanize_subclass.rb
580
- - test/test_mechanize_util.rb
581
- - test/test_mechanize_xml_file.rb
582
- - test/test_multi_select.rb
413
+ test_files: []
data/.autotest DELETED
@@ -1,6 +0,0 @@
1
- require 'autotest/restart'
2
-
3
- Autotest.add_hook :initialize do |at|
4
- at.testlib = 'minitest/autorun'
5
- end
6
-
@@ -1,11 +0,0 @@
1
- # To get started with Dependabot version updates, you'll need to specify which
2
- # package ecosystems to update and where the package manifests are located.
3
- # Please see the documentation for all configuration options:
4
- # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5
-
6
- version: 2
7
- updates:
8
- - package-ecosystem: "bundler"
9
- directory: "/"
10
- schedule:
11
- interval: "weekly"
@@ -1,43 +0,0 @@
1
- name: "ci"
2
-
3
- concurrency:
4
- group: "${{github.workflow}}-${{github.ref}}"
5
- cancel-in-progress: true
6
-
7
- on:
8
- workflow_dispatch:
9
- schedule:
10
- - cron: "0 8 * * 5" # At 08:00 on Friday # https://crontab.guru/#0_8_*_*_5
11
- push:
12
- branches:
13
- - main
14
- pull_request:
15
- types: [opened, synchronize]
16
- branches:
17
- - main
18
-
19
- jobs:
20
- rubocop:
21
- runs-on: ubuntu-latest
22
- steps:
23
- - uses: actions/checkout@v4
24
- - uses: ruby/setup-ruby@v1
25
- with:
26
- ruby-version: "4.0"
27
- bundler-cache: true
28
- - run: bundle exec rake rubocop
29
-
30
- test:
31
- needs: ["rubocop"]
32
- strategy:
33
- fail-fast: false
34
- matrix:
35
- ruby-version: ["2.6", "2.7", "3.0", "3.1", "3.2", "3.3", "3.4", "4.0"]
36
- runs-on: ubuntu-latest
37
- steps:
38
- - uses: actions/checkout@v4
39
- - uses: ruby/setup-ruby@v1
40
- with:
41
- ruby-version: ${{matrix.ruby-version}}
42
- bundler-cache: true
43
- - run: bundle exec rake test
@@ -1,51 +0,0 @@
1
- name: "upstream"
2
-
3
- concurrency:
4
- group: "${{github.workflow}}-${{github.ref}}"
5
- cancel-in-progress: true
6
-
7
- on:
8
- workflow_dispatch:
9
- schedule:
10
- - cron: "0 8 * * 5" # At 08:00 on Friday # https://crontab.guru/#0_8_*_*_5
11
- push:
12
- branches:
13
- - main
14
- pull_request:
15
- types: [opened, synchronize]
16
- branches:
17
- - main
18
- paths:
19
- - .github/workflows/upstream.yml # this file
20
-
21
- jobs:
22
- test:
23
- strategy:
24
- fail-fast: false
25
- matrix:
26
- ruby-version: ["head", "truffleruby-head"]
27
- runs-on: ubuntu-latest
28
- steps:
29
- - uses: actions/checkout@v4
30
- - uses: ruby/setup-ruby@v1
31
- with:
32
- ruby-version: ${{matrix.ruby-version}}
33
- bundler-cache: true
34
- - run: bundle exec rake test
35
-
36
- upstream:
37
- name: "upstream (${{matrix.name}})"
38
- strategy:
39
- fail-fast: false
40
- matrix:
41
- include:
42
- - { name: "nokogiri", git: "https://github.com/sparklemotion/nokogiri" }
43
- runs-on: ubuntu-latest
44
- steps:
45
- - uses: actions/checkout@v4
46
- - uses: ruby/setup-ruby@v1
47
- with: { ruby-version: "4.0" }
48
- - run: |
49
- bundle add ${{matrix.name}} --git="${{matrix.git}}"
50
- bundle show
51
- - run: bundle exec rake test
data/.gitignore DELETED
@@ -1,15 +0,0 @@
1
- *.swp
2
- *.gem
3
- *.rbc
4
- /.bundle
5
- /.config
6
- /Gemfile.lock
7
- /TAGS
8
- /pkg
9
- /tags
10
- /.rvmrc
11
- digest.htpasswd
12
- doc
13
- rdoc
14
- .yardoc
15
- _yardoc
data/.yardopts DELETED
@@ -1,8 +0,0 @@
1
- --main=README.md
2
- lib/**/*.rb
3
- -
4
- README.md
5
- LICENSE.txt
6
- CHANGELOG.md
7
- GUIDE.rdoc
8
- EXAMPLES.rdoc
data/Gemfile DELETED
@@ -1,12 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gemspec
4
-
5
- gem "minitest", "~> 5.14"
6
- gem "rake", "~> 13.0"
7
- gem "rdoc", "~> 7.2"
8
- gem "rubocop", "~> 1.12"
9
- unless RUBY_PLATFORM == 'java'
10
- gem 'brotli', '>= 0.5'
11
- gem 'zstd-ruby', '~> 2.0'
12
- end
data/Rakefile DELETED
@@ -1,56 +0,0 @@
1
- require 'rubygems'
2
-
3
- begin
4
- require "bundler/gem_tasks"
5
- rescue LoadError
6
- end
7
-
8
- require 'rdoc/task'
9
- require 'rake/testtask'
10
-
11
- task :prerelease => [:clobber_rdoc, :test]
12
-
13
- desc "Update SSL Certificate"
14
- task('ssl_cert') do |p|
15
- sh "openssl genrsa -des3 -out server.key 1024"
16
- sh "openssl req -new -key server.key -out server.csr"
17
- sh "cp server.key server.key.org"
18
- sh "openssl rsa -in server.key.org -out server.key"
19
- sh "openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt"
20
- sh "cp server.key server.pem"
21
- sh "mv server.key server.csr server.crt server.pem test/data/"
22
- sh "rm server.key.org"
23
- end
24
-
25
- RDoc::Task.new do |rdoc|
26
- rdoc.main = "README.md"
27
- rdoc.rdoc_dir = 'doc'
28
- rdoc.rdoc_files.include( "CHANGELOG.md", "EXAMPLES.rdoc", "GUIDE.rdoc", "LICENSE.txt", "README.md", "lib/**/*.rb")
29
- end
30
-
31
- desc "Run tests"
32
- Rake::TestTask.new { |t|
33
- t.test_files = Dir['test/**/test*.rb']
34
- # t.verbose = true
35
- }
36
-
37
- task publish_docs: %w[rdoc] do
38
- sh 'rsync', '-avzO', '--delete', 'doc/', 'docs-push.seattlerb.org:/data/www/docs.seattlerb.org/mechanize/'
39
- end
40
-
41
- desc "Run rubocop checks"
42
- task :rubocop => ["rubocop:security", "rubocop:frozen_string_literals"]
43
-
44
- namespace "rubocop" do
45
- desc "Run rubocop security check"
46
- task :security do
47
- sh "rubocop lib --only Security"
48
- end
49
-
50
- desc "Run rubocop string literals check"
51
- task :frozen_string_literals do
52
- sh "rubocop lib test --auto-correct-all --only Style/FrozenStringLiteralComment"
53
- end
54
- end
55
-
56
- task default: [:rubocop, :test]
@@ -1,22 +0,0 @@
1
- require 'rubygems'
2
- require 'mechanize'
3
-
4
- agent = Mechanize.new
5
-
6
- # Get the flickr sign in page
7
- page = agent.get 'http://flickr.com/signin/flickr/'
8
-
9
- # Fill out the login form
10
- form = page.form_with :name => 'flickrloginform'
11
- form.email = ARGV[0]
12
- form.password = ARGV[1]
13
- form.submit
14
-
15
- # Go to the upload page
16
- page = page.link_with(:text => 'Upload').click
17
-
18
- # Fill out the form
19
- form = page.forms.action('/photos_upload_process.gne').first
20
- form.file_uploads.name('file1').first.file_name = ARGV[2]
21
- form.submit
22
-
@@ -1,100 +0,0 @@
1
- require 'mechanize'
2
- require 'ostruct'
3
-
4
- # LatestUAFetcher fetches latest user agents from `WhatIsMyBrowser.com`.
5
- # It can use to update `Mechanize::AGENT_ALIASES`.
6
- class LatestUAFetcher
7
- attr_reader :user_agents
8
-
9
- USER_AGENT_TYPES = OpenStruct.new(
10
- linux_firefox: "Linux Firefox",
11
- mac_firefox: "Mac Firefox",
12
- mac_safari: "Mac Safari",
13
- windows_chrome: "Windows Chrome",
14
- windows_edge: "Windows Edge",
15
- windows_firefox: "Windows Firefox",
16
- android: "Android",
17
- iphone: "iPhone",
18
- ipad: "iPad",
19
- )
20
-
21
- BASE_URL = 'https://www.whatismybrowser.com/guides/the-latest-user-agent'
22
-
23
- def initialize
24
- @agent = Mechanize.new.tap { |a| a.user_agent_alias = 'Mac Firefox' }
25
- @user_agents = {}
26
- end
27
-
28
- def run
29
- return unless user_agents.empty?
30
-
31
- sleep_time = 1
32
-
33
- fetch_user_agents('chrome')
34
- fetch_user_agents('firefox')
35
- fetch_user_agents('safari')
36
- fetch_user_agents('edge')
37
- end
38
-
39
- def ordered_user_agents
40
- USER_AGENT_TYPES.to_h.values.each_with_object({}) do |type, ordered_user_agents|
41
- ordered_user_agents[type] = user_agents[type]
42
- end
43
- end
44
-
45
- private
46
-
47
- def fetch_user_agents(browser_name, sleep_time = 1)
48
- puts "fetch #{browser_name} UA..."
49
- send(browser_name)
50
- puts "sleeping... (#{sleep_time}s)"
51
- sleep sleep_time
52
- end
53
-
54
- def edge
55
- page = @agent.get("#{BASE_URL}/edge")
56
-
57
- windows_dom = page.css("h2:contains('Latest Edge on Windows User Agents')")
58
-
59
- @user_agents[USER_AGENT_TYPES.windows_edge] = windows_dom.css('+ .listing-of-useragents .code').first.text
60
- end
61
-
62
- def firefox
63
- page = @agent.get("#{BASE_URL}/firefox")
64
-
65
- desktop_dom = page.css("h2:contains('Latest Firefox on Desktop User Agents')")
66
- table_dom = desktop_dom.css('+ .listing-of-useragents')
67
-
68
- @user_agents[USER_AGENT_TYPES.linux_firefox] = table_dom.css('td:contains("Linux")').css("+ td .code:contains('Ubuntu; Linux x86_64')").text
69
- @user_agents[USER_AGENT_TYPES.windows_firefox] = table_dom.css('td:contains("Windows")').css('+ td .code').text
70
- @user_agents[USER_AGENT_TYPES.mac_firefox] = table_dom.css('td:contains("Macos")').css('+ td .code').text
71
- end
72
-
73
- def safari
74
- page = @agent.get("#{BASE_URL}/safari")
75
-
76
- macos_dom = page.css("h2:contains('Latest Safari on macOS User Agents')")
77
- ios_dom = page.css("h2:contains('Latest Safari on iOS User Agents')")
78
-
79
- @user_agents[USER_AGENT_TYPES.mac_safari] = macos_dom.css('+ .listing-of-useragents .code').first.text
80
- @user_agents[USER_AGENT_TYPES.iphone] = ios_dom.css('+ .listing-of-useragents').css("tr:contains('Iphone') .code").text
81
- @user_agents[USER_AGENT_TYPES.ipad] = ios_dom.css('+ .listing-of-useragents').css("tr:contains('Ipad') .code").text
82
- end
83
-
84
- def chrome
85
- page = @agent.get("#{BASE_URL}/chrome")
86
-
87
- windows_dom = page.css("h2:contains('Latest Chrome on Windows 10 User Agents')")
88
- android_dom = page.css("h2:contains('Latest Chrome on Android User Agents')")
89
-
90
- @user_agents[USER_AGENT_TYPES.windows_chrome] = windows_dom.css('+ .listing-of-useragents .code').first.text
91
- @user_agents[USER_AGENT_TYPES.android] = android_dom.css('+ .listing-of-useragents .code').first.text
92
- end
93
- end
94
-
95
- if $0 == __FILE__
96
- agent = LatestUAFetcher.new
97
- agent.run
98
-
99
- pp agent.ordered_user_agents
100
- end