@@ -47,4 +47,70 @@ def test_default_headers_with_mixed_types
4747 assert_nil body [ "headers" ] [ "X-Nil" ]
4848 assert_equal "ok" , body [ "headers" ] [ "X-Str" ]
4949 end
50+
51+ def test_header_order
52+ order = [ "x-zzz" , "x-aaa" , "x-ccc" ]
53+ client = Wreq ::Client . new (
54+ emulation : false ,
55+ http1_only : true ,
56+ no_proxy : true ,
57+ header_order : order ,
58+ headers : { "x-aaa" => "1" , "x-ccc" => "2" , "x-zzz" => "3" }
59+ )
60+ received = capture_wire_headers { |url | client . get ( url ) }
61+
62+ positions = order . map { |h | received . index ( h ) } . compact
63+ assert_equal order . size , positions . size ,
64+ "Not all target headers found in: #{ received . inspect } "
65+ assert_equal positions . sort , positions ,
66+ "Expected #{ order . inspect } in order, got positions #{ positions . inspect } in: #{ received . inspect } "
67+ end
68+
69+ def test_header_order_takes_precedence_over_emulation
70+ # Chrome emulation normally puts "user-agent" before "accept". We reverse
71+ # that relationship to prove the user's header_order wins.
72+ order = [ "host" , "accept" , "user-agent" ]
73+ client = Wreq ::Client . new (
74+ emulation : "chrome_145" ,
75+ http1_only : true ,
76+ no_proxy : true ,
77+ header_order : order
78+ )
79+ received = capture_wire_headers { |url | client . get ( url ) }
80+
81+ positions = order . map { |h | received . index ( h ) } . compact
82+ assert_equal order . size , positions . size ,
83+ "Not all target headers found in: #{ received . inspect } "
84+ assert_equal positions . sort , positions ,
85+ "Expected user's header_order #{ order . inspect } to take precedence; " \
86+ "got positions #{ positions . inspect } in: #{ received . inspect } "
87+ end
88+
89+ private
90+
91+ # Spins up a local TCP server, yields the port formatted into a URL, captures
92+ # the header names from the raw HTTP/1.1 request, then tears down the server.
93+ def capture_wire_headers
94+ require "socket"
95+ server = TCPServer . new ( "127.0.0.1" , 0 )
96+ port = server . addr [ 1 ]
97+ received = [ ]
98+ t = Thread . new do
99+ conn = server . accept
100+ conn . gets # skip request line
101+ loop do
102+ line = conn . gets &.chomp
103+ break if line . nil? || line . empty?
104+ received << line . split ( ":" , 2 ) . first . downcase
105+ end
106+ conn . write "HTTP/1.1 200 OK\r \n Content-Length: 0\r \n Connection: close\r \n \r \n "
107+ conn . close
108+ rescue
109+ conn &.close
110+ end
111+ yield format ( "http://127.0.0.1:#{ port } /" )
112+ t . join ( 5 )
113+ server . close
114+ received
115+ end
50116end
0 commit comments