Пишу здесь чтобы не забыть. Сейчас XML-RPC довольно популярен, и как показывает практика мало кто, например из интернет-магазинов, использует его в чистом виде. В основном ресурсы, где выходной XML довольно большой, любят сжимать его Zlib’ом и после чего этот бинарник шифровать base64, а-ля он вовсе и не бинарник.
XML-RPC
Для XML-RPC в Ruby замечательная библиотека с одноименным названием XMLRPC.
И для примера рассмотрим как ей пользоватся:
1 2 3 4 5 6 7 8 9 | require 'xmlrpc/client' XMLRPC::Client.class_eval do def parse_content_type(a) ['text/xml'] end end client = XMLRPC::Client.new2("http://site.ru/xml") result = client.call("xmlrpc.cmd") |
Перегрузка parse_content_type
нужна для того, чтобы Ruby не смущался, когда заголовок у выходного документа не text/xml
. Об этой штуке я прочитал на http://blog.alno.name/ru/2009/03/xmlrpc-in-ruby.
Если для XML-RPC нужна базовая авторизация, то используем
1 | client = XMLRPC::Client.new3("http://site.ru/xml",'login','pass') |
Однако, на моем опыте не было случаев с базовой авторизацией в XML-RPC. Часто встречалось, что логин и пароль сували как параметры в сам запрос т.е. они были как параметры в запросном XML:
1 | result = client.call("xmlrpc.cmd",'login','pass') |
На этом, если в ресурсе нет больше никаких примочек, в result
будет уже хэш.
base64
Теперь рассмотрим вариант, если выходной XML зашифрован base64. Расшифровывать его можно так:
1 2 | require 'base64' puts Base64.decode64(result) |
Однако, это не единственный вариант т.к. в библиотеке XMLRPC есть тоже класс для этого.
Приведу еще пример, как вывести зашифрованный XML во временный файл, предварительно расшифровав.
1 2 3 4 5 6 | require 'base64' require 'tempfile' fl=Tempfile.new('xmlrpc') fl.print Base64.decode64(result) fl.close |
gzip
Как правило base64 просто так не используют т.к. с точки зрения криптографии он не реализует никакой стоящей защиты данных, а для приведения бинарника к текстовом виду он как раз подойдет.
В Zlib существует 2 метода для сжатия и распаковки строки:
Zlib::Deflate.deflate(string, level)
– сжатиеZlib::Inflate.inflate(string)
– распаковка
Все было бы очень легко и просто, но к сожалению, Zlib::Inflate.inflate(string) не вернет нам распакованный XML-RPC ответ, единственное, что вы увидите:
1 | `inflate': incorrect header check (Zlib::DataError) |
Собственно, поэтому нам и потребовалось записать расшифрованный base64 XML во временный файл, чтобы распаковать gzip другим способом:
1 2 3 4 5 6 7 8 9 | require 'zlib' include Zlib ... fl=Tempfile.new('xmlrpc') fl.print Base64.decode64(result) fl.close xmlrpc='' Zlib::GzipReader.open(fl.path) {|gz| xmlrpc=gz.read} fl.close(true) |
fl.close(true)
с флагом true
удаляет временный файл.
получение хэша их XML
Вообще, существует миллион двести различных библиотек и классов для расхэширования XML, но я не буду проводить исследования и воспользуюсь, пусть и не самым быстрым, зато стандартным REXML.
1 2 3 4 | require 'rexml/document' include REXML ... xml=Document.new xmlrpc |
Все, теперь в переменной xml
лежит хэш.