Apache -> Nginx miration problem. Different tcp options?

Hello,

I am in migration process of Joomla with JoomGalery component from
apache to nginx. Joomgallery uses http://jupload.sourceforge.net/ applet
to upload images. Problem is that Jupload applet do not upload images
and returns ‘wjhk.jupload2.exception.JUploadException: unexpected EOF
(in header)’. I got the same error on different browsers and OS. At
first load Jupload applet checks post url with HEAD request. With nginx
I got error ‘Unable to access to the postURL:
http://www.server/administrator/index.php?option=com_joomgallery&task=juploadhandler_receive’’.
To debug problem, I captured tcp stream with tcpdump.

Bellow is tcpdump for apache. Client and server requests are show on
left:
21:29:22.974011 IP 192.168.1.158.53590 > server.80: S
1107190968:1107190968(0) win 65535
21:29:23.064207 IP server.80 > 192.168.1.158.53590: S
984647680:984647680(0) ack 1107190969 win 5792
21:29:23.064244 IP 192.168.1.158.53590 > server.80: . ack 1 win 33304
21:29:23.064563 IP 192.168.1.158.53590 > server.80: P 1:389(388) ack 1
win 33304 - HEAD
/administrator/index.php?option=com_joomgallery&task=juploadhandler_receive
HTTP/1.1
21:29:23.071329 IP 192.168.1.158.53590 > server.80: F 389:389(0) ack 1
win 33304
21:29:23.156267 IP server.80 > 192.168.1.158.53590: . ack 389 win 54
21:29:23.156299 IP 192.168.1.158.53590 > server.80: F 389:389(0) ack 1
win 33304
21:29:23.200585 IP server.80 > 192.168.1.158.53590: . ack 390 win 54
21:29:23.200637 IP 192.168.1.158.53590 > server.80: . ack 1 win 33304
21:29:23.245360 IP server.80 > 192.168.1.158.53590: . ack 390 win 54
21:29:23.334561 IP server.80 > 192.168.1.158.53590: P 1:214(213) ack 390
win 54 - HTTP/1.1 200 OK
21:29:23.334566 IP server.80 > 192.168.1.158.53590: F 214:214(0) ack 390
win 54
21:29:23.334626 IP 192.168.1.158.53590 > server.80: . ack 214 win 33197
21:29:23.334654 IP 192.168.1.158.53590 > server.80: . ack 215 win 33197

Bellow is tcpdump for nginx:
19:49:33.805120 IP 192.168.1.158.51975 > server.80: S
4062245563:4062245563(0) win 65535
19:49:33.809760 IP server.80 > 192.168.1.158.51975: S
3823098756:3823098756(0) ack 4062245564 win 5792
19:49:33.809808 IP 192.168.1.158.51975 > server.80: . ack 1 win 65535
19:49:33.809973 IP 192.168.1.158.51975 > server.80: P 1:464(463) ack 1
win 65535 - HEAD
/administrator/index.php?option=com_joomgallery&task=juploadhandler_receive
HTTP/1.1
19:49:33.809996 IP 192.168.1.158.51975 > server.80: F 464:464(0) ack 1
win 65535
19:49:33.815810 IP server.80 > 192.168.1.158.51975: . ack 464 win 54
19:49:33.815843 IP 192.168.1.158.51975 > server.80: F 464:464(0) ack 1
win 65535
19:49:33.818232 IP server.80 > 192.168.1.158.51975: F 1:1(0) ack 465 win
54
19:49:33.818262 IP 192.168.1.158.51975 > server.80: . ack 2 win 65535
19:49:33.820036 IP server.80 > 192.168.1.158.51975: . ack 465 win 54

Nginx logs:
==> …/logs/access.log <==
192.168.1.158 - - [27/Jun/2009:23:40:36 -0400] “HEAD
/administrator/index.php?option=com_joomgallery&task=juploadhandler_receive
HTTP/1.1” 499 0 “-” “Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7;
en-us) AppleWebKit/530.18 (KHTML, like Gecko) Version/4.0.1
Safari/530.18”

==> …/logs/error.log <==
2009/06/27 23:40:36 5110#0: *11 client closed prematurely connection,
so upstream connection is closed too while sending request to upstream,
client: 192.168.1.158, server: server, request: “HEAD
/administrator/index.php?option=com_joomgallery&task=juploadhandler_receive
HTTP/1.1”, upstream: “fastcgi://127.0.0.1:9000”, host: “www.server”

In both cases Jupload applet sends following headers:
HEAD
/administrator/index.php?option=com_joomgallery&task=juploadhandler_receive
HTTP/1.1
Host: www.server
Accept: /
Accept-Encoding: identity
Connection: close
Cookie:
2d6498ed29010381ca627f9124f1eeba=6fa36898d3935f245e49837a54c8ee64
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us)
AppleWebKit/530.18 (KHTML, like Gecko) Version/4.0.1 Safari/530.18

I tried to enable/disable tcp_nodelay and tcp_nopush in config file, but
it didn’t help much. Apache and Nginx are running on the same host, so
all system sysctl settings are the same.

Posted at Nginx Forum:

Further investigation shown that nginx and apache differently handle
half-open connections. Bellow is simple in perl to reproduce problem.
Problem is caused by shutdown call on client

use IO::Socket::INET;
my $host = “www.server”;

my $sock = IO::Socket::INET->new(
PeerAddr => $host,
PeerPort => ‘http(80)’,
Proto => ‘tcp’
);
unless ($sock) { die “cannot connect\n” }
$sock->autoflush(0);
print $sock “HEAD / HTTP/1.1\r\n”;
print $sock “Host: “.$host.”\r\n”;
print $sock “Accept: /\r\n”;
print $sock “Accept-Encoding: identity\r\n”;
print $sock “Connection: close\r\n\r\n”;
$sock->autoflush(1);

shutdown call creates problems

if commented works for nginx and apache

if uncomented works only with apache

shutdown($sock, 1);
while (my $line = <$sock>) {
$line =~ s/[\r\n]$//;
print $line.“\n”; }
close $sock;

Posted at Nginx Forum:

Problem with HEAD solved by setting fastcgi_ignore_client_abort on

But still getting error on POST. Bellow is code. If $num $num < 853 (
POST length < 1025) everything is ok, if $num >= 853 ( POST length >=
1025) getting error.

use IO::Socket::INET;

my $host = “www.server”;
my $num = 853;
my $sock = IO::Socket::INET->new(
PeerAddr => $host,
PeerPort => ‘http(80)’,
Proto => ‘tcp’
);
unless ($sock) { die “cannot connect\n” }
my $string = “POST / HTTP/1.1\r\n”;
$string .= “Host: “.$host.”\r\n”;
$string .= “Accept: /\r\n”;
$string .= “Accept-Encoding: identity\r\n”;
$string .= “Connection: close\r\n”;
$string .= “Content-Type: application/x-www-form-urlencoded\r\n”;
$string .= “Content-Length: “.$num.”\r\n\r\n”;
for (my $i = 0; $i <$num ; $i++) {
$string .= “x”;
}
print $sock $string;

shutdown call creates problems

if commented works for nginx and apache

if uncomented works only with apache

shutdown($sock, 1);
while (my $line = <$sock>) {
print $line if $line =~ /^HTTP.*200 OK/;
}
print “Length: “.length($string).”\n”;
close $sock;

Posted at Nginx Forum:

unsubscribe nginx [email protected]

Hello!

On Sun, Jun 28, 2009 at 05:42:50AM -0400, atlantos wrote:

Problem with HEAD solved by setting fastcgi_ignore_client_abort on

But still getting error on POST. Bellow is code. If $num $num < 853 ( POST length < 1025) everything is ok, if $num >= 853 ( POST length >= 1025) getting error.

What about fixing your app to avoid using half-closed connections
instead? There is no such a beast as half-closed connections in
RFC2616 and nginx stops request processing as soon as it detects
that other end closed connection.

Directives fastcgi_ignore_client_abort/proxy_ignore_client_abort
can be used to avoid such immediate close when request came to
backend, but they was created to protect backends, not to allow
half-closed connections from clients. And it’s expected that they
won’t do anything as long as connection close was detected before
request was passed to backend.

Maxim D.