libwww-perl / libwww-perl/HTTP-Message

`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.

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

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.

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.

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.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.