Revision f5bc2335
Von Moritz Bunkus vor mehr als 14 Jahren hinzugefügt
SL/FCGIFixes.pm | ||
---|---|---|
package SL::FCGIFixes;
|
||
|
||
use strict;
|
||
|
||
use Encode;
|
||
use FCGI;
|
||
|
||
# FCGI does not use Perl's I/O layer. Therefore it does not honor
|
||
# setting STDOUT to ":utf8" with "binmode". Also FCGI starting with
|
||
# 0.69 implements proper handling for UTF-8 flagged strings -- namely
|
||
# by downgrading them into bytes. The combination of the two causes
|
||
# Lx-Office's way of handling strings to go belly up (storing
|
||
# everything in Perl's internal encoding and using Perl's I/O layer
|
||
# for automatic conversion on output).
|
||
#
|
||
# This workaround monkeypatches FCGI's print routine so that all of
|
||
# its arguments safe for "$self" are encoded into UTF-8 before calling
|
||
# FCGI's original PRINT function.
|
||
#
|
||
# However, this must not be done if raw I/O is requested -- e.g. when
|
||
# sending out binary data. Fortunately that has been centralized via
|
||
# Locale's "with_raw_io" function which sets a variable indicating
|
||
# that current I/O operations should be raw.
|
||
|
||
sub fix_print_and_internal_encoding_after_0_68 {
|
||
return if version->parse($FCGI::VERSION) <= version->parse("0.68");
|
||
|
||
my $encoder = Encode::find_encoding('UTF-8');
|
||
my $original_fcgi_print = \&FCGI::Stream::PRINT;
|
||
|
||
no warnings 'redefine';
|
||
|
||
*FCGI::Stream::PRINT = sub {
|
||
if (!$::locale || !$::locale->raw_io_active) {
|
||
my $self = shift;
|
||
my @vals = map { $encoder->encode($_, Encode::FB_CROAK|Encode::LEAVE_SRC) } @_;
|
||
@_ = ($self, @vals);
|
||
}
|
||
|
||
goto $original_fcgi_print;
|
||
};
|
||
}
|
||
|
||
sub apply_fixes {
|
||
fix_print_and_internal_encoding_after_0_68();
|
||
}
|
||
|
||
1;
|
SL/Locale.pm | ||
---|---|---|
return $self->quote_special_chars($dst_format, $self->quote_special_chars("${src_format}-reverse", shift));
|
||
}
|
||
|
||
sub raw_io_active {
|
||
my $self = shift;
|
||
|
||
return !!$self->{raw_io_active};
|
||
}
|
||
|
||
sub with_raw_io {
|
||
my $self = shift;
|
||
my $fh = shift;
|
||
my $code = shift;
|
||
|
||
$self->{raw_io_active} = 1;
|
||
binmode $fh, ":raw";
|
||
$code->();
|
||
binmode $fh, ":utf8" if $self->is_utf8;
|
||
$self->{raw_io_active} = 0;
|
||
}
|
||
|
||
1;
|
dispatcher.fpl | ||
---|---|---|
|
||
use FCGI;
|
||
use SL::Dispatcher;
|
||
use SL::FCGIFixes;
|
||
|
||
SL::FCGIFixes::apply_fixes();
|
||
|
||
SL::Dispatcher::pre_startup();
|
||
my $request = FCGI::Request();
|
Auch abrufbar als: Unified diff
Ausgaben mit FCGI richtig codieren
Hintergrund:
FCGI benutzt Perls I/O-Schitensystem nicht. Deshalb kümmert es sich
auch nicht um mit 'binmode STDOUT, ":utf8"' gesetzte
Konvertierungsparameter. Weiterhin enthält FCGI ab Version 0.69 Fixes,
die doppeltes Encoding bei der Ausgabe vermeiden und damit eigentlich
korrektes Verhalten herstellen.
Leider geht damit Lx-Offices Art, wie Strings intern gehandhabt und
ausgegeben werden, in die Hose. Lx-Office speichert Strings in Perls
internem Encoding und verlässt sich auf die mit "binmode" aktivierte,
autoatmische Konvertierung bei der Ausgabe.
Dieser Workaround implementiert das Umcodieren vom internen Encoding
nach UTF-8 mittels Monkeypatching, bevor die FCGIs originale
PRINT-Routine aufgerufen wird.
Das darf allerdings nicht passieren, wenn unbearbeitete Ausgabe
benötigt wird -- z.B. beim Download von
Binärdaten (PDFs). Glücklicherweise ist dies in der Funktion
"with_raw_io" in Locale gekapselt, sodass dieser Workaround den Status
"unbearbeitete Ausgabe?" bei Locale erfragen kann.