2016-04-19 16 views
0

Ich erbte Aufrechterhaltung eines selbst geschriebenen CGI-Anwendung ohne Dokumentation arbeiten und habe noch nie den Namen des Autors. Die Anwendung hat in Debian 8 nicht mehr funktioniert, aber in Debian 7 und CentOS 5 funktioniert. Die Hauptänderungen waren das Upgrade von Apache 2.2 (verwendet von Debian 7 & CentOS 5) auf Apache 2.4 (verwendet von Debian 8) und das Upgrade von perl 5,8 (in CentOS 5), die jeweils 5,14 Perl (in Debian 7) 5,20 bis perl. Der problematische Teil läuft darauf hinaus, das folgende Skript nach unten (a 302-Umleitung):302 Redirect von CGI-Skript gestoppt in Apache 2.4

#!/usr/bin/perl 
$|=1; # activate auto-flushing of stdout 
use strict; 
use warnings; 
my $CRLF = "\015\012"; 
print STDOUT "Status: 302 Moved Temporarily$CRLF" . 
      "Location: /does_not_matter$CRLF" . 
      "URI: /does_not_matter$CRLF" . 
      "Connection: close$CRLF" . 
      "Content-type: text/html; charset=UTF-8$CRLF$CRLF"; 
close STDOUT; 
while(1) { 
     sleep 1; 
} 

Das beobachtete Verhalten ist, dass die Umleitung nie so lange den Client erreicht, wie das Skript noch wenn verwendet mit laufendem Apache 2.4, aber gibt es keine Fehlermeldung in Apache's error.log. Ich änderte den Client (Firefox, Chromium, wget), das Apache-Modul (mod_cgid & mod_cgi), schickte zusätzliche Header, die close STDOUT entfernt, entfernt, um die $|=1, ersetzte den $CRLF mit \n und machte das Skript Gabel und verlassen die Elternprozess (so dass Apache nicht mehr der Elternprozess ist), alles ohne Erfolg. Die einzigen Dinge, die funktioniert: Verwenden Sie Apache 2.2, schalten Sie das Skript in eine NPH-CGI-Skript (das komplette HTTP-Header senden hat, die Apache wird nicht in irgendeiner Weise ändern, auch wenn sie Fehler enthalten), machen das Skript Exit statt eine Endlosschleife eingeben. Ich habe über tcpdump bestätigt, dass die Pakete mit der Weiterleitung den Server tatsächlich nie verlassen, bevor das Skript beendet wird. Und von der Datumszeile in der Antwort und die Zeit der eventuellen Ankunft Ich erhalte, dass Apache meine Ausgabe sofort erhält (& fügt sofort die Datumszeile zu den Headern), aber sendet nicht die Antwort an den Client .

Kümmern Sie sich nicht um Antworten, ich dachte bereits die Lösung von mir selbst und wird eine Antwort schreiben. Ich möchte nur die Lösung verfügbar für andere, die das gleiche Problem auftreten können.

Antwort

0

Das Problem war die fehlende Nachrichtentext. Eine 302-Weiterleitung kann einen Nachrichtentext enthalten (siehe RFC 2616, Abschnitt 4.3 (Nachrichtentext): "Alle anderen Antworten enthalten eine Nachricht-Körper, obwohl es von Null Länge sein kann"), sondern ein Content-Length- Zeile ist optional (Abschnitt 4.4 von RFC 2616 sagt, die Länge des Nachrichtenkörpers kann durch Schließen der Verbindung bestimmt werden, wenn die Content-Length-Zeile fehlt). Da Apache nicht wissen kann, ob ich einen Nachrichtentext senden möchte oder nicht, muss es warten bis ich die Verbindung schließe oder tatsächlich den Nachrichtentext senden (Apache 2.2 scheinbar irrtümlich hier durch nicht auf der Nachricht Körper zu warten - oder vielleicht close STDOUT; tut nicht in perl 5.20, was es in älteren perl-Versionen der Fall war). Die richtige Skript sollte daher wie folgt aussehen (verifiziert beide 2.2 in Apache zu arbeiten und in Apache 2.4) - Der einzige Unterschied ist eine zusätzliches $CRLF die einen Körper Länge Null Nachricht endet:

#!/usr/bin/perl 
$|=1; # activate auto-flushing of stdout 
use strict; 
use warnings; 
my $CRLF = "\015\012"; 
print STDOUT "Status: 302 Moved Temporarily$CRLF" . 
      "Location: /doesNotMatter$CRLF" . 
      "URI: /doesNotMatter$CRLF" . 
      "Connection: close$CRLF" . 
      "Content-type: text/html; charset=UTF-8$CRLF$CRLF$CRLF"; 
close STDOUT; 
while(1) { 
     sleep 1; 
} 

Es war https://stackoverflow.com/a/8062277/2845840 die ich in der richtigen Richtung.