Lukáš Bařinka
© 2021
REV 2.10
mod_ext_filter
modulemod_ext_filter
ExtFilterDefine lower-to-upper mode=output \
intype=text/plain outtype=text/plain \
cmd="/usr/bin/tr '[:lower:]' '[:upper:]'"
intype
attribute selects types of filtered filesouttype
attribute is necessary in case the filter changes mime-type of filtered file
<Directory "/tmp/example">
SetOutputFilter lower-to-upper
AddType text/plain .txt
</Directory>
ExtFilterDefine lower-to-upper mode=output \
intype=text/plain outtype=text/plain \
cmd="/usr/bin/tr '[:lower:]' '[:upper:]'"
intype
slouží pro omezení filtrovaných souborůouttype
je nezbytné použít v případě, že filtr mění mime-typ souboru
<Directory "/tmp/example">
SetOutputFilter lower-to-upper
AddType text/plain .txt
</Directory>
The goal is to configure output filter that will change response data using external command.
It is important the external filter is able to read data from stdin
and write data to stderr
.
The filter will process text files only.
Cílem je nakonfigurovat výstupní filtr, který bude upravovat odesílaná data pomocí externího programu.
Je potřeba aby externí filtr četl data ze stdin
a zapisoval na stderr
.
Zpracovávat bude pouze textové soubory.
tidy
program to change/correct HTML files
apt install tidy
\
characters must be escaped ⇒ "/usr/bin/tr -d '\\n'"
tidy
, který upravuje vzhled HTML souborů
apt install tidy
\
musí být escapované ⇒ "/usr/bin/tr -d '\\n'"
tr
and tidy
commands as an external filters using mod_ext_filter
directives with following names:
TR
, filter should remove all new-line characters (\n
)TIDY
TR
filter for all files with html
extension in /var/www/main/filter
directorycurl
TIDY
filter for all files with html
extension in /var/www/main/filter
directorytr
resp. tidy
jako externí výstupní filtry pomocí direktiv mod_ext_filter
pod názvy:
TR
, filtr z textu smaže všechny znaky nový řádek tj. (\n
)TIDY
/var/www/main/filter
zaregistrujte pro všechny soubory s příponou html
filtr TR
curl
/var/www/main/filter
zaregistrujte pro všechny soubory s příponou html
filtr TIDY
html
extension in /var/www/main/filter
directory/var/www/main/filter
zaregistrujte pro všechny soubory s příponou html
oba filtry
ExtFilterDefine SUM mode=output \
cmd="/usr/bin/awk '{ data[$1]+=$10; c[$1]++ } \
END { for (ip in data) print ip,c[ip],data[ip] }'"
ExtFilterDefine SORT mode=output \
cmd="/usr/bin/sort -k2rn"
SetOutputFilter SUM;SORT
There is no possibility to use a pipe in external filter “cmd1 | cmd2” (it is not a shell).
⇒ The chain of filter is a way in that case
V externím filtru nelze použít rouru “cmd1 | cmd2” (není to shell).
⇒ Je potřeba zřetězit jednotlivé filtry.
mod_cgi
= Process-based MPM (prefork)
Uses an internal mechanism to create new proccesses
mod_cgid
= Thread-based MPM (worker/event)
Forking a process with multiple threads is expensive operation
Uses an external CGI daemon to create new processes
Apache - CGI daemon communication uses Unix socket
ScriptSock
directivemod_cgi
= Procesové zpracování požadavků (prefork)
Používá interní mechanizmus vytváření procesů
mod_cgid
= Vláknové zpracování požadavků (worker/event)
Replikace procesů s více vlákny je nákladná operace
Používá externího daemona pro vytváření nových procesů
Komunikaci s externím daemonem zajišťuje socket
ScriptSock
direktivuScriptAlias
directivemod_cgid
module
LoadModule cgid_module libexec/mod_cgid.so
ScriptSock /var/run/cgisock
ScriptAlias
mod_cgid
)
LoadModule cgid_module modules/mod_cgid.so
ScriptSock /var/run/cgisock
Mime-type: application/x-httpd-cgi For backward compatibility (deprecated)
Mime-type: application/x-httpd-cgi Pro zpětnou kompatibilitu (deprecated)
ScriptAlias /cgi-bin/ /www/cgi-bin/
<Directory /www/cgi-bin/>
…
</Directory>
ScriptAliasMatch "^~([a-z0-9]+)/cgi-bin/(.*)" "/home/$1/www/cgi-bin/$2"
<DirectoryMatch "/home/[a-z0-9]+/www/cgi-bin">
Options +ExecCGI
AddHandler cgi-script .cgi .sh …
</Directory>
Content-Type: text/html
Content-Type: text/html
stdin
) in case of POST request
REQUEST_METHOD
– method of client request
CONTENT_LENGTH
– length of stdin
in bytes
stdin
) při použití metody POST
REQUEST_METHOD
– metoda požadavku
CONTENT_LENGTH
– délka stdin v bajtech
Content-Type
?Content-Type
?Forbidden
" error message is displayedInternal Server Error
" message is displayedPremature end of script headers
" – Check whether the CGI script produces response header and body separated by an empty lineForbidden
"Internal Server Error
"Premature end of script headers
" – Zkontrolujte, jestli program správně generuje hlavičku odpovědi oddělenou prázdným řádkem od těla
ScriptLog path/to/log/file
ScriptLogLength bytes
ScriptLogBuffer bytes
ScriptLog cesta/k/log/souboru
ScriptLogLength bytes
ScriptLogBuffer bytes
%% [time] request-line
%% HTTP-status CGI-script-filename
%%error
error-message
%request
HTTP request headers
POST / PUT input (when present)
%response
HTTP response headers
%stdout
CGI standard output
%stderr
CGI standard error output
%% [time] request-line
%% HTTP-status CGI-script-filename
%%error
error-message
%request
HTTP hlavičky požadavku
POST / PUT vstup (pokud existuje)
%response
HTTP hlavičky výstupu
%stdout
CGI standardní výstup
%stderr
CGI standardní chybový výstup
List of environment variables Environment of CGI script (example)
Zjištění nastavení prostředí běhu CGI skriptu
#!/bin/bash
echo "Content-type: text/plain"
echo
/usr/bin/env
DOCUMENT_ROOT /var/www/localhost/htdocs
PATH /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin…
PWD /var/www/modules/cgi-bin
SCRIPT_FILENAME /var/www/modules/cgi-bin/df.sh
REQUEST_URI /modules/cgi-bin/df.sh?dir=/tmp
SCRIPT_NAME /modules/cgi-bin/df.sh
REQUEST_METHOD POST
CONTENT_LENGTH 328
QUERY_STRING dir=/tmp
SERVER_NAME ewait
SERVER_ADDR 147.32.80.97
REMOTE_ADDR 147.32.80.98
The goal is to configure web server to execute CGI scripts. Simple script listing environment is a part of this task. It will helps you to write more meaningful scripts later.
Cílem je nakonfigurovat spouštění CGI skriptů webovým serverem. Součástí je napsání jednoduchého skriptu, který vypíše informace o systému.
mod_cgid
moduleHTTP_…
variables
curl -H "Foo-bar: baz" …
Is in variable
HTTP_FOO_BAR=baz
…?foo=bar&baz
QUERY_STRING="foo=bar&baz"
mod_cgid
)HTTP_…
curl -H "Foo-bar: baz" …
Je v proměnné
HTTP_FOO_BAR=baz
…?foo=bar&baz
QUERY_STRING="foo=bar&baz"
/var/www/cgi-bin
directory and map that directory into webspaceScriptAlias
Handler cgi-script
Beware of CGI file extension configuration
/var/www/cgi-bin
a namapujte tento adresář do webspaceScriptAlias
Handler cgi-script
Pozor na nastavení přípony CGI skriptu
mod_include
modulemod_include
Options +IncludesNoExec
Options +Includes
+Include
SSI including external command execution
INCLUDES
to search for and process SSI commands
Options +IncludesNoExec
Options +Includes
+Include
je SSI včetně vykonávání externích příkazů
INCLUDES
pro hledání a zpracování SSI příkazů
<IfModule mime_module>
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
</IfModule>
XBitHack
directive usage for directory
XBitHack On
SetOutputFilter INCLUDES
<IfModule mime_module>
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
</IfModule>
XBitHack
v adresáři
XBitHack On
SetOutputFilter INCLUDES
<!--#element attribute=value attribute=value … -->
There must be no space between <!--
and #element
!
config | sets output formats |
echo | prints out variable content |
exec | executes external command |
fsize | prints out file size |
flastmod | prints out last modification date of file |
include | includes file content |
printenv | prints out environment (all env. variables) |
set | sets variable value |
<!--#element attribute=value attribute=value … -->
Mezi <!--
a #element
nesmí být mezera!
config | nastavuje výstupní formáty |
echo | vypisuje obsah proměnných |
exec | spouští externí program |
fsize | vypisuje velikost souboru |
flastmod | vypisuje datum poslední modifikace souboru |
include | vkládá obsah souboru |
printenv | vypisuje obsah prostředí (všech proměnných) |
set | nastavuje hodnotu proměnné |
include file="..." | virtual="..."
file
File in current sub/directory, absolute path or ..
can't be usedvirtual
Web space address of a documentPATH_INFO
usage must be enabled
AcceptPathInfo On|Default
REQUEST_URI
will not change, only PATH_INFO
will change
include file="..." | virtual="..."
file
Soubor ve stejném pod/adresáři, nelze použít absolutní cestu nebo ..
virtual
Dokument s adresou ve webspace serveruPATH_INFO
AcceptPathInfo On|Default
Požadavku se nezmění REQUEST_URI
, jenom PATH_INFO
Usage of virtual
option can lead to unexpected results
E.g. request processing repetition.
An action (Action
- see later) may be called recursively because of the constant REQUEST_URI
variable value during request processing when all files (e.g. .ssi
, .s/html
, .sh
) are in one directory and mod_actions
is configured.
Použití virtual
může vést k nečekanému výsledku
Např. k opakovanému zpracování požadavku.
Když budou všechny soubory
(např .ssi
, .s/html
, .sh
) v jednom adresáři a bude nastaven mod_actions
,
může dojít k rekurzivnímu volání akce (Action
) díky stále stejné REQUEST_URI
!
<pre>
<!--#exec cmd="ls" -->
</pre>
<!--#config timefmt="%D" -->
This file was modified: <!--#echo var="LAST_MODIFIED" -->
<!--#include virtual="/footer.html" -->
DATE_LOCAL
DOCUMENT_NAME
(including pathname)DOCUMENT_URI
LAST_MODIFIED
<!--#set var="modified" value="$LAST_MODIFIED" -->
str
str1 = str2
, str1 == str2
, str1 != str2
/str2/
represents RE
Subexpressions in RE are str1 < str2
, str1 <= str2
, str1 > str2
, str1 >= str2
( condition )
, ! condition
condition1 && condition2
, condition1 || condition2
str
str1 = str2
, str1 == str2
, str1 != str2
/str2/
představuje RE
Podvýrazy v RE jsou dostupné v proměnných $1 .. $9
str1 < str2
, str1 <= str2
, str1 > str2
, str1 >= str2
( podmínka )
, ! podmínka
podmínka1 && podmínka2
, podmínka1 || podmínka2
The goal is to configure SSI when a requested source is served. That can be useful to include header/footer to content, or to generate file timestamp, and other simple cases.
Cílem je použít dynamické vkládání obsahu do poskytovaného zdroje. To se může hodit v jednoduchých příkladech vkládání hlavičky/patičky do obsahu nebo generování časových značek apod.
ab
commandab
<!--#config timefmt="%R, %B %d, %Y" -->
<!--#flastmod file=$DOCUMENT_NAME -->
<!--#exec cmd="/bin/date" -->
DATE_LOCAL
variable And set time format using timefmt
variabledate
to achieve the same resultINCLUDES
output filter for created documentsab
commandDATE_LOCAL
A nastavením formátu času pomocí timefmt
date
INCLUDES
pro vytvořený dokumentab
Watch ErrorLog
during configuration attempts
Je dobré průběžně sledovat ErrorLog
AH00082: an unknown filter was not added: INCLUDES
Load module mod_include
e.g. using
a2enmod include
AH01374: mod_include: Options +Includes (or IncludesNoExec) wasn't set,
INCLUDES filter removed: /ssi/index.html
Enable SSI for chosen directory
<Directory …>
Options +Includes
…
</Directory>
AH00082: an unknown filter was not added: INCLUDES
Načíst modul mod_include
např. pomocí
a2enmod include
AH01374: mod_include: Options +Includes (or IncludesNoExec) wasn't set,
INCLUDES filter removed: /ssi/index.html
Povolit SSI pro daný adresář
<Directory …>
Options +Includes
…
</Directory>
mod_actions
modulemod_actions
Provides CGI execution of (another) configured script instead of requested file or method
Umožňuje podle MIME typu požadovaného souboru nebo metody vykonat zvolený (jiný) CGI skript místo požadovaného souboru
ScriptAlias
directory and act like standard CGI script
LoadModule actions_module modules/mod_actions.so
<Directory "…">
# Text files wrapped inside special header and footer
Action text/plain "/actions/txt.sh" virtual
</Directory>
virtual
flag specifies whether the requested file must exist or not
If virtual
flag is not specified and requested file does not exist, the response status is 404 Not Found
If virtual
flag is specified, the action script is executed and has to deal with requested file existence by itself
ScriptAlias
a měl všechny vlastnosti CGI skriptu
LoadModule actions_module modules/mod_actions.so
<Directory "…">
# textové soubory dostanou spec. hlavičku a patičku
Action text/plain "/actions/txt.sh" virtual
</Directory>
virtual
určuje, zda soubor musí existovat
Pokud není uvedeno a soubor neexistuje, dostaneme 404 Not Found
Pokud je uvedeno, skript se vykoná a s existencí/neexistencí souboru se musí vyrovnat sám
#!/bin/bash
echo "Content-Type: text/html"
echo
echo "<h1>File: ${REDIRECT_URL}</h1><hr>"
if [ "$REQUEST_METHOD" == "POST" ]; then
QUERY_STRING="$QUERY_STRING&$( head -c $CONTENT_LENGTH )"
QUERY_STRING=${QUERY_STRING#&}
fi
if [ ! -f "${PATH_TRANSLATED}" ]; then
echo "File does not exist."
elif [ $( echo "${QUERY_STRING}" | tr '&' '\n'| grep "^full=" | tail -1 ) == "full=yes" ]; then
echo '<pre>'
cat "${PATH_TRANSLATED}"
echo "$QUERY_STRING</pre><hr>"
echo "<a href='${REDIRECT_URL}'>Display first 10 lines</a>"
echo '<form action="#" method="POST"><input type="submit" name="full" value="no">
<input type="hidden" name="foo" value="bar"></form><hr>'
else
echo "<pre>"
head "${PATH_TRANSLATED}"
echo "$QUERY_STRING</pre><hr>"
echo "<a href='${REDIRECT_URL}?full=yes'>Display full content</a>"
echo '<form action="#" method="POST"><input type="submit" name="full" value="yes">
<input type="hidden" name="foo" value="bar"></form><hr>'
fi
stat "${PATH_TRANSLATED}" | egrep "Modify:"
#!/bin/bash
echo "Content-Type: text/html"
echo
echo "<h1>Soubor: ${REDIRECT_URL}</h1><hr>"
if [ "$REQUEST_METHOD" == "POST" ]; then
QUERY_STRING="$QUERY_STRING&$( head -c $CONTENT_LENGTH )"
QUERY_STRING=${QUERY_STRING#&}
fi
if [ ! -f "${PATH_TRANSLATED}" ]; then
echo "Soubor neexistuje."
elif [ $( echo "${QUERY_STRING}" | tr '&' '\n'| grep "^full=" | tail -1 ) == "full=yes" ]; then
echo '<pre>'
cat "${PATH_TRANSLATED}"
echo "$QUERY_STRING</pre><hr>"
echo "<a href='${REDIRECT_URL}'>zobrazit pouze ukazku (10 radek)</a>"
echo '<form action="#" method="POST"><input type="submit" name="full" value="no">
<input type="hidden" name="foo" value="bar"></form><hr>'
else
echo "<pre>"
head "${PATH_TRANSLATED}"
echo "$QUERY_STRING</pre><hr>"
echo "<a href='${REDIRECT_URL}?full=yes'>zobrazit cely soubor</a>"
echo '<form action="#" method="POST"><input type="submit" name="full" value="yes">
<input type="hidden" name="foo" value="bar"></form><hr>'
fi
stat "${PATH_TRANSLATED}" | egrep "Modify:"
#!/bin/bash
echo "Content-Type: text/plain"
echo
head -c "$CONTENT_LENGTH" > "/var/www/main/upload/$REDIRECT_URL"
echo "File $REDIRECT_URL uploaded"
Script PUT /cgi-bin/upload
curl -i -X PUT --data-binary @/etc/passwd URL...txt
The goal is to create CGI script that will be executed according to request for another resource. The will be executed no matter of requested file existence. That can be useful in many cases.
Cílem je vytvořit skript, který bude spouštěn na základě požadavků bez ohledu na existenci požadovaného zdroje. To se může hodit…
text/plain
mime-typetext/plain
#!/bin/bash
[ -f "$PATH_TRANSLATED" ] || echo "Status: 404 Not Found"
echo "Content-Type: text/plain"
echo
set -x #stderr to errorlog
/usr/bin/env
if [ "$REQUEST_METHOD" = POST ]; then
echo POST DATA
head -c "$CONTENT_LENGTH"
echo
fi
[ -f "$PATH_TRANSLATED" ] && cat "$PATH_TRANSLATED"
curl -i --data="a=b" URL...txt
curl -i --data-binary @/etc/passwd URL...txt