crimsonpoint

мысли вслух

среда, октября 29, 2008

еще доки

Еще документация на русском по популярным перловским модулям: LWP и CGI. Спецификация на LWP поможет вам разобраться в коде прокси сервера из предыдущего поста.

понедельник, октября 27, 2008

экономим трафик - прокси на perl

Для тех, кто выходит в интернет через gprs или просто живет не в Москве или Питере и не имеет дешевой безлимитки, короче для всех, кто вынужден экономить трафик.
До вчерашнего дня я выходил в интернет через связку HandyCache + CProxy. HandyCache - это кэширующий прокси, который к тому-же можно настроить на резку банеров или другого нежелательного контента, мне он экономит около 25 процентов трафика. CProxy - это программа-клиент чешского бесплатного сервиса позволяющего уменьшить трафик за счет сжатия (если вам это ни о чем не говорит, сходите сюда). CProxy эконимит мне еще около 70 процентов от того, что пропускает HandyCache.
Беда только в том, что бесплатные сервисы типа CProxy очень тормозные. Лучший вариант - поднять свой собственный жмущий прокси, например ziproxy. Но поскольку я искал быстрое решение и заморачиваться с компиляцией ziproxy мне не хотелось, я решил поискать тоже-самое на perl. Долго искать не пришлось, на первой-же позиции в гугле оказалось то что надо. Правда, сразу у меня скрипт вылетал с ошибкой, но после небольшой доработки все заработало. Теперь наслаждаюсь скоростью по сравнению с CProxy, даже на тормозном firstvds.ru.
Нужно будет еще установить степень сжатия на максимальную и сделать возможным доступ только с определенного списка IP.
#!/usr/bin/perl -Tw
use strict;
$ENV{PATH} = join ":", qw(/usr/ucb /bin /usr/bin);
$|++;

my $VERSION_ID = q$Id: proxy,v 1.21 1998/xx/xx xx:xx:xx merlyn Exp $;
my $VERSION = (qw$Revision: 1.21 $ )[-1];

## Copyright (c) 1996, 1998 by Randal L. Schwartz
## This program is free software; you can redistribute it
## and/or modify it under the same terms as Perl itself.

### debug management
sub prefix {
my $now = localtime;

join "", map { "[$now] [${$}] $_\n" } split /\n/, join "", @_;
}
$SIG{__WARN__} = sub { warn prefix @_ };
$SIG{__DIE__} = sub { die prefix @_ };
&setup_signals();

### logging flags
my $LOG_PROC = 0; # begin/end of processes
my $LOG_TRAN = 0; # begin/end of each transaction
my $LOG_REQ_HEAD = 0; # detailed header of each request
my $LOG_REQ_BODY = 0; # header and body of each request
my $LOG_RES_HEAD = 0; # detailed header of each response
my $LOG_RES_BODY = 0; # header and body of each response

### configuration
my $HOST = 'localhost';
my $PORT = 8080; # pick next available user-port
my $SLAVE_COUNT = 8; # how many slaves to fork
my $MAX_PER_SLAVE = 20; # how many transactions per slave

### main
warn("running version ", $VERSION);

&main();
exit 0;

### subs
sub main { # return void
use HTTP::Daemon;
my %kids;

my $master = HTTP::Daemon->new(LocalPort => $PORT, LocalAddr => $HOST)
or die "Cannot create master: $!";
warn("master is ", $master->url);
## fork the right number of children
for (1..$SLAVE_COUNT) {
$kids{&fork_a_slave($master)} = "slave";
}
{ # forever:
my $pid = wait;
my $was = delete ($kids{$pid}) || "?unknown?";
warn("child $pid ($was) terminated status $?") if $LOG_PROC;
if ($was eq "slave") { # oops, lost a slave
sleep 1; # don't replace it right away (avoid thrash)
$kids{&fork_a_slave($master)} = "slave";
}
} continue { redo }; # semicolon for cperl-mode
}

sub setup_signals { # return void

setpgrp; # I *am* the leader
$SIG{HUP} = $SIG{INT} = $SIG{TERM} = sub {
my $sig = shift;
$SIG{$sig} = 'IGNORE';
kill $sig, 0; # death to all-comers
die "killed by $sig";
};
}

sub fork_a_slave { # return int (pid)
my $master = shift; # HTTP::Daemon

my $pid;
defined ($pid = fork) or die "Cannot fork: $!";
&child_does($master) unless $pid;
$pid;
}

sub child_does { # return void
my $master = shift; # HTTP::Daemon

my $did = 0; # processed count

warn("child started") if $LOG_PROC;
{
flock($master, 2); # LOCK_EX
warn("child has lock") if $LOG_TRAN;
my $slave = $master->accept or die "accept: $!";
warn("child releasing lock") if $LOG_TRAN;
flock($master, 8); # LOCK_UN
my @start_times = (times, time);
$slave->autoflush(1);
warn("connect from ", $slave->peerhost) if $LOG_TRAN;
&handle_one_connection($slave); # closes $slave at right time
if ($LOG_TRAN) {
my @finish_times = (times, time);
for (@finish_times) {
$_ -= shift @start_times; # crude, but effective
}
warn(sprintf "times: %.2f %.2f %.2f %.2f %d\n", @finish_times);
}

} continue { redo if ++$did < $MAX_PER_SLAVE };
warn("child terminating") if $LOG_PROC;
exit 0;
}

sub handle_one_connection { # return void
use HTTP::Request;
my $handle = shift; # HTTP::Daemon::ClientConn

my $request = $handle->get_request;
defined($request) or die "bad request"; # XXX

my $response = &fetch_request($request);
warn("response: <<<\n", $response->headers_as_string, "\n>>>")
if $LOG_RES_HEAD and not $LOG_RES_BODY;
warn("response: <<<\n", $response->as_string, "\n>>>")
if $LOG_RES_BODY;
$handle->send_response($response);
close $handle;
}

sub fetch_request { # return HTTP::Response
use HTTP::Response;
my $request = shift; # HTTP::Request

## XXXX needs policy here
my $url = $request->url;
warn("processing url is $url") if $LOG_TRAN;
&fetch_validated_request($request);
}

BEGIN { # local static block
my $agent; # LWP::UserAgent

sub fetch_validated_request { # return HTTP::Response
my $request = shift; # HTTP::Request

$agent ||= do {
use LWP::UserAgent;
my $agent = LWP::UserAgent->new;
$agent->agent("Mozilla/5.0");
$agent->env_proxy;
$agent;
};

$request->header('accept-encoding'=>'gzip,deflate');

warn("fetch: <<<\n", $request->headers_as_string, "\n>>>")
if $LOG_REQ_HEAD and not $LOG_REQ_BODY;
warn("fetch: <<<\n", $request->as_string, "\n>>>")
if $LOG_REQ_BODY;

my $response = $agent->simple_request($request);

my $content = $response->content;
if ($response->is_success and
$response->content_type =~ /(text|plain|html|javascript)/ and
not ($response->content_encoding || "") =~ /\S/ and
length($content)>100 and
($request->header("accept-encoding") || "") =~ /gzip/) {
require Compress::Zlib;
my $new_content = Compress::Zlib::memGzip($content);
if (defined $new_content) {
$response->content($new_content);
$response->content_length(length $new_content);
$response->content_encoding("gzip");
warn("gzipping content from ".
(length $content)." to ".
(length $new_content)) if $LOG_TRAN;
}
}

$response;
}
}

суббота, октября 25, 2008

появился релиз FireFox 3.0

На сайте мозиллы официально представлен релиз второй версии mozilla firefox. Но я пожалуй подожду версию 3.1, заодно пока и расширения все под новую версию переделают.
А вот, проверенный временем список расширений, которые у меня установлены:
  • Tab Mix Plus - ну это все знают - навороченное управление табами и сохранение сессий. Без него Фоксом пользоваться не очень удобно.
  • ImgLikeOpera - расширенное управление загрузкой картинок, тот кто считает трафик - must have.
  • CookieCuller - очень полезное расширение, позволяет ставить блок на нужные вам куки и защищать их от удаления. Таким образом почистив в очередной раз кукисы вам не нужно будет рыться в почтовых ящиках и искать пароли ко всем форумам, где вы были зарегистрированы.
  • Super DrugAndGo - позволяет посредством grug-and-drop выделенного текста открывать урлы не оформленные ссылками или выполнять поиск.
  • Paste Email - простой помошник в заполнения форм - щелкаешь в поле формы правой кнопкой мыши и выбираешь из меню то что заранее туда вписал. Удобно для хранения, паролей, емайлов и т.п.
  • Add Bookmark Here - с ним гораздо удобнее добавлять закладки сразу в нужную папку.
  • Bookmark Sync and Sort - позволяет обмениваться букмарками через ftp. С этим расширением у меня всегда одинаковые закладки на работе и дома.

четверг, октября 23, 2008

регулярные выражения в perl

Доки по regexp на русском: хорошая статья по регулярным выражениям в perl с примерами, вторая то-же про регэкспы покороче, как справочник. Все в формате pdf. Для тех, кто не в курсе - в perl всего штук пять функций для работы со строками, между тем это один из самых мощных языков по обработке текста. А все потому, что встроены регулярные выражения. Не просто доступны через библиотечные функции, а встроенны и доведены до совершенства. Пример красоты и мощи - узнал недавно про модификатор "e", который позволяет использовать в качестве подстановки исполняемый код. Вот как можно в тексте заменить каждое третье слово left на right:
$num = 0;
$text =~ s/(left).*?/if((++$num%3)== 0){'right'}else{$1}/igex;
Вот за это я люблю perl.

вторник, октября 21, 2008

Функциональное программирование

Попалась тут переводная статья, объясняющая принципы функционального программирования на примере Питона. Всем кто занимается программированием профессионально и нет, и не в курсе что такое FP советую зачитать - Функциональное программирование на языке Python. Статья написана доступно и я думаю будет полезна даже тем кто Питон не использует, как я, например. Не согласен только с двумя вещами:
  1. Автор обидел мой любимый perl, записав его в компанию языков лишенных возможности писать в стиле FP. На самом деле в perl есть все что он описывает в статье, а в рекомендациях по хорошему стилю программирования на perl всячески рекомендуют этим пользоваться, там где уместно. Большинство так и делает - 99 процентов программеров на perl напишут:
    open(IN,"<filename") or die;
    вместо
    unless(open(IN,"<filename")) {  die; }
  2. Помоему, FP использовать нужно только там, где это делает код короче и читабельней. Злоупотреблять им явно не стоит. А то что функциональный подход стоит использовать для уменьшения количества ошибок в программе, это просто бред. Сравните примеры из статьи.
    императивный код:
    xs = (1,2,3,4)
    ys = (10,15,3,22)
    bigmuls = []
    #...прочий код...
    for x in xs:
        for y in ys:
            #...прочий код...
            if x*y > 25:
                bigmuls.append((x,y))
                #...прочий код...
    #...прочий код...
    print bigmuls

    функциональный код:
    bigmuls = lambda xs,ys: filter(lambda (x,y):x*y > 25, combine(xs,ys))
    combine = lambda xs,ys: map(None, xs*len(ys), dupelms(ys,len(xs)))
    dupelms = lambda lst,n: reduce(lambda s,t:s+t, map(lambda l,n=n: [l]*n, lst))
    print bigmuls((1,2,3,4),(10,15,3,22))

    Просто очевидно какой вариант читабельней, проще пишется и проще отлаживается.

воскресенье, октября 19, 2008

купил ноутбук

Всем кто задумался о покупке дешевого ноутбука для серфинга, печати и программирования (не gamedev) рекомендую - HP nx6310 модель EY503ES. Характеристики такие - CPU Intel CM 410 (1,46GHz, 1MB L2 cash, 533MHz FSB), 15.0 XGA (1024x768), RAM 256MB DDR2 533MHz, HDD 60GB 5400rpm, DVD+/-RW, 56K Modem, 802.11b/g, OS Free DOS. Цена в Москве дешевле 700$. Поясняю - новый целик, пишущий DVD, WiFi, приличная матрица и все это дешевле 20 тысяч. Работать за ним очень приятно - не шумит, не греется, раскладка клавиатуры приближена к десктопной, ни где не скрипит, ни чего не болтается. Кроме того это все-таки HP, это вам не Acer и тем более не Rover и iRu. Минус - винды нет, нужно ставить самому, причем оказалось там есть кое-какие тонкости; диска с драйверами тоже нет. Пришлось немножко погуглить, и за вечер я все настроил.
ИМХО лучший по соотношению цена/качество бюджетный ноутбук. Вообще-то покупал я его жене, но похоже работать за ним буду сам :)

четверг, октября 16, 2008

пятница, тринадцатое

В прошлую пятницу, тринадцатого числа случилась неприятность. Сам не знаю зачем, я выгрузил фаервол (Outpost 2.0), чего никогда не делаю, потом про это благополучно забыл и вышел в интернет. Через полчаса я заметил что все как-то странно подтормаживает, и на модеме не гаснет лампочка SEND... Короче, за пол-часа в интернете я нацеплял штук 10 троянов и фиг его знает чего они успели за это время у меня стянуть. Вот тут я порадовался, что месяца два назад поставил TrueCrypt и перенес на криптованный диск базу с паролями от почтовых ящиков, аськи, вебмани, хостинга и т.п. А вот Касперский разочаровал - с только-что обновленными базами и высоким уровнем безопасности всех троянов он отловить не смог, остались два, запустившиеся как виндовые сервисы - дочищал за ним руками.
Выводы:
  1. Agnitum Outpost Firewall - вполне надежная стенка, хотя во всех обзорах по надежности стоит где-то в середине списка.
  2. Антивирус Касперского нужно или менять на что-то другое (многие хвалят NOD32), или ставить кроме KAV еще что-то типа Лавасофт Адваре.
  3. Как бы хорошо ваш комп не был защищен, всю приватную информацию нужно обязательно держать в криптованном виде. Здесь лучшее и к тому-же бесплантое решение - TrueCrypt.
  4. в пятницу тринадцатого не пользуйтесь компьютером :)

test

test