Archive

Posts Tagged ‘programming’

HTTP сервер в одну строку: версия 2.0

August 30th, 2007

Идея с HTTP сервером на bash мне не дает покоя.

Вернуться к ней меня побудила.. попытка воспользоваться старой версией: получалсь не очень :)

Поэтому решил довести его до ума. Что-то дописал, что-то выкинул, полчилось следующее:
:;while [ $? -eq 0 ];do nc -vlp 8080 -c'(r=read;e=echo;$r a b c;z=$r;while [ ${#z} -gt 2 ];do $r z;done;f=`$e $b|sed 's/[^a-z0-9_.-]//gi'`;h="HTTP/1.0";o="$h 200 OK\r\n";c="Content";if [ -z $f ];then($e $o;ls|(while $r n;do if [ -f "$n" ]; then $e "<a href=\"/$n\">`ls -gh $n`</a><br>";fi;done););elif [ -f $f ];then $e "$o$c-Type: `file -ib $f`\n$c-Length: `stat -c%s $f`";$e;cat $f;else $e -e "$h 404 Not Found\n\n404\n";fi)';done

Теперь по URL http://ваш_ip:8080/ можно получить доступ ко всем файлам, находящимся в текущим каталоге. Очевидных и прямолинейных способов сменить каталог нет. Как и раньше, протестировано и работает под Linux, bash 3.2.13, и с хоббитовским netcat v1.10 с поддержкой опции -с (запустите netcat -h и посмотрите. Как минимум в Ubuntu, Debian и Fedora Core такая опция есть).

Теперь строка занимает 434 байт, что на 212 больше, чем прошлая версия. И мне кажется, что я с толком потратил эти байты: новый сервер обрабатывает ошибку 404, кроме того, теперь он работает без задержки, которая раньше требовалась для того, чтобы была возможность его остановить с помощью Ctrl-C. Для успешных запросов сервер отдает нормальные заголовки, с размером файла и даже с его MIME-типом. Например:

dainichi@fujitsu:~/backup$ echo "GET /6.1-RELEASE-i386-disc1.iso HTTP/1.1" | nc localhost 8080 | head -n3
HTTP/1.x 200 OK
Content-Type: application/x-iso9660
Content-Length: 529784832

Для удобства можно сохранить его в файл и написать в .bash_profile примерно следующее:alias share='sh ~/bash_httpd.sh'

Да, были попытки его еще уменьшить, но они не увенчались успехом. Есть такой вариант, но он даже больше:
w=while;d=done;e=echo;r=read;echo "true; $w [ @? -eq 0 ];do nc -vlp 8080 -c'($r a b c;f={$e @b|sed 's/[^a-z0-9_.-]//gi'{;h=}HTTP/1.x};o=}@h 200 OK#};c=}Content};if [ -z @f ];then($e @o;ls|(while $r n;do $e }@n
};done));elif [ -f @f ];then $e }@o@c-Type: {file -ib @f{#@c-Length: {stat -c%s @f{#};cat @f;else $e }@h 404 Not Found##404#};fi)';done"|tr "@{}#" '$`"
'|sh
Оставил его, потому что выглядит страшно, детей пугать – самое то :)

Если у вас получится сэкономить еще пару байтов, то милости просим в комментаторскую :)

UPD: 03.09.2007: Код обновлен, в него вошли исправления, которые сделал тов. jetxee, за которые ему большое спасибо.

UPD: 03.09.2007: Я удивлен тому факту, что эта заметка попала в топ news2, спасибо dik’у за то, что добавил ее. Я рад, что она многим показалась интересной.

UPD: 07.09.2007: Товарищ Ed очень здорово прооптимизировал код. Вот, что у него вышло:
while :;do nc -p8080 -vnlc'r=read;e="echo -e";$r a b c;while [ -n "`$e $a|tr -d "\r\n"`" ];do $r a;done;f=`$e $b|sed s/.//`;h="HTTP/1.0";z="404 Not Found\n";[ -z $f ]&&(ls|while $r n;do [ -f $n ]&&$e "$n";done)||([ -f $f ]&&($e "$h 200 OK\r\nContent-Type: `file -ib $f`\n";cat $f)||$e "$h $z\n$z")';done

Работоспособность проверялась автором на таблетке Nokia N800, а у меня в Kubuntu 7.04 что-то не заработало. Сегодня вечером буду разбираться :)

p.s. Мне теперь стыдно из-за того, что сам не догадался использовать && и || вместо if..then. :(

p.p.s. stay tuned!

UPD 18.08.2008: О, написали про это безобразие на Хабре, назвали меня извращенцем. Хулиганьё!! :)

SHELL, UNIX, tips, Программирование , , , , ,

Perl и фиксированные ключи в хеше.

July 5th, 2007

Некоторое время назад мне приходилось писать довольно большой проект на PHP. Тогда очень хотелось от хешей возможности зафиксировать множество ключей, чтобы не отлавливать по десяткам файлов опечатки в названиях полей сложных многоуровневых структур данных.

Тогда решения не нашлось. И сейчас PHP для меня лично уходит потихоньку в прошлое, т.к. в perl нахожу все больше интересных возможностей, которых раньше не хватало.
Так вот, по поводу фиксированного набора ключей, вот пример объекта на основе такого хеша:

package some;

use warnings;
use strict;
use Hash::Util qw{lock_keys};

sub new
{
my $class = shift;
my %hash;
my @keys = ("one", "two", "three", "four", "five");
my $self = bless \%hash, $class;
lock_keys %hash, @keys;
return $self;
}

1;

Теперь при выполнении инструкция $some->{‘there’} произойдет ошибка:
Attempt to access disallowed key 'there' in a restricted hash at ./test.pl line 11.

Причем сделано это не через Tie, чего я сначала опасался, а собственными средствами компилятора, т.е. должно работать очень быстро.

Но вообще-то, в каждой книге по ООП-прогрммированию обязателно замолвят слово о том, что открытые свойства класса это не очень хорошо, и что их значения предпочтительней изменять с помощью методов. А ведь их лень писать для каждой переменной!! Но хорошие языки тем и отличаются, что на них вовсе не сложно писать красиво и правильно. Смотрим, что предлагает Perl (пример из документации):


package Foo;
use base qw(Class::Accessor);
Foo->mk_accessors('foo'); # или mk_ro_accessors(qw{ one two three }) для read-only полей

my $obj = Class->new({ foo => 42 });
print $obj->foo; # 42
$obj->foo("24");
print $obj->foo; # 24

Ну вот и все! Теперь если захочется изменить поведение объекта таким образом, чтобы при изменении свойства foo, менялось также значение bar, достаточно реализовать самостоятельно нужную функцию, а править использующий класс код не нужно.

Все-таки perl язык великий и могучий, этого у него не отнять!

PERL, Программирование, общее , , ,

Hint [10]

December 23rd, 2006

[10] Все мы с пеленок знаем, что & значит запустить программу в фоновом режиме, но лично у меня случаи, когда такая форма запуска является оправданной встречаются редко. Хотя недавно я “открыл для себя” один из классов таких случаев – какие-либо действия с сетью, которые сами по себе не ресурсоемки, но могут выполняться долго вследствие больших таймаутов.

Вот так я проверяю список хвостов на “пингуемость”:

cat proxies | (IFS=”:\n”; while read ip port; do (if ping -w 1 -c 1 -q $ip>/dev/null; then echo “$ip:$port”; else echo “bad: $ip:$port”; fi)& done;) | tee proxies_pingable

В данном случае я запускаю в фоне сабшелл (if ping -w 1 -c 1 -q $ip>/dev/null; then echo “$ip:$port”; else echo “bad: $ip:$port”; fi), потому скрипт приступает к пингу следующего хоста, не дожидаясь, когда завершится проверка предыдущего. Выигрыш по времени пропорционален количеству хостов – если их 100, то практически стократный!
Правда, нужно быть аккуратным – если в списке 10 тысяч хостов, то это будет уже больше похоже на DoS.

UNIX, tips , , , ,

HTTP сервер размером в 222 байта :)

December 23rd, 2006

В продолжение предыдущей идеи с передачей файлов по HTTP. Я не удержался и написал вполне полноценный (для нужд раздачи файлов на соседний компьютер) HTTP сервер:

while true; do nc -vv -l -p 8080 -c '( read a b c; file=`echo $b | sed 's/[^a-z0-9.]//g'`; if [ a$file = "a" ]; then ( ls | (while read f; do echo "$f
"; done) ); else cat $PWD/$file; fi )'; sleep 1; done

(все это – одна команда, должна вводиться в одну строку. Тестировалось в linux/bash 3.1.17)

Вот и все :) Правда, на этот раз я опять решил отказаться от заголовков ответа, т.к. это слишком усложнит “команду”, но при желании их можно взять из предыдущего примера. Этот сервер отдает все файлы, которые есть в текущем каталоге и пытается противодействовать попыткам его сменить. В случае, если запрашивается корневая директория, то управление передается своеобразному mod_index – т.е. выводится список файлов-ссылок. В конце добавлена задержка в 1 сек для того, чтобы была возможность убить его нажатием Ctrl-C.

Воистину, netcat одна из моих любимых программ!

p.s. Кто теперь осмелится заявить, что я не извращенец? :))

UPD: немного доделал его, см новую версию

SHELL, Программирование , , , , ,

Subshell в PERL

August 9th, 2006

Моя задача сегодня – сделать так, чтобы один из скриптов имел возможность выполнять какие-либо команды на локальной или удаленной машине. Причем не просто команды, а инлайн перл- и шелл-скрипты (генерируемые на лету), причем их довольно много, а выполнять надо часто, поэтому system() и “ отпадают сразу хотя бы из соображений быстродействия.

Итак, в глубинах CPAN отыскалось следующее:

  • IPC::Open2: Вроде бы получалось запускать (в режиме неблокирующего чтения), но это довольно сложно: во-первых, надо было еще обойти все глюки с буфферизацией ввода-вывода и не наплодить при этом своих, и во-вторых у меня не получилось корректно завершить процесс – хотя бы перехватить Ctrl-C
  • Expect.pm: Практически идеальный вариант. Все программирование сводится к установке своих обработчиков на появление тех или инных сообщений от запущенной программы. В будущем я скорей всего еще воспользуюсь этим модулем, но в данном случае он не подходит, поскольку для его работы нужен отдельный pty, а этот ресурс может и не быть доступен в тех услових, в которых придется работать моей программе.
  • IPC::Session: Это обертка вокруг IPC::Open3, которая с точки зрения пользователя ведет себя как Excpect.pm – это мой выбор! Я пока не знаю, чего я лишился, отказавшись от Excpect, который работает через отдельный pty, но пока мне это кажется самым удобным вариантом. :)
  • Net::SSH::Perl: к сожалению, этот модуль не заработал на моей машине (FreeBSD 4.11) – зависает во время тестирования один из зависимых модулей. По идее, Net::SSH – это аналог open3, но работающий с удаленной консолью, а Net::SSH::Perl – это IPC::Session-подобный интерфейс. Количество зависимостей и размер Bundle::SSH устрашают, но, судя по документации – вполне подходящий вариант.

PERL, Программирование , , ,