суббота, 16 мая 2009 г.

Багфикс ns_httptime в AOLServer

Началось все с того, что обнаружил неприятную вещь - AOLServer 4.5.1 для файлов, созданных с 1-го по 10-е число любого месяца, никогда не отдает код ответа 304, а всегда заново их пересылает. Т.е. не работает кэширование, т.к. браузер сообщает, что актуальный файл в кэше есть, но сервер "не понимает". Обнаружил я эти "грабли" в процессе написания своей системы кэширования, которая еще и gzip-сжатие определенных типов файлов выполняет. Т.к. мне нужна работа в non-english локали, то я использовал debian-овский патч для ns_httptime, убирающий локалезависимость этой функции, а в нем и оказалась ошибка.
Исправленный патч можно взять здесь:

http://mobigroup.ru/files/aol4.5.1/httptime.c.diff


--- httptime.c.orig 2003-01-18 22:24:20.000000000 +0300
+++ httptime.c 2009-05-12 20:14:24.000000000 +0400
@@ -27,6 +27,9 @@
* version of this file under either the License or the GPL.
*/

+static char *weekdays_names[7] =
+{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+

/*
* time.c --
@@ -92,11 +95,14 @@
}

/*
- * This will most likely break if the locale is not an english one.
+ * Using snprintf instead of strftime to always use english names
* The format is RFC 1123: "Sun, 06 Nov 1997 09:12:45 GMT"
*/

- strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", tmPtr);
+ snprintf(buf, 40, "%s, %02d %s %d %02d:%02d:%02d GMT",
+ weekdays_names[tmPtr->tm_wday], tmPtr->tm_mday,
+ month_names[tmPtr->tm_mon], tmPtr->tm_year + 1900,
+ tmPtr->tm_hour, tmPtr->tm_min, tmPtr->tm_sec);

Ns_DStringAppend(pds, buf);
return pds->string;


Мантейнеру патч я уже отправил, а также он войдет в upstream. Как говорится, "заседание продолжается".

P.S. Ниже приведена та функция, которую я писал - для сжатия файлов с кэшированием на сервере сжатой версии (очевидно, что "на лету" сжимать статику при каждом запросе, как это делают с помощью nginx и подобных, решение явно бредовое).



# return original or gzipped file
# is used zlib module
# may cooperate with config "checkmodifiedsince" parameter
# may use fastpath cache
# config must have these sections:
#ns_section "ns/server/${servername}"
# ns_param gzipmin 512
#ns_section ns/server/dataset
# ns_param temp
proc ns_returnfilez {fname} {
if {[file isfile $fname]==0} {
ns_returnnotfound
return
}
# TODO: when file must be gzipped?
set ext [string tolower [file extension $fname]]
if {$ext eq {.html} ||
$ext eq {.htm} ||
$ext eq {.css} ||
$ext eq {.js} ||
$ext eq {.xml} ||
$ext eq {.xsl} ||
$ext eq {.docx} ||
$ext eq {.doc} ||
$ext eq {.mdb} ||
$ext eq {.xls} ||
$ext eq {.txt}
} {
set is_compress 1
} else {
set is_compress 0
}

# minimal gzipping file size set equal to config gzipping setting for ADP
set gzipmin [ns_config "ns/server/main" gzipmin]
if {[file size $fname] < $gzipmin} {
set is_compress 0
}

# TODO: check client compability
# client must send header like as "Accept-Encoding: gzip,deflate"

set mtime [file mtime $fname]

if {$is_compress == 1} {
# create hidden gzipped file in temp storage
# get temp storage path from config
set temp [ns_config "ns/server/dataset" temp]
set fname_hidden [file normalize [file join $temp www_pool .[ns_conn url]]].gz
# will create all non-existing parent directories
if {[file exists [file dirname $fname_hidden]]==0} {
file mkdir [file dirname $fname_hidden]
}
if {[file exists $fname_hidden]} {
set mtime_hidden [file mtime $fname_hidden]
# delete old gzipped file _or_ directory with same name from temp storage
if {$mtime >= $mtime_hidden} {
file delete -force $fname_hidden
}
}
}

if {$is_compress == 1} {
# send gzipped file
if {[file isfile $fname_hidden]==0} {
file copy -force $fname [file rootname $fname_hidden]
ns_zlib gzipfile [file rootname $fname_hidden]
}
ns_updateheader Content-Encoding gzip
ns_returnfile 200 [ns_guesstype $fname] $fname_hidden
} else {
# send original file
ns_returnfile 200 [ns_guesstype $fname] $fname
}
}

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


(C) Alexey Pechnikov aka MBG, mobigroup.ru