среда, апреля 02, 2008

Неправильный POST через LWP

Писал я тут небольшое приложение и написал к нему тест на perl - с помощью LWP посылал POST запрос ну и соответственно проверял реакцию. Реакция оказалась неправильной, но при этом если я руками через firefox слал то же самое то всё замечательно работало. Побайтно сравнив посылаемое в обоих случаях - обнаружил что perl не эскейпит символ "!", т.е. посылает как есть, а firefox как %21. Полез искать почему так - нашёл что в итоге вызывается query_form (в URI::_query) который соответственно вызывает метод query такой:

sub query
{
my $self = shift;
$$self =~ m,^([^?\#]*)(?:\?([^\#]*))?(.*)$,s or die;

if (@_) {
my $q = shift;
$$self = $1;
if (defined $q) {
$q =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go;
$$self .= "?$q";
}
$$self .= $3;
}
$2;
}


Т.е. эскейпится всё кроме символов в $URI::uric. Полез смотреть что там прописано:

$reserved = q(;/?:@&=+$,[]);
$mark = q(-_.!~*'()); #'; emacs
$unreserved = "A-Za-z0-9\Q$mark\E";
$uric = quotemeta($reserved) . $unreserved . "%";


Т.к. "!" в $mark то он тоже не преобразуется. Полез смотреть стандарты в rfc1866 сказано следующее:
The form field names and values are escaped: space
characters are replaced by `+', and then reserved characters
are escaped as per [URL]; that is, non-alphanumeric
characters are replaced by `%HH', a percent sign and two
hexadecimal digits representing the ASCII code of the
character. Line breaks, as in multi-line text field values,
are represented as CR LF pairs, i.e. `%0D%0A'.


Тут конечно можно задуматся входит "!" в alphanumeric или нет, но rfc2396 рассеивает все сомнения:
alpha = lowalpha | upalpha

lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
"j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
"s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"

upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
"J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
"S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"

digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
"8" | "9"

alphanum = alpha | digit


Т.е. firefox прав, а lwp нет. В принципе lwp вообще непонятно зачем form_query в POST вызывает - оно не для этого. Ну ладно - это всё лирика...

Поправить дело можно относительно легко - исправить $URI::uric на то что нужно перед POST, а потом обратно. Заменить можно например так: $URI::uric = quotemeta("=&+")."A-Za-z0-9"; . Но возможно(скорей всего) я тут что-то не учёл - просто для моего теста это сработало, а всесторонне исследовать - времени нет.

Всё-таки LWP написан очень плохо - в который раз убеждаюсь. Зачитать про другой баг LWP.

Комментариев нет: