Skip to content

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

Description

@djzort

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions