|
138 | 138 | },
|
139 | 139 | }
|
140 | 140 |
|
| 141 | + response_hash[:ok_no_status_text] = response_hash[:ok].deep_dup |
| 142 | + response_hash[:ok_no_status_text].delete(:status_text) |
| 143 | + |
| 144 | + response_hash[:ok_blank_header_value] = response_hash[:ok].deep_dup |
| 145 | + response_hash[:ok_blank_header_value][:headers]["range"] = "" |
| 146 | + |
141 | 147 | response_hash[:redirection] = {
|
142 | 148 | status_code: "301",
|
143 | 149 | status_text: "Moved Permanently",
|
|
257 | 263 | \r
|
258 | 264 | EOS
|
259 | 265 |
|
| 266 | + response_text[:ok_no_status_text] = response_text[:ok].sub(" #{response_hash[:ok][:status_text]}", "") |
| 267 | + response_text[:ok_blank_header_name] = response_text[:ok].sub( |
| 268 | + "#{response_hash[:ok][:headers]["date"]}\r\n", |
| 269 | + "#{response_hash[:ok][:headers]["date"]}\r\n: Test\r\n", |
| 270 | + ) |
| 271 | + response_text[:ok_blank_header_value] = response_text[:ok].sub( |
| 272 | + "#{response_hash[:ok][:headers]["date"]}\r\n", |
| 273 | + "#{response_hash[:ok][:headers]["date"]}\r\nRange:\r\n", |
| 274 | + ) |
| 275 | + |
260 | 276 | response_text[:redirection] = response_text[:ok].sub(
|
261 | 277 | "HTTP/1.1 #{response_hash[:ok][:status_code]} #{response_hash[:ok][:status_text]}\r",
|
262 | 278 | "HTTP/1.1 #{response_hash[:redirection][:status_code]} #{response_hash[:redirection][:status_text]}\r\n" \
|
|
306 | 322 | body
|
307 | 323 | end
|
308 | 324 |
|
309 |
| - describe "curl_args" do |
| 325 | + describe "::curl_executable" do |
| 326 | + it "returns `HOMEBREW_BREWED_CURL_PATH` when `use_homebrew_curl` is `true`" do |
| 327 | + expect(curl_executable(use_homebrew_curl: true)).to eq(HOMEBREW_BREWED_CURL_PATH) |
| 328 | + end |
| 329 | + |
| 330 | + it "returns curl shim path when `use_homebrew_curl` is `false` or omitted" do |
| 331 | + curl_shim_path = HOMEBREW_SHIMS_PATH/"shared/curl" |
| 332 | + expect(curl_executable(use_homebrew_curl: false)).to eq(curl_shim_path) |
| 333 | + expect(curl_executable).to eq(curl_shim_path) |
| 334 | + end |
| 335 | + end |
| 336 | + |
| 337 | + describe "::curl_path" do |
| 338 | + it "returns a curl path string" do |
| 339 | + expect(curl_path).to match(%r{[^/]+(?:/[^/]+)*}) |
| 340 | + end |
| 341 | + end |
| 342 | + |
| 343 | + describe "::curl_args" do |
| 344 | + include Context |
| 345 | + |
310 | 346 | let(:args) { ["foo"] }
|
311 | 347 | let(:user_agent_string) { "Lorem ipsum dolor sit amet" }
|
312 | 348 |
|
|
388 | 424 | expect { curl_args(*args, retry_max_time: "test") }.to raise_error(TypeError)
|
389 | 425 | end
|
390 | 426 |
|
| 427 | + it "uses `--show-error` when :show_error is `true`" do |
| 428 | + expect(curl_args(*args, show_error: true)).to include("--show-error") |
| 429 | + expect(curl_args(*args, show_error: false)).not_to include("--show-error") |
| 430 | + end |
| 431 | + |
391 | 432 | it "uses `--referer` when :referer is present" do
|
392 | 433 | expect(curl_args(*args, referer: "https://brew.sh").join(" ")).to include("--referer https://brew.sh")
|
393 | 434 | end
|
|
426 | 467 | expect(curl_args(*args).join(" ")).to include("--fail")
|
427 | 468 | expect(curl_args(*args, show_output: true).join(" ")).not_to include("--fail")
|
428 | 469 | end
|
| 470 | + |
| 471 | + it "uses `--progress-bar` outside of a `--verbose` context" do |
| 472 | + expect(curl_args(*args).join(" ")).to include("--progress-bar") |
| 473 | + with_context verbose: true do |
| 474 | + expect(curl_args(*args).join(" ")).not_to include("--progress-bar") |
| 475 | + end |
| 476 | + end |
| 477 | + |
| 478 | + context "when `EnvConfig.curl_verbose?` is `true`" do |
| 479 | + before do |
| 480 | + allow(Homebrew::EnvConfig).to receive(:curl_verbose?).and_return(true) |
| 481 | + end |
| 482 | + |
| 483 | + it "uses `--verbose`" do |
| 484 | + expect(curl_args(*args).join(" ")).to include("--verbose") |
| 485 | + end |
| 486 | + end |
| 487 | + |
| 488 | + context "when `EnvConfig.curl_verbose?` is `false`" do |
| 489 | + before do |
| 490 | + allow(Homebrew::EnvConfig).to receive(:curl_verbose?).and_return(false) |
| 491 | + end |
| 492 | + |
| 493 | + it "doesn't use `--verbose`" do |
| 494 | + expect(curl_args(*args).join(" ")).not_to include("--verbose") |
| 495 | + end |
| 496 | + end |
| 497 | + |
| 498 | + context "when `$stdout.tty?` is `false`" do |
| 499 | + before do |
| 500 | + allow($stdout).to receive(:tty?).and_return(false) |
| 501 | + end |
| 502 | + |
| 503 | + it "uses `--silent`" do |
| 504 | + expect(curl_args(*args).join(" ")).to include("--silent") |
| 505 | + end |
| 506 | + end |
| 507 | + |
| 508 | + context "when `$stdout.tty?` is `true`" do |
| 509 | + before do |
| 510 | + allow($stdout).to receive(:tty?).and_return(true) |
| 511 | + end |
| 512 | + |
| 513 | + it "doesn't use `--silent` outside of a `--quiet` context" do |
| 514 | + with_context quiet: false do |
| 515 | + expect(curl_args(*args).join(" ")).not_to include("--silent") |
| 516 | + end |
| 517 | + |
| 518 | + with_context quiet: true do |
| 519 | + expect(curl_args(*args).join(" ")).to include("--silent") |
| 520 | + end |
| 521 | + end |
| 522 | + end |
429 | 523 | end
|
430 | 524 |
|
431 |
| - describe "url_protected_by_cloudflare?" do |
| 525 | + describe "::url_protected_by_cloudflare?" do |
432 | 526 | it "returns `true` when a URL is protected by Cloudflare" do
|
433 | 527 | expect(url_protected_by_cloudflare?(details[:cloudflare][:single_cookie])).to be(true)
|
434 | 528 | expect(url_protected_by_cloudflare?(details[:cloudflare][:multiple_cookies])).to be(true)
|
|
448 | 542 | end
|
449 | 543 | end
|
450 | 544 |
|
451 |
| - describe "url_protected_by_incapsula?" do |
| 545 | + describe "::url_protected_by_incapsula?" do |
452 | 546 | it "returns `true` when a URL is protected by Cloudflare" do
|
453 | 547 | expect(url_protected_by_incapsula?(details[:incapsula][:single_cookie_visid_incap])).to be(true)
|
454 | 548 | expect(url_protected_by_incapsula?(details[:incapsula][:single_cookie_incap_ses])).to be(true)
|
|
468 | 562 | end
|
469 | 563 | end
|
470 | 564 |
|
471 |
| - describe "#parse_curl_output" do |
| 565 | + describe "::curl_version" do |
| 566 | + it "returns a curl version string" do |
| 567 | + expect(curl_version).to match(/^v?(\d+(?:\.\d+)+)$/) |
| 568 | + end |
| 569 | + end |
| 570 | + |
| 571 | + describe "::curl_supports_fail_with_body?" do |
| 572 | + it "returns `true` if curl version is 7.76.0 or higher" do |
| 573 | + allow_any_instance_of(Utils::Curl).to receive(:curl_version).and_return(Version.new("7.76.0")) |
| 574 | + expect(curl_supports_fail_with_body?).to be(true) |
| 575 | + |
| 576 | + allow_any_instance_of(Utils::Curl).to receive(:curl_version).and_return(Version.new("7.76.1")) |
| 577 | + expect(curl_supports_fail_with_body?).to be(true) |
| 578 | + end |
| 579 | + |
| 580 | + it "returns `false` if curl version is lower than 7.76.0" do |
| 581 | + allow_any_instance_of(Utils::Curl).to receive(:curl_version).and_return(Version.new("7.75.0")) |
| 582 | + expect(curl_supports_fail_with_body?).to be(false) |
| 583 | + end |
| 584 | + end |
| 585 | + |
| 586 | + describe "::curl_supports_tls13?" do |
| 587 | + it "returns `true` if curl command is successful" do |
| 588 | + allow_any_instance_of(Kernel).to receive(:quiet_system).and_return(true) |
| 589 | + expect(curl_supports_tls13?).to be(true) |
| 590 | + end |
| 591 | + |
| 592 | + it "returns `false` if curl command is not successful" do |
| 593 | + allow_any_instance_of(Kernel).to receive(:quiet_system).and_return(false) |
| 594 | + expect(curl_supports_tls13?).to be(false) |
| 595 | + end |
| 596 | + end |
| 597 | + |
| 598 | + describe "::http_status_ok?" do |
| 599 | + it "returns `true` when `status` is 1xx or 2xx" do |
| 600 | + expect(http_status_ok?("200")).to be(true) |
| 601 | + end |
| 602 | + |
| 603 | + it "returns `false` when `status` is not 1xx or 2xx" do |
| 604 | + expect(http_status_ok?("301")).to be(false) |
| 605 | + end |
| 606 | + |
| 607 | + it "returns `false` when `status` is `nil`" do |
| 608 | + expect(http_status_ok?(nil)).to be(false) |
| 609 | + end |
| 610 | + end |
| 611 | + |
| 612 | + describe "::parse_curl_output" do |
472 | 613 | it "returns a correct hash when curl output contains response(s) and body" do
|
473 | 614 | expect(parse_curl_output("#{response_text[:ok]}#{body[:default]}"))
|
474 | 615 | .to eq({ responses: [response_hash[:ok]], body: body[:default] })
|
|
505 | 646 | it "returns correct hash when curl output is blank" do
|
506 | 647 | expect(parse_curl_output("")).to eq({ responses: [], body: "" })
|
507 | 648 | end
|
| 649 | + |
| 650 | + it "errors if response count exceeds `max_iterations`" do |
| 651 | + expect do |
| 652 | + parse_curl_output(response_text[:redirections_to_ok], max_iterations: 1) |
| 653 | + end.to raise_error("Too many redirects (max = 1)") |
| 654 | + end |
508 | 655 | end
|
509 | 656 |
|
510 |
| - describe "#parse_curl_response" do |
| 657 | + describe "::parse_curl_response" do |
511 | 658 | it "returns a correct hash when given HTTP response text" do
|
512 | 659 | expect(parse_curl_response(response_text[:ok])).to eq(response_hash[:ok])
|
| 660 | + expect(parse_curl_response(response_text[:ok_no_status_text])).to eq(response_hash[:ok_no_status_text]) |
| 661 | + expect(parse_curl_response(response_text[:ok_blank_header_value])).to eq(response_hash[:ok_blank_header_value]) |
513 | 662 | expect(parse_curl_response(response_text[:redirection])).to eq(response_hash[:redirection])
|
514 | 663 | expect(parse_curl_response(response_text[:duplicate_header])).to eq(response_hash[:duplicate_header])
|
515 | 664 | end
|
516 | 665 |
|
| 666 | + it "skips over response header lines with blank header name" do |
| 667 | + expect(parse_curl_response(response_text[:ok_blank_header_name])).to eq(response_hash[:ok]) |
| 668 | + end |
| 669 | + |
517 | 670 | it "returns an empty hash when given an empty string" do
|
518 | 671 | expect(parse_curl_response("")).to eq({})
|
519 | 672 | end
|
520 | 673 | end
|
521 | 674 |
|
522 |
| - describe "#curl_response_last_location" do |
| 675 | + describe "::curl_response_last_location" do |
523 | 676 | it "returns the last location header when given an array of HTTP response hashes" do
|
524 | 677 | expect(curl_response_last_location([
|
525 | 678 | response_hash[:redirection],
|
|
577 | 730 | ).to eq(response_hash[:redirection_parent_relative][:headers]["location"].sub(/^\./, "https://brew.sh/test1"))
|
578 | 731 | end
|
579 | 732 |
|
| 733 | + it "skips response hashes without a `:headers` value" do |
| 734 | + expect(curl_response_last_location([ |
| 735 | + response_hash[:redirection], |
| 736 | + { status_code: "404", status_text: "Not Found" }, |
| 737 | + response_hash[:ok], |
| 738 | + ])).to eq(response_hash[:redirection][:headers]["location"]) |
| 739 | + end |
| 740 | + |
580 | 741 | it "returns nil when the response hash doesn't contain a location header" do
|
581 | 742 | expect(curl_response_last_location([response_hash[:ok]])).to be_nil
|
582 | 743 | end
|
583 | 744 | end
|
584 | 745 |
|
585 |
| - describe "#curl_response_follow_redirections" do |
| 746 | + describe "::curl_response_follow_redirections" do |
586 | 747 | it "returns the original URL when there are no location headers" do
|
587 | 748 | expect(
|
588 | 749 | curl_response_follow_redirections(
|
|
634 | 795 | ),
|
635 | 796 | ).to eq("#{location_urls[0]}example/")
|
636 | 797 | end
|
| 798 | + |
| 799 | + it "skips response hashes without a `:headers` value" do |
| 800 | + expect( |
| 801 | + curl_response_follow_redirections( |
| 802 | + [ |
| 803 | + response_hash[:redirection_root_relative], |
| 804 | + { status_code: "404", status_text: "Not Found" }, |
| 805 | + response_hash[:ok], |
| 806 | + ], |
| 807 | + "https://brew.sh/test1/test2", |
| 808 | + ), |
| 809 | + ).to eq("https://brew.sh/example/") |
| 810 | + end |
637 | 811 | end
|
638 | 812 | end
|
0 commit comments