gpt4 book ai didi

linux - 文件大小超过 60K 时文件上传失败

转载 作者:塔克拉玛干 更新时间:2023-11-01 19:08:17 24 4
gpt4 key购买 nike

我一直在努力使内部应用程序不再使用 FTP,因为安全团队已告诉我们停止使用 FTP。所以我一直在使用 HTTP 上传,并且在大多数情况下效果很好。我们的环境是 Linux、HP-UX、Solaris 和 AIX 的混合体。在我们的 Linux 服务器上,curl 是普遍可用的,所以我一直在使用 curl 的 POST 功能进行上传,而且效果很好。不幸的是,Unix 机器很少有 curl,甚至是 wget,所以我用 perl 写了一个 GET 脚本,它运行良好,而我为 perl 编写的 POST 脚本(从网络上的其他地方提取和改编)在 Unix 上运行得非常好,直到上传的数据大于大约 60K(顺便说一句,curl 在 Linux 中处理得很好)。除此之外,Apache 错误日志开始吐出:

CGI.pm: Server closed socket during multipart read (client aborted?).

当我使用 curl 上传时,从未发生过这样的错误。这是我的 POST 脚本,使用 Socket,因为 LWP 并非在每个服务器上都可用,而且在任何 Unix 服务器上根本不可用。

#!/usr/bin/perl -w

use strict;
use Socket;

my $v = 'dcsm';
my $upfile = $ARGV[0] or die 'Upload File not found or not specified.' . "\n";
my $hostname = $ARGV[1] or die 'Hostname not specified.' . "\n";
$| = 1;

my $host = "url.mycompany dot com";
my $url = "/csmtar.cgi";
my $start = times;
my ( $iaddr, $paddr, $proto );
$iaddr = inet_aton($host);
$paddr = sockaddr_in( 80, $iaddr );
$proto = getprotobyname('tcp');

unless ( socket( SOCK, PF_INET, SOCK_STREAM, $proto ) ) {
die "ERROR : init socket: $!";
}
unless ( connect( SOCK, $paddr ) ) {
die "no connect: $!\n";
}

my $length = 0;

open( UH, "< $upfile" ) or warn "$!\n";
$length += -s $upfile;
my $boundary = 'nn7h23ffh47v98';

my @head = (
"POST $url HTTP/1.1",
"Host: $host",
"User-Agent: z-uploader",
"Content-Length: $length",
"Content-Type: multipart/form-data; boundary=$boundary",
"",
"--$boundary",
"Content-Disposition: form-data; name=\"hostname\"",
"",
"$hostname",
"--$boundary",
"Content-Disposition: form-data; name=\"ren\"",
"",
"true",
"--$boundary",
"Content-Disposition: file; name=\"filename\"; filename=\"$upfile\"",
"--$boundary--",
"",
"",
);

my $header = join( "\r\n", @head );
$length += length($header);
$head[3] = "Content-Length: $length";
$header = join( "\r\n", @head );
$length = -s $upfile;
$length += length($header);

select SOCK;
$| = 1;

print SOCK $header;

while ( sysread( UH, my $buf, 8196 ) ) {
if ( length($buf) < 8196 ) {
$buf = $buf . "\r\n--$boundary";
syswrite SOCK, $buf, length($buf);
} else {
syswrite SOCK, $buf, 8196;
}
print STDOUT '.',;
}

close UH;

shutdown SOCK, 1;

my @data = (<SOCK>);
print STDOUT "result->@data\n";
close SOCK;

有人看到让他们兴奋的东西吗?

更新:

我进行了以下更新,错误似乎没有变化。

为了解决内容长度问题,并尝试消除在附加最终边界之前循环等于确切字符数的可能性,我更新了以下代码。

my $boundary = 'nn7h23ffh47v98';
my $content = <<EOF;
--$boundary
Content-Disposition: form-data; name="hostname"

$hostname
--$boundary
Content-Disposition: file; name="filename"; filename="$upfile"
--$boundary--


EOF

$length += length($content);
my $header = <<EOF;
POST $url HTTP/1.1
Host: $host
User-Agent: z-uploader
Content-Length: $length
Content-Type: multipart/form-data; boundary=$boundary

EOF

$header .= $content;
select SOCK;
$| = 1;

print SOCK $header;

my $incr = ($length + 100) / 20;
$incr = sprintf("%.0f", $incr);

while (sysread(UH, my $buf, $incr )) {
syswrite SOCK, $buf, $incr;
}
syswrite SOCK, "\n--$boundary", $incr;

最佳答案

您是在通过查看代码询问是否有“跳出的东西”。

我突然想到两件事:

1) POST HTTP 消息中的 Content-Length 参数指定 HTTP 消息实体部分的确切字节数。参见 RFC 2616 的第 4.4 节.

您正在将 Content-Length: header 设置为您正在上传的文件的确切大小。不幸的是,除了文件本身,您还发送了 MIME header 。

HTTP 消息的“实体”部分,如 RFC 2616 所定义,基本上由 HTTP 消息 header 最后一个 header 后面的空行之后的所有内容组成。 低于该点的所有内容 都必须包含在 Content-Length: header 中。 Content-Length header 不是您要上传的文件的大小,而是跟在 header 后面的 HTTP 消息的整个实体部分的大小。

2) 忽略损坏的 Content-Length: header ,如果文件大小恰好是 8196 字节的整数倍,您正在构建的 MIME 文档很可能已损坏。您最后一次调用 sysread() 将获得文件中的最后 8196 个字节,您可以愉快地复制它,下一次调用 sysread() 将返回 0,并且您将终止循环,而不会发出尾随边界分隔符。 MIME 文档将损坏。

关于linux - 文件大小超过 60K 时文件上传失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27475994/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com