`request_type_with_data` sets `Content-Type: application/x-www-form-urlencoded` even when no body is provided

Open Beginner friendly
#227 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
82/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
perl
Domain
networking

Research direction

Read lib/HTTP/Request/Common.pm, focusing on request_type_with_data and the _simple_req behavior described in the issue. Use the bodyless OPTIONS example to verify that Content-Type is not set without content, while requests with content still receive the resolved type and Content-Length remains handled as described.

Written by the indexing model from the issue text.

Description

Description

request_type_with_data (used by POST, PUT, PATCH, and OPTIONS) unconditionally sets a Content-Type header to application/x-www-form-urlencoded even when no body content is supplied.

In lib/HTTP/Request/Common.pm:

sub request_type_with_data {
    my $type = shift;
    my $url  = shift;
    my $req = HTTP::Request->new($type => $url);
    my $content;
    $content = shift if @_ and ref $_[0];
    my($k, $v);
    while (($k,$v) = splice(@_, 0, 2)) {
        if (lc($k) eq 'content') {
            $content = $v;
        }
        else {
            $req->push_header($k, $v);
        }
    }
    my $ct = $req->header('Content-Type');
    unless ($ct) {
        $ct = 'application/x-www-form-urlencoded';   # default
    }
    elsif ($ct eq 'form-data') {
        $ct = 'multipart/form-data';
    }

    # ... content encoding ...

    $req->header('Content-Type' => $ct);              # always set
    if (defined($content)) {
        $req->header('Content-Length' =>
                     length($content)) unless ref($content);
        $req->content($content);
    }
    else {
        $req->header('Content-Length' => 0);
    }
    $req;
}

Content-Type is resolved before checking whether $content is defined, and the assignment at the end is unconditional.

Impact

For HTTP methods that commonly have no body (e.g. OPTIONS without a body), a caller doing:

use HTTP::Request::Common;
my $req = OPTIONS 'http://example.com';

receives a request with:

  • Content-Type: application/x-www-form-urlencoded
  • Content-Length: 0

Neither header is meaningful for a bodyless OPTIONS request.

Suggested fix

Move the Content-Type assignment inside the if (defined($content)) block so it only applies when there is actual content to describe:

if (defined($content)) {
    $req->header('Content-Type' => $ct);
    $req->header('Content-Length' =>
                 length($content)) unless ref($content);
    $req->content($content);
}
else {
    $req->header('Content-Length' => 0);
}

This would make request_type_with_data consistent with _simple_req (used by GET, HEAD, DELETE), which does not set Content-Type at all.

Dominant language
Perl
Stars
32
Forks
63
Avg merge
5h 14m
Merged PRs (30d)
1

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from libwww-perl/HTTP-Message

All issues in libwww-perl/HTTP-Message

Similar issues

More Perl issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.