Skip to content

Conversation

Copilot
Copy link

@Copilot Copilot AI commented Oct 9, 2025

Problem

Calling as_string() on an HTTP::Response or HTTP::Request object and then restoring it via parse() would modify the content by adding an unwanted trailing newline. This made serialization/deserialization non-commutative, causing issues when using as_string() as a means to serialize HTTP messages.

Reproduction:

use HTTP::Response;

my $r = HTTP::Response->new;
$r->content("This is a sample of content");
print $r->content;  # "This is a sample of content"

my $s = $r->as_string;
my $t = HTTP::Response->parse($s);
print $t->content;  # "This is a sample of content\n"  <- Extra newline!

The same issue affected HTTP::Request objects.

Root Cause

Both HTTP::Response::as_string() and HTTP::Request::as_string() were passing @_ to the parent class method:

return join($eol, $status_line, $self->SUPER::as_string(@_));

This caused HTTP::Message::as_string() to incorrectly detect that no explicit $eol parameter was provided (checking @_ == 1), triggering logic that appends a trailing newline to content not already ending with one.

Solution

Changed both methods to pass the $eol parameter explicitly instead of forwarding @_:

return join($eol, $status_line, $self->SUPER::as_string($eol));

This ensures HTTP::Message::as_string() correctly receives the $eol parameter and doesn't add spurious newlines.

Testing

  • Added comprehensive test suite with 18 new tests (9 for HTTP::Response, 9 for HTTP::Request)
  • All existing tests continue to pass (810 total tests passing)
  • Tests verify content preservation through serialization/deserialization with various scenarios:
    • Content without trailing newline
    • Content with trailing newline
    • Multiline content
    • Empty content
    • Explicit CRLF line endings
    • Multiple round trips

Impact

This is a minimal, surgical fix that ensures as_string() and parse() are now properly commutative, allowing HTTP::Response and HTTP::Request objects to be reliably serialized and deserialized without content corruption.

Fixes #62959

Original prompt

This section details on the original issue you should resolve

<issue_title>HTTP::Response as_string and parse not commutative [rt.cpan.org #62959]</issue_title>
<issue_description>Migrated from rt.cpan.org#62959 (status was 'new')

Requestors:

From [email protected] on 2010-11-12 23:23:29:

We have found that calling as_string on an HTTP::Response object which
is later restored via HTTP::Response->parse introduces changes in the
content of the response.

HTTP::Response v 5.813

Perl 5.10.0

OS   Debian 2.6.26-25lenny1  Linux 2.6.26 modules on AMD64

=============

Reproducing this problem is very simple. The following snippet of code
will demonstrate the problem; its output is below the next break.

use HTTP::Response; 

my $r = HTTP::Response->new; 
$r->content("This is a sample of content"); 
print "---\n",$r->content,"---\n"; 

my $s = $r->as_string; 
print "---\n", $s, "---\n"; 

my $t = HTTP::Response->parse($s); 
print "---\n", $t->content, "---\n";

=============

---
This is a sample of content---
---
000 Unknown code

This is a sample of content
---
---
This is a sample of content
---

=============

It is the opinion of myself and my colleagues that the last output
should be identical to the first.  Introducing new data into the content
stream during this operation is troublesome from the context of using
as_string as a means to serialize an HTTP::Message (specifically an
HTTP::Response, but I suspect this also applies to HTTP::Requests; but
that is not confirmed).

Without knowing why a newline is appended to the as_string results, I
cannot suggest methods of fixing this. We have a work-around in place,
but I would rather see a solution within libwww-perl than leave a
work-around in place for an extended period of time.

James Zwiers
Riverstyx Internet

</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #48


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@Copilot Copilot AI changed the title [WIP] Fix HTTP::Response as_string and parse inconsistency Fix HTTP::Response and HTTP::Request as_string/parse commutativity issue #62959 Oct 9, 2025
@Copilot Copilot AI requested a review from oalders October 9, 2025 19:35
Copilot finished work on behalf of oalders October 9, 2025 19:35
Copy link

codecov bot commented Oct 9, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.57%. Comparing base (9a985b1) to head (3f2a4c4).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #212   +/-   ##
=======================================
  Coverage   94.57%   94.57%           
=======================================
  Files          10       10           
  Lines        1254     1254           
  Branches      348      348           
=======================================
  Hits         1186     1186           
  Misses         14       14           
  Partials       54       54           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@oalders oalders marked this pull request as ready for review October 9, 2025 21:06
@oalders
Copy link
Member

oalders commented Oct 9, 2025

@eserte does this look to be correct to you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

HTTP::Response as_string and parse not commutative [rt.cpan.org #62959]
2 participants