Revision f5bc2335
Von Moritz Bunkus vor etwa 14 Jahren hinzugefügt
SL/FCGIFixes.pm | ||
---|---|---|
1 |
package SL::FCGIFixes; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use Encode; |
|
6 |
use FCGI; |
|
7 |
|
|
8 |
# FCGI does not use Perl's I/O layer. Therefore it does not honor |
|
9 |
# setting STDOUT to ":utf8" with "binmode". Also FCGI starting with |
|
10 |
# 0.69 implements proper handling for UTF-8 flagged strings -- namely |
|
11 |
# by downgrading them into bytes. The combination of the two causes |
|
12 |
# Lx-Office's way of handling strings to go belly up (storing |
|
13 |
# everything in Perl's internal encoding and using Perl's I/O layer |
|
14 |
# for automatic conversion on output). |
|
15 |
# |
|
16 |
# This workaround monkeypatches FCGI's print routine so that all of |
|
17 |
# its arguments safe for "$self" are encoded into UTF-8 before calling |
|
18 |
# FCGI's original PRINT function. |
|
19 |
# |
|
20 |
# However, this must not be done if raw I/O is requested -- e.g. when |
|
21 |
# sending out binary data. Fortunately that has been centralized via |
|
22 |
# Locale's "with_raw_io" function which sets a variable indicating |
|
23 |
# that current I/O operations should be raw. |
|
24 |
|
|
25 |
sub fix_print_and_internal_encoding_after_0_68 { |
|
26 |
return if version->parse($FCGI::VERSION) <= version->parse("0.68"); |
|
27 |
|
|
28 |
my $encoder = Encode::find_encoding('UTF-8'); |
|
29 |
my $original_fcgi_print = \&FCGI::Stream::PRINT; |
|
30 |
|
|
31 |
no warnings 'redefine'; |
|
32 |
|
|
33 |
*FCGI::Stream::PRINT = sub { |
|
34 |
if (!$::locale || !$::locale->raw_io_active) { |
|
35 |
my $self = shift; |
|
36 |
my @vals = map { $encoder->encode($_, Encode::FB_CROAK|Encode::LEAVE_SRC) } @_; |
|
37 |
@_ = ($self, @vals); |
|
38 |
} |
|
39 |
|
|
40 |
goto $original_fcgi_print; |
|
41 |
}; |
|
42 |
} |
|
43 |
|
|
44 |
sub apply_fixes { |
|
45 |
fix_print_and_internal_encoding_after_0_68(); |
|
46 |
} |
|
47 |
|
|
48 |
1; |
SL/Locale.pm | ||
---|---|---|
462 | 462 |
return $self->quote_special_chars($dst_format, $self->quote_special_chars("${src_format}-reverse", shift)); |
463 | 463 |
} |
464 | 464 |
|
465 |
sub raw_io_active { |
|
466 |
my $self = shift; |
|
467 |
|
|
468 |
return !!$self->{raw_io_active}; |
|
469 |
} |
|
470 |
|
|
465 | 471 |
sub with_raw_io { |
466 | 472 |
my $self = shift; |
467 | 473 |
my $fh = shift; |
468 | 474 |
my $code = shift; |
469 | 475 |
|
476 |
$self->{raw_io_active} = 1; |
|
470 | 477 |
binmode $fh, ":raw"; |
471 | 478 |
$code->(); |
472 | 479 |
binmode $fh, ":utf8" if $self->is_utf8; |
480 |
$self->{raw_io_active} = 0; |
|
473 | 481 |
} |
474 | 482 |
|
475 | 483 |
1; |
dispatcher.fpl | ||
---|---|---|
4 | 4 |
|
5 | 5 |
use FCGI; |
6 | 6 |
use SL::Dispatcher; |
7 |
use SL::FCGIFixes; |
|
8 |
|
|
9 |
SL::FCGIFixes::apply_fixes(); |
|
7 | 10 |
|
8 | 11 |
SL::Dispatcher::pre_startup(); |
9 | 12 |
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.