libwww-perl / HTTP-Daemon

A simple http server class
http://metacpan.org/release/HTTP-Daemon/
Other
6 stars 16 forks source link

Setting $\ to "\n" inserts newlines in the file send with $c->send_file() or $c->send_file_response() #48

Open florian-pe opened 3 years ago

florian-pe commented 3 years ago

When you set $\ ($OUTPUT_RECORD_SEPARATOR) to anything other than "" (empty string) in the server script, the value of $\ is inserted multiple times in a file send with $c->send_file() or $c->send_file_response();

It may not be too bad for a text file but it makes a BINARY FILE corrupted and useless, a video for example.

I put an example of the server and client script that I used.

I also found the problem.

This is coming from the send_file() method. This method reads the file to be send by chunk of 8K and it prints the temporary buffer to a filehandle.

And because $\ is global, a new line is inserted on each print of HTTP::Daemon::send_file().

The SOLUTION is to put : local ($\ = ""); in the method send_file()

The reason I didn't make a pull request is because I am not sure if that is the best solution.

Would it be better to put local ($\ = ""); at the top of the package for example ?

ALSO, the same problem that I found might also impact other methods of this package because there is other methods that prints to a filehandle. And I do not know enough HTTP to decide myself.

In particular, when it concerns the CRLF "\r\n"

Those are the methods that can be possibly impacted : (because of a print to a filehandle)

I put aside methods that print to STDERR.

sub send_status_line { sub send_crlf { sub send_basic_header { sub send_header { sub send_response { sub send_redirect { sub send_error { sub send_file_response { sub send_file {

####################################################

EXAMPLE

SERVER SCRIPT

my $file = "/path/to/small/video_file.mp4";
my $port = 3000;
my $d = HTTP::Daemon->new(LocalPort => $port) || die "fail";

$\ = "\n";
print $d->url;

while (my $c = $d->accept) {
        while (my $r = $c->get_request) {
                if ($r->method eq "GET") {
                        print "got a GET request";             # the reason to set $\ to "\n"
                        # $c->send_file_response($file);
                        $c->send_file($file);
                }
        }
        $c->close;
        undef $c;
}

#################################################### CLIENT SCRIPT

my $url = "http://localhost:3000/";
my $req = HTTP::Request->new(GET => $url);
my $ua = LWP::UserAgent->new();
$ua->show_progress(1);
my $res = $ua->request($req);

open FH, ">:bytes", "response.mp4";
print FH $res->content;
close FH;

PS : Sorry for the indentation, I don't know how that works

oalders commented 3 years ago

Sorry for the indentation, I don't know how that works

Thanks for raising this issue. :) You can get indentation with a fenced code block. I edited your comment, but you can find more info here: https://docs.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks