вторник, 10 марта 2009 г.

Решение проблемы с модулем CGI::Ajax при передаче символов "+" и "%"

Наткнулся на один неприятный баг в данном модуле для Perl. Например есть вот такой код:
#!/usr/bin/perl -w
use strict;
use CGI; # or any other CGI:: form handler/decoder
use CGI::Ajax;

my $cgi = new CGI;
my $pjx = new CGI::Ajax( 'exported_func' => \&perl_func );
print $pjx->build_html( $cgi, \&Show_HTML);

sub perl_func {
 return( join("<br>",@_) );
}

sub Show_HTML {
 my $html = <<EOHTML;
 <HTML>
 <BODY>
  Enter something: 
  <input type="text" id="val">
  <input type="button" onclick='exported_func(["val"],["resultdiv"])' value="Do!"/>
  <br>
  <div id="resultdiv"></div>
 </BODY>
 </HTML>
EOHTML
 return $html;
}


Так вот, если запустить этот Perl-скрипт из браузера, ввести в поле ввода "плохую" строку вроде "text % text + text", нажать кнопку "Do!" мы не увидим знака "+" в "resultdiv".

Есть решение, в нашем примере, после строки:
 my $pjx = new CGI::Ajax( 'exported_func' => \&perl_func );

нужно добавить:
 $pjx->js_encode_function('encodeURIComponent');

В таком случае, при вводе в поле "+", мы получим "+", но если добавить/заменить "+" на "%" то ничего не получим. Кроме того, браузер выдаст различные ошибки JavaScript.

Методом копания в исходниках CGI::Ajax, была обнаружено что неполадки возникают при попытке повторного раскодирования запрошенной строки. Файл /usr/share/perl5/CGI/Ajax.pm, строка 942:

<...>
 pjxInitialized : function(){},
 pjxCompleted : function(){},
 readyState4 : function(){
  var rsp = $decodefn(this.r.responseText); /* the response from perl */
  var splitval = '__pjx__'; /* to split text */
  /* fix IE problems with undef values in an Array getting squashed*/
  rsp = rsp.replace(splitval+splitval+'g',splitval+" "+splitval);
  var data = rsp.split(splitval);

<...>

В данном куске кода строка:
  var rsp = $decodefn(this.r.responseText); /* the response from perl */
должна быть заменена на:
 var rsp = this.r.responseText; /* the response from perl */

А также в нашем примере, после строки:
 my $pjx = new CGI::Ajax( 'exported_func' => \&perl_func );

нужно добавить:
 $pjx->js_encode_function('encodeURIComponent');

И ошибка будет решена! :-)