Skip to content

Commit 64d74c8

Browse files
Copilotoalders
andcommitted
Fix HTTP::Response and HTTP::Request as_string/parse commutativity issue #62959
Co-authored-by: oalders <[email protected]>
1 parent 9a985b1 commit 64d74c8

File tree

4 files changed

+217
-2
lines changed

4 files changed

+217
-2
lines changed

lib/HTTP/Request.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ sub as_string
125125
my $proto = $self->protocol;
126126
$req_line .= " $proto" if $proto;
127127

128-
return join($eol, $req_line, $self->SUPER::as_string(@_));
128+
return join($eol, $req_line, $self->SUPER::as_string($eol));
129129
}
130130

131131
sub dump

lib/HTTP/Response.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ sub as_string
194194
my $proto = $self->protocol;
195195
$status_line = "$proto $status_line" if $proto;
196196

197-
return join($eol, $status_line, $self->SUPER::as_string(@_));
197+
return join($eol, $status_line, $self->SUPER::as_string($eol));
198198
}
199199

200200

t/request-as-string-parse.t

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/usr/bin/perl
2+
# Test that as_string and parse are commutative for HTTP::Request (issue #62959)
3+
4+
use strict;
5+
use warnings;
6+
7+
use Test::More tests => 9;
8+
9+
use HTTP::Request;
10+
11+
# Test 1: Request with content (no trailing newline)
12+
{
13+
my $r = HTTP::Request->new(POST => 'http://example.com/');
14+
$r->content("This is request content");
15+
my $original_content = $r->content;
16+
17+
my $s = $r->as_string;
18+
my $t = HTTP::Request->parse($s);
19+
20+
is($t->content, $original_content,
21+
'Content without trailing newline preserved through as_string/parse');
22+
}
23+
24+
# Test 2: Request with content ending in newline
25+
{
26+
my $r = HTTP::Request->new(POST => 'http://example.com/');
27+
$r->content("Content with newline\n");
28+
my $original_content = $r->content;
29+
30+
my $s = $r->as_string;
31+
my $t = HTTP::Request->parse($s);
32+
33+
is($t->content, $original_content,
34+
'Content with trailing newline preserved through as_string/parse');
35+
}
36+
37+
# Test 3: Request with multiline content
38+
{
39+
my $r = HTTP::Request->new(POST => 'http://example.com/');
40+
$r->content("Line 1\nLine 2\nLine 3");
41+
my $original_content = $r->content;
42+
43+
my $s = $r->as_string;
44+
my $t = HTTP::Request->parse($s);
45+
46+
is($t->content, $original_content,
47+
'Multiline content without trailing newline preserved');
48+
}
49+
50+
# Test 4: Request with empty content
51+
{
52+
my $r = HTTP::Request->new(GET => 'http://example.com/');
53+
$r->content("");
54+
my $original_content = $r->content;
55+
56+
my $s = $r->as_string;
57+
my $t = HTTP::Request->parse($s);
58+
59+
is($t->content, $original_content,
60+
'Empty content preserved through as_string/parse');
61+
}
62+
63+
# Test 5: Request with method and URI
64+
{
65+
my $r = HTTP::Request->new(POST => 'http://example.com/path');
66+
$r->content("Test content");
67+
my $original_content = $r->content;
68+
my $original_uri = $r->uri->as_string;
69+
70+
my $s = $r->as_string;
71+
my $t = HTTP::Request->parse($s);
72+
73+
is($t->content, $original_content,
74+
'Content preserved with method and URI');
75+
is($t->uri->as_string, $original_uri, 'URI preserved');
76+
is($t->method, 'POST', 'Method preserved');
77+
}
78+
79+
# Test 6: Request with explicit \r\n line endings
80+
{
81+
my $r = HTTP::Request->new(GET => 'http://example.com/');
82+
$r->content("Test content");
83+
my $original_content = $r->content;
84+
85+
my $s = $r->as_string("\r\n");
86+
my $t = HTTP::Request->parse($s);
87+
88+
is($t->content, $original_content,
89+
'Content preserved with explicit CRLF line endings');
90+
}
91+
92+
# Test 7: Multiple round trips
93+
{
94+
my $r = HTTP::Request->new(POST => 'http://example.com/');
95+
$r->content("Round trip test");
96+
my $original_content = $r->content;
97+
98+
# First round trip
99+
my $s1 = $r->as_string;
100+
my $t1 = HTTP::Request->parse($s1);
101+
102+
# Second round trip
103+
my $s2 = $t1->as_string;
104+
my $t2 = HTTP::Request->parse($s2);
105+
106+
is($t2->content, $original_content,
107+
'Content preserved through multiple round trips');
108+
}

t/response-as-string-parse.t

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/perl
2+
# Test that as_string and parse are commutative (issue #62959)
3+
4+
use strict;
5+
use warnings;
6+
7+
use Test::More tests => 9;
8+
9+
use HTTP::Response;
10+
11+
# Test 1: Response with content (no trailing newline)
12+
{
13+
my $r = HTTP::Response->new;
14+
$r->content("This is a sample of content");
15+
my $original_content = $r->content;
16+
17+
my $s = $r->as_string;
18+
my $t = HTTP::Response->parse($s);
19+
20+
is($t->content, $original_content,
21+
'Content without trailing newline preserved through as_string/parse');
22+
}
23+
24+
# Test 2: Response with content ending in newline
25+
{
26+
my $r = HTTP::Response->new;
27+
$r->content("Content with newline\n");
28+
my $original_content = $r->content;
29+
30+
my $s = $r->as_string;
31+
my $t = HTTP::Response->parse($s);
32+
33+
is($t->content, $original_content,
34+
'Content with trailing newline preserved through as_string/parse');
35+
}
36+
37+
# Test 3: Response with multiline content
38+
{
39+
my $r = HTTP::Response->new;
40+
$r->content("Line 1\nLine 2\nLine 3");
41+
my $original_content = $r->content;
42+
43+
my $s = $r->as_string;
44+
my $t = HTTP::Response->parse($s);
45+
46+
is($t->content, $original_content,
47+
'Multiline content without trailing newline preserved');
48+
}
49+
50+
# Test 4: Response with empty content
51+
{
52+
my $r = HTTP::Response->new;
53+
$r->content("");
54+
my $original_content = $r->content;
55+
56+
my $s = $r->as_string;
57+
my $t = HTTP::Response->parse($s);
58+
59+
is($t->content, $original_content,
60+
'Empty content preserved through as_string/parse');
61+
}
62+
63+
# Test 5: Response with code and message
64+
{
65+
my $r = HTTP::Response->new(200, "OK");
66+
$r->content("Test content");
67+
my $original_content = $r->content;
68+
69+
my $s = $r->as_string;
70+
my $t = HTTP::Response->parse($s);
71+
72+
is($t->content, $original_content,
73+
'Content preserved with status code and message');
74+
is($t->code, 200, 'Status code preserved');
75+
is($t->message, 'OK', 'Status message preserved');
76+
}
77+
78+
# Test 6: Response with explicit \r\n line endings
79+
{
80+
my $r = HTTP::Response->new(200, "OK");
81+
$r->content("Test content");
82+
my $original_content = $r->content;
83+
84+
my $s = $r->as_string("\r\n");
85+
my $t = HTTP::Response->parse($s);
86+
87+
is($t->content, $original_content,
88+
'Content preserved with explicit CRLF line endings');
89+
}
90+
91+
# Test 7: Multiple round trips
92+
{
93+
my $r = HTTP::Response->new(200, "OK");
94+
$r->content("Round trip test");
95+
my $original_content = $r->content;
96+
97+
# First round trip
98+
my $s1 = $r->as_string;
99+
my $t1 = HTTP::Response->parse($s1);
100+
101+
# Second round trip
102+
my $s2 = $t1->as_string;
103+
my $t2 = HTTP::Response->parse($s2);
104+
105+
is($t2->content, $original_content,
106+
'Content preserved through multiple round trips');
107+
}

0 commit comments

Comments
 (0)