form-date with newline in filename

Bill Moseley <[email protected]> Tue, 4 Jul 2017 13:41:12 -0700
Newsgroups gmane.comp.lang.perl.modules.lwp
Message-ID <CAKhN_m7EcgF+=iooTqcWx83NwreTpnWXaFrNAuj=TSOFHVWUnQ@mail.gmail.com>
--089e082162e046d0d8055383e9c6
Content-Type: text/plain; charset="UTF-8"

I'm trying to understand if the Perl code is doing the right thing by
placing a newline directly in the double-quoted filename in the
Content-Disposition header.

Even though it's probably a bad thing to do, POSIX allows newlines in
filenames. Receiving systems, of course, must be careful how that filename
is used -- but in this case it's never actually used in a filesystem (i.e.
it's just considered metadata).

The code below does a full round-trip successfully (meaning the newline in
the filename is preserved), but that's all within Perl.

I'm POSTing to a service written in Golang and that library is complaining
about malformed headers.

My question: Is HTTP::Request not escaping correctly or is Golang library
not parsing correctly?

use strict;
use warnings;
use HTTP::Request::Common;
use HTTP::Response;
use HTTP::Body;
use Data::Dumper;

my $filename = "name with\na newline";

my $req = POST(
    'http://example.com/post',
    content_type => 'form-data',
    Content => [
        file => [
            $0,
            $filename,
        ],
        one => 1,
        two => 2,
    ],
);

my $res = HTTP::Response->parse( $req->as_string );
my $body = HTTP::Body->new( join( ' ' ,$res->content_type),
$res->content_length );
$body->add( $res->decoded_content );
print Dumper $body->upload;

Above returns:

$VAR1 = {
          'file' => {
                      'filename' => 'name with
a newline',
                      'tempname' =>
'/var/folders/sz/w4rntlpx76vcy5xrp441m0qw0000gn/T/6QNv98gd5B',
                      'size' => 561,
                      'headers' => {
                                     'Content-Disposition' => 'form-data;
name="file"; filename="name with
a newline"',
                                     'Content-Type' => 'text/plain'
                                   },
                      'name' => 'file'
                    }
        };

It seems like header folding is no longer allowed, but I'm not clear that
this is a case of header-folding:

https://stackoverflow.com/questions/521275/how-to-escape-a-line-break-literal-in-the-http-header


Or asked another way, is Perl or Golang breaking Postel's law
<https://en.wikipedia.org/wiki/Robustness_principle>?


-- 
Bill Moseley
[email protected]

--089e082162e046d0d8055383e9c6
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>I&#39;m trying to understand if the Perl code is doin=
g the right thing by placing a newline directly in the double-quoted filena=
me in the Content-Disposition header.<br></div><div><br></div><div>Even tho=
ugh it&#39;s probably a bad thing to do, POSIX allows newlines in filenames=
. Receiving systems, of course, must be careful how that filename is used -=
- but in this case it&#39;s never actually used in a filesystem (i.e. it&#3=
9;s just considered metadata).=C2=A0</div><div><br></div><div>The code belo=
w does a full round-trip successfully (meaning the newline in the filename =
is preserved), but that&#39;s all within Perl.=C2=A0</div><div><br></div><d=
iv>I&#39;m POSTing to a service written in Golang and that library is compl=
aining about malformed headers.=C2=A0</div><div><br></div><div>My question:=
 Is HTTP::Request not escaping correctly or is Golang library not parsing c=
orrectly?</div><div><br></div><div><div><font face=3D"monospace, monospace"=
>use strict;</font></div><div><font face=3D"monospace, monospace">use warni=
ngs;</font></div><div><font face=3D"monospace, monospace">use HTTP::Request=
::Common;</font></div><div><font face=3D"monospace, monospace">use HTTP::Re=
sponse;</font></div><div><font face=3D"monospace, monospace">use HTTP::Body=
;</font></div><div><font face=3D"monospace, monospace">use Data::Dumper;</f=
ont></div><div><font face=3D"monospace, monospace"><br></font></div><div><f=
ont face=3D"monospace, monospace">my $filename =3D &quot;name with\na newli=
ne&quot;;</font></div><div><font face=3D"monospace, monospace"><br></font><=
/div><div><font face=3D"monospace, monospace">my $req =3D POST(</font></div=
><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 &#39;<a href=3D"htt=
p://example.com/post">http://example.com/post</a>&#39;,</font></div><div><f=
ont face=3D"monospace, monospace">=C2=A0 =C2=A0 content_type =3D&gt; &#39;f=
orm-data&#39;,</font></div><div><font face=3D"monospace, monospace">=C2=A0 =
=C2=A0 Content =3D&gt; [</font></div><div><font face=3D"monospace, monospac=
e">=C2=A0 =C2=A0 =C2=A0 =C2=A0 file =3D&gt; [</font></div><div><font face=
=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $0,</fo=
nt></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 $filename,</font></div><div><font face=3D"monospace, mono=
space">=C2=A0 =C2=A0 =C2=A0 =C2=A0 ],</font></div><div><font face=3D"monosp=
ace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 one =3D&gt; 1,</font></div><div=
><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 two =3D&gt=
; 2,</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 ],<=
/font></div><div><font face=3D"monospace, monospace">);</font></div><div><f=
ont face=3D"monospace, monospace"><br></font></div><div><font face=3D"monos=
pace, monospace">my $res =3D HTTP::Response-&gt;parse( $req-&gt;as_string )=
;</font></div><div><font face=3D"monospace, monospace">my $body =3D HTTP::B=
ody-&gt;new( join( &#39; &#39; ,$res-&gt;content_type), $res-&gt;content_le=
ngth );</font></div><div><font face=3D"monospace, monospace">$body-&gt;add(=
 $res-&gt;decoded_content );</font></div><div><font face=3D"monospace, mono=
space">print Dumper $body-&gt;upload;</font></div></div><div><br></div><div=
>Above returns:</div><div><br></div><div><div><font face=3D"monospace, mono=
space">$VAR1 =3D {</font></div><div><font face=3D"monospace, monospace">=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &#39;file&#39; =3D&gt; {</font></div><div><=
font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &#39;filename&#39; =3D&gt; &#39;name=
 with</font></div><div><font face=3D"monospace, monospace">a newline&#39;,<=
/font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &#39;tempname&#39; =
=3D&gt; &#39;/var/folders/sz/w4rntlpx76vcy5xrp441m0qw0000gn/T/6QNv98gd5B&#3=
9;,</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &#39;size&#39; =
=3D&gt; 561,</font></div><div><font face=3D"monospace, monospace">=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &#39;=
headers&#39; =3D&gt; {</font></div><div><font face=3D"monospace, monospace"=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&#39;Content-Dis=
position&#39; =3D&gt; &#39;form-data; name=3D&quot;file&quot;; filename=3D&=
quot;name with</font></div><div><font face=3D"monospace, monospace">a newli=
ne&quot;&#39;,</font></div><div><font face=3D"monospace, monospace">=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&#39;Content-Type&#39; =
=3D&gt; &#39;text/plain&#39;</font></div><div><font face=3D"monospace, mono=
space">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0},</font></div><=
div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &#39;name&#39; =3D&gt; &#39;file&=
#39;</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }</font></div><div><fo=
nt face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 };</font></div=
></div><div><br></div><div>It seems like header folding is no longer allowe=
d, but I&#39;m not clear that this is a case of header-folding:</div><div><=
br></div><blockquote style=3D"margin:0px 0px 0px 40px;border:none;padding:0=
px"><div><a href=3D"https://stackoverflow.com/questions/521275/how-to-escap=
e-a-line-break-literal-in-the-http-header">https://stackoverflow.com/questi=
ons/521275/how-to-escape-a-line-break-literal-in-the-http-header</a></div><=
/blockquote><div><br></div><div>Or asked another way, is Perl or Golang bre=
aking<a href=3D"https://en.wikipedia.org/wiki/Robustness_principle">=C2=A0P=
ostel&#39;s law</a>?</div><br clear=3D"all"><div><br></div>-- <br><div clas=
s=3D"gmail_signature">Bill Moseley<br><a href=3D"mailto:[email protected]" t=
arget=3D"_blank">[email protected]</a></div>
</div>

--089e082162e046d0d8055383e9c6--