1+ # frozen_string_literal: true
2+
3+ # Released under the MIT License.
4+ # Copyright, 2022-2024, by Samuel Williams.
5+
6+ require "protocol/rack/rewindable"
7+ require "protocol/http/body/rewindable"
8+
9+ describe Protocol ::Rack ::Rewindable do
10+ let ( :headers ) { Protocol ::HTTP ::Headers . new }
11+ let ( :body ) { Protocol ::HTTP ::Body ::Readable . new }
12+ let ( :app ) {
13+ app = Object . new
14+ mock ( app ) do |mock |
15+ mock . replace ( :call ) do |request |
16+ Protocol ::HTTP ::Response [ 200 , { } , [ ] ]
17+ end
18+ end
19+ app
20+ }
21+
22+ with "non-POST requests" do
23+ it "should rewind if it has a buffered media type" do
24+ request = Protocol ::HTTP ::Request . new (
25+ "https" , "example.com" , "GET" , "/" , "HTTP/1.1" , headers , body
26+ )
27+ request . headers [ "content-type" ] = "application/x-www-form-urlencoded"
28+
29+ rewindable = subject . new ( nil )
30+ expect ( rewindable . needs_rewind? ( request ) ) . to be == true
31+ end
32+ end
33+
34+ with "POST requests" do
35+ it "should rewind POST requests with no content type" do
36+ request = Protocol ::HTTP ::Request . new (
37+ "https" , "example.com" , "POST" , "/" , "HTTP/1.1" , headers , body
38+ )
39+
40+ rewindable = subject . new ( nil )
41+ expect ( rewindable . needs_rewind? ( request ) ) . to be == true
42+ end
43+
44+ it "should rewind form-urlencoded requests" do
45+ request = Protocol ::HTTP ::Request . new (
46+ "https" , "example.com" , "POST" , "/" , "HTTP/1.1" , headers , body
47+ )
48+ request . headers [ "content-type" ] = "application/x-www-form-urlencoded"
49+
50+ rewindable = subject . new ( nil )
51+ expect ( rewindable . needs_rewind? ( request ) ) . to be == true
52+ end
53+
54+ it "should rewind multipart form requests" do
55+ request = Protocol ::HTTP ::Request . new (
56+ "https" , "example.com" , "POST" , "/" , "HTTP/1.1" , headers , body
57+ )
58+ request . headers [ "content-type" ] = "multipart/form-data; boundary=----WebKitFormBoundary"
59+
60+ rewindable = subject . new ( nil )
61+ expect ( rewindable . needs_rewind? ( request ) ) . to be == true
62+ end
63+
64+ it "should rewind multipart related requests" do
65+ request = Protocol ::HTTP ::Request . new (
66+ "https" , "example.com" , "POST" , "/" , "HTTP/1.1" , headers , body
67+ )
68+ request . headers [ "content-type" ] = "multipart/related; boundary=----WebKitFormBoundary"
69+
70+ rewindable = subject . new ( nil )
71+ expect ( rewindable . needs_rewind? ( request ) ) . to be == true
72+ end
73+
74+ it "should rewind multipart mixed requests" do
75+ request = Protocol ::HTTP ::Request . new (
76+ "https" , "example.com" , "POST" , "/" , "HTTP/1.1" , headers , body
77+ )
78+ request . headers [ "content-type" ] = "multipart/mixed; boundary=----WebKitFormBoundary"
79+
80+ rewindable = subject . new ( nil )
81+ expect ( rewindable . needs_rewind? ( request ) ) . to be == true
82+ end
83+
84+ it "should not rewind other content types" do
85+ request = Protocol ::HTTP ::Request . new (
86+ "https" , "example.com" , "POST" , "/" , "HTTP/1.1" , headers , body
87+ )
88+ request . headers [ "content-type" ] = "application/json"
89+
90+ rewindable = subject . new ( nil )
91+ expect ( rewindable . needs_rewind? ( request ) ) . to be == false
92+ end
93+ end
94+
95+ with "body wrapping" do
96+ it "should wrap rewindable bodies" do
97+ request = Protocol ::HTTP ::Request . new (
98+ "https" , "example.com" , "POST" , "/" , "HTTP/1.1" , headers , body
99+ )
100+ request . headers [ "content-type" ] = "application/x-www-form-urlencoded"
101+
102+ rewindable = subject . new ( app )
103+ rewindable . call ( request )
104+
105+ expect ( request . body ) . to be_a ( Protocol ::HTTP ::Body ::Rewindable )
106+ expect ( request . body . body ) . to be == body
107+ end
108+
109+ it "should not wrap non-rewindable bodies" do
110+ request = Protocol ::HTTP ::Request . new (
111+ "https" , "example.com" , "POST" , "/" , "HTTP/1.1" , headers , body
112+ )
113+ request . headers [ "content-type" ] = "application/json"
114+
115+ rewindable = subject . new ( app )
116+ rewindable . call ( request )
117+
118+ expect ( request . body ) . to be == body
119+ end
120+ end
121+
122+ with "middleware delegation" do
123+ it "should delegate make_environment to wrapped middleware" do
124+ request = Protocol ::HTTP ::Request . new (
125+ "https" , "example.com" , "POST" , "/" , "HTTP/1.1" , headers , body
126+ )
127+ env = { "rack.input" => StringIO . new }
128+
129+ middleware = Object . new
130+ mock ( middleware ) do |mock |
131+ mock . replace ( :make_environment ) do |request |
132+ env
133+ end
134+ end
135+
136+ rewindable = subject . new ( middleware )
137+ expect ( rewindable . make_environment ( request ) ) . to be == env
138+ end
139+ end
140+ end
0 commit comments