[ Россум, Дрейк, Откидач ] Язык программирования Python
.pdf26.1. rexec — основные средства настройки защищенного режима |
351 |
rexec Основные средства настройки защищенного режима.
Bastion Ограничивает доступ к экземпляру класса.
26.1rexec — основные средства настройки защищенного режима
Этот модуль определяет класс RExec, предоставляющий методы r_eval(), r_execfile(), r_exec() и r_import(), являющиеся ограниченными версиями встроенных функций eval() и execfile() и инструкций exec и import. Код, выполняемый в созданном этим классом окружении, имеет доступ только к модулям и функциям, которые считаются безопасными. Вы можете определить производный от RExec класс, если необходимо добавить или убрать какие-либо возможности.
Заметим, что класс RExec предотвращает использование кодом опасных операций (например, чтение и запись файлов или использование сетевых соединений), но не может защитить от использования слишком большого количества памяти или процессорного времени.
RExec([hooks [, verbose]])
Создает и возвращает объект, предоставляющий окружение с ограниченными возможностями. Аргумент hooks должен быть экземпляром RHooks (в настоящий момент не документирован) или производного от него класса, который реализует загрузку модулей. Если аргумент hooks опущен или равен None, автоматически создается новый экземпляр (используются аргументы по умолчанию). Если задан и является истиной аргумент verbose, на стандартный поток вывода будет выводиться отладочная информация.
Используя альтернативный объект в качестве аргумента hooks, Вы можете обеспечить переадресацию запросов к файловой системе через механизм RPC (Remote Procedure Call) или реализовать загрузку модулей с определенного URL (как это сделано в браузере Grail).
Класс RExec имеет следующие атрибуты, которые используются при создании экземпляра. Присваивание новых значений одноименным атрибутам экземпляра не окажет никакого влияния. Присваивание следует проводить атрибутам производного класса в его определении (но не в конструкторе). Все эти атрибуты являются кортежами из строк.
nok_builtin_names
Имена встроенных функций, которые не будут доступны в защищенном режиме. Для класса RExec это ‘(’open’, ’reload’, ’__import__’)’. Добавлять имена в производных классах следует следующим способом:
352 |
Глава 26. Выполнение в защищенном режиме |
class MyRExec(RExec):
...
nok_builtin_names = RExec.nok_builtin_names +
Это позволит избежать неприятностей, если в будущих версиях языка будут добавлены новые опасные функции.
ok_builtin_modules
Имена встроенных и динамически подгружаемых модулей, использование которых безопасно. Для класса RExec это ‘(’audioop’, ’array’, ’binascii’, ’cmath’, ’errno’, ’imageop’, ’marshal’, ’math’, ’md5’, ’operator’, ’parser’, ’regex’, ’pcre’, ’rotor’, ’select’, ’strop’, ’struct’, ’time’)’.
ok_path
Каталоги, в которых будет производиться поиск модулей при импортировании в защищенном режиме. Для класса RExec берется значение sys.path на момент инициализации модуля rexec.
ok_posix_names
Имена, определенные в модуле os, которые будут доступны в защищенном режиме. Для класса RExec это ‘(’error’, ’fstat’, ’listdir’, ’lstat’, ’readlink’, ’stat’, ’times’, ’uname’, ’getpid’, ’getppid’, ’getcwd’, ’getuid’, ’getgid’, ’geteuid’, ’getegid’)’.
ok_sys_names
Имена, определенные в модуле sys, которые будут доступны в защищенном режиме. Для класса RExec это ‘(’ps1’, ’ps2’, ’copyright’, ’version’, ’platform’, ’exit’, ’maxint’)’.
Экземпляры класса RExec поддерживают следующие методы. Отличие методов с приставками ‘r_’ и ‘s_’ состоит в том, что последние после выполнения кода восстанавливают исходные значения переменных sys.stdin, sys.stderr и sys.stdout в созданном окружении.
r_eval(code)
s_eval(code)
Вычисляет и возвращает значение выражения языка Python, представленного строкой или объектом кода code. Вычисление производится в модуле __main__ созданного окружения.
r_exec(code) s_exec(code)
Выполняет в модуле __main__ созданного окружения инструкции языка Python, представленные строкой или объектом кода code.
26.1. rexec — основные средства настройки защищенного режима |
353 |
r_execfile(filename)
s_execfile(filename)
Выполняет в модуле __main__ созданного окружения код языка Python, содержащийся в файле filename.
Класс RExec также определяет следующие методы, которые неявно вызываются при выполнении кода в защищенном режиме. Вы можете переопределить их в производном классе, чтобы изменить накладываемые ограничения (достаточно переопределить метод с приставкой ‘r_’).
r_import(modulename [, globals [, locals [, fromlist]]])
s_import(modulename [, globals [, locals [, fromlist]]])
Этот метод используется вместо встроенной функции __import__() (см. главу 12) для импортирования модуля. Должен генерировать исключение ImportError, если считается небезопасным.
r_open(filename [, mode [, bufsize]]) s_open(filename [, mode [, bufsize]])
Этот метод используется вместо встроенной функции open() (см. главу 12). По умолчанию метод r_open() позволяет открыть любой файл только для чтения (режимы ’r’ и ’rb’). Смотрите пример в конце раздела, реализующий метод r_open() с меньшими ограничениями.
r_reload(module) s_reload(module)
Этот метод используется вместо встроенной функции reload() (см. главу 12) для перезагрузки модуля.
r_unload()
s_unload()
Вы можете использовать эти методы для выгрузки модуля (удаления его из словаря sys.modules созданного окружения).
Приведем пример класса, позволяющего открывать файлы на запись в каталоге ‘/tmp’:
from rexec import RExec
from os.path import normpath, islink
class TmpWriterRExec(RExec):
def r_open(self, file, mode=’r’, bufsize=-1): if mode not in (’r’, ’rb’):
file = normpath(file)
354 |
Глава 26. Выполнение в защищенном режиме |
if file[:5]!=’/tmp/’ or islink(file): raise IOError(
"Can’t write outside /tmp") return open(file, mode, bufsize)
26.2Bastion — ограничение доступа к экземплярам классов
Этот модуль предназначен для использования совместно с модулем rexec и предоставляет возможность запретить доступ ко всем атрибутам данных и небезопасным методам экземпляра класса.
Bastion(object [, filter [, name [, bastionclass]]])
Возвращает экземпляр класса bastionclass (по умолчанию используется BastionClass), который ведет себя аналогично объекту object, но предоставляет доступ только к методам, для имен attr_name которых filter(attr_name) является истиной. Функция filter, используемая по умолчанию, запрещает доступ к методам, имена которых начинаются с символа подчеркивания (‘_’). При попытке доступа к атрибутам данных или запрещенным методам генерируется исключение AttributeError. Строковым представлением (результатом применения встроенной функции repr() или при заключении в обратные кавычки) защищенного объекта будет ’<Bastion for name>’. Если аргумент name опущен или равен None, вместо name используется repr(object).
BastionClass(getfunc, name)
Этот (или производный от него) класс используется в качестве аргумента bastionclass функции Bastion() и реализует защиту объекта. Аргумент getfunc должен быть функцией (тип function), возвращающей значение атрибута с именем, переданным в качестве единственного аргумента, если атрибут считается безопасным, и генерирующей исключение AttributeError, если доступ к атрибуту запрещен. Аргумент name используется при конструировании строкового представления объекта.
355
Глава 27
Поддержка протоколов Internet
Стандартная библиотека предоставляет набор модулей, осуществляющих поддержку большинства распространенных протоколов Internet. Мы остановимся лишь на наиболее часто используемых — тех, которые предоставляют интерфейс высокого уровня.
cgi Протокол CGI (общий шлюзовой интерфейс), используемый для интерпретации форм HTML на стороне сервера.
urllib Чтение произвольных ресурсов по URL.
urlparse Операции над URL.
27.1cgi — протокол CGI
Этот модуль предоставляет средства, которые будут полезны при написании программ, использующих интерфейс CGI (Common Gateway Interface, общий шлюзовой интерфейс), на языке Python.
27.1.1 Введение
CGI-программа вызывается HTTP-сервером, обычно для обработки данных, переданных пользователем через элементы ‘<FORM>’ и ‘<ISINDEX>’ языка HTML. HTTP-сервер помещает информацию о запросе (имя узла клиента, запрашиваемый URL, строка параметров запроса и др.) в переменные окружения программы, выполняет программу и пересылает клиенту его вывод. Часть данных от клиента может также поступать на стандартный поток ввода программы. Модуль cgi берет на себя заботу обо всех возможных способах передачи данных и предоставляет их программе через простой интерфейс. Модуль также предоставляет набор средств, которые будут полезны при отладке.
Вывод CGI-программы должен состоять из двух частей, разделенных пустой строкой. Первая часть содержит набор заголовков, которые описывают тип данных, следующих во втором разделе. Простейшая программа может выглядеть следующим образом:
# ъБЗПМПЧПЛ: ДБМЕЕ УМЕДХЕФ HTML-ДПЛХНЕОФ print "Content-Type: text/html"
356 |
Глава 27. Поддержка протоколов Internet |
#рХУФБС УФТПЛБ: ЛПОЕГ ЪБЗПМПЧЛПЧ print
#чФПТБС ЮБУФШ: HTML-ДПЛХНЕОФ print "<html>"
print "<title>чЩЧПД CGI-РТПЗТБННЩ</title>" print "<body>"
print "<h1>ьФП НПС РЕТЧБС CGI-РТПЗТБННБ</h1>" print "рТЙЧЕФ ЧУЕНХ НЙТХ!"
print "</body>" print "</html>"
27.1.2 |
Использование модуля cgi |
Начните |
с инструкции ‘import cgi’. Никогда не используйте ‘from cgi |
import |
*’ — модуль определяет множество имен для внутреннего использования и |
для совместимости с предыдущими версиями, появление которых нежелательно в вашем пространстве имен.
FieldStorage([**keyword_args])
В этом классе сосредоточена наиболее часто используемая функциональность модуля cgi. При инициализации его без аргументов происходит обработка данных со стандартного потока ввода и/или из переменных окружения в соответствии со стандартом CGI1. Так как при этом поглощаются данные со стандартного ввода, следует создавать только один экземпляр класса FieldStorage за все время работы программы.
Конструктор класса воспринимает следующие именованные аргументы (keyword_args):
fp
Указывает альтернативный файловый (или подобный) объект, из которого будут считываться данные. По умолчанию используется sys.stdin. Этот аргумент игнорируется при использовании метода GET.
headers
Отображение с информацией о HTTP-заголовках. По умолчанию извлекается из переменных окружения.
environ
Отображение с информацией о переменных окружения. По умолчанию используется os.environ.
keep_blank_values
По умолчанию создаваемый экземпляр класса FieldStorage не содержит записи для полей, значения которых являются пустыми строками; для того,
1 С одним исключением: при использовании метода POST не обрабатываются данные в строке запроса (часть URL после символа ‘?’).
27.1. cgi — протокол CGI |
357 |
чтобы такие значения сохранялись, необходимо при инициализации указать этот аргумент равным истине.
strict_parsing
По умолчанию ошибки, возникающие при обработке данных, молча игнорируются. Если же задан и является истиной аргумент strict_parsing, при возникновении ошибок будет генерироваться исключение ValueError.
Помимо представления всей формы, экземпляры класса FieldStorage используются для представления полей формы, переданных в виде ‘multipart/formdata’.
MiniFieldStorage
Экземпляры этого класса используются для представления полей формы, переданных в виде ‘application/x-www-form-urlencoded’.
Экземпляры классов FieldStorage и MiniFieldStorage имеют следующие общие атрибуты данных:
name
Имя поля или None.
filename
Имя файла, указанное клиентом, или None.
value
Значение поля в виде строки, список значений (если используется несколько полей с одинаковым именем) или None. Если объект соответствует загружаемому файлу, при каждом обращении к этому атрибуту производится чтение всего содержимого файла.
file
Файловый (или подобный) объект, из которого Вы можете считывать данные, или None, если данные представлены строкой.
type
Тип содержимого поля (заголовок ‘Content-Type’) или None, если тип не указан.
type_options
Словарь параметров, указанных в заголовке ‘Content-Type’.
disposition
Размещение содержимого поля (заголовок ‘Content-Disposition’) или None.
disposition_options
Словарь параметров, указанных в заголовке ‘Content-Disposition’.
headers
Отображение, содержащее записи для всех заголовков.
358 |
Глава 27. Поддержка протоколов Internet |
Экземпляры класса FieldStorage являются отображениями имен полей к представляющим их объектам и поддерживают основные операции, характерные для отображений, а также методы has_key() и keys(). Помимо этого они имеют следующие методы:
getvalue(key [, default])
Возвращает строковое значение поля с именем key или default, если нет поля с таким именем. Если форма содержит несколько полей с таким именем, возвращает список их строковых значений. По умолчанию в качестве аргумента default используется None.
make_file(binary)
Этот метод используется реализацией класса для создания временного хранилища данных. По умолчанию используется tempfile.TemporaryFile(). Вы можете переопределить этот метод в производном классе, предоставив альтернативный способ временного хранения данных. В качестве аргумента binary используется строка ’b’, если файл должен быть открыт в двоичном режиме, в противном случае он равен пустой строке. Метод должен возвращать файловый (или подобный) объект, доступный для чтения и записи.
Приведем простой пример CGI-программы, который проверяет, чтобы были заполнены поля ‘name’ и ‘addr’:
import cgi
print """\
Content-Type: text/html
<html>
<body>"""
form = cgi.FieldStorage()
if form.has_key("name") and form.has_key("addr"): print """\
<p>йНС: %s</p> <p>бДТЕУ: %s</p>"""
else:
print """\
<h1>пЫЙВЛБ</h1>
<p>чЧЕДЙФЕ, РПЦБМХКУФБ, ЙНС Й БДТЕУ.</p>"""
print """\
</body>
</html>"""
Поля формы, доступные через form[key], могут быть представлены экземплярами класса FieldStorage, MiniFieldStorage (в зависимости от способа кодирования) или списком экземпляров, если форма содержит несколько полей с указанным
27.1. cgi — протокол CGI |
359 |
именем. В последнем случае метод getvalue() также возвращает список строковых значений полей. Если в Вашем случае возможно присутствие нескольких полей с одинаковым именем, используйте встроенную функцию type() для определения типа:
value = form.getvalue("username", "") if type(value) is type([]):
# ъБРПМОЕОП ОЕУЛПМШЛП РПМЕК У ЙНЕОЕН РПМШЪПЧБФЕМС usernames = ",".join(value)
else:
#ъБРПМОЕОП ОЕ ВПМЕЕ ПДОПЗП РПМС У ЙНЕОЕН
#РПМШЪПЧБФЕМС
usernames = value
Если объект представляет загружаемый файл, при обращении к атрибуту value весь файл считывается в память в виде строки. Такое поведение не всегда желательно. Вы можете определить, представляет ли объект загружаемый файл, по значению атрибута filename или file:
fileitem = form["userfile"] if fileitem.file:
#пВЯЕЛФ fileitem РТЕДУФБЧМСЕФ ЪБЗТХЦБЕНЩК ЖБКМ.
#рПДУЮЙФЩЧБЕН УФТПЛЙ, ОЕ УПИТБОСС ЧЕУШ ЖБКМ Ч
#РБНСФЙ.
linecount = 0 while 1:
if fileitem.file.readline() linecount += 1
else: break
Проект стандарта по организации загрузки файлов принимает во внимание возможность загрузки нескольких файлов из одного поля HTML-формы (рекурсивно используя ‘multipart/*’). В этом случае объект будет являться отображением, с которым можно работать аналогично объекту, представляющему всю форму. Вы можете определить такой объект по значению атрибута type (‘obj.type and obj.type.startswith(’multipart/’)’).
27.1.3 Дополнительные возможности модуля
Модуль cgi определяет также дополнительные функции, которые будут полезны, если необходим более тонкий контроль.
parse([**keyword_args])
Обрабатывает данные со стандартного потока ввода и/или из переменных окружения в соответствии со стандартом CGI1 и возвращает словарь, отображающий
360 |
Глава 27. Поддержка протоколов Internet |
имена полей к спискам значений. Функция воспринимает именованные аргументы fp, environ, keep_blank_values и strict_parsing, которые имеют такое же значения, как и для конструктора класса FieldStorage (см. раздел 27.1.2).
parse_qs(qs [, **keyword_args])
Обрабатывает строку запроса, переданную в качестве аргумента qs (данные типа ‘application/x-www-form-urlencoded’), и возвращает словарь, отображающий имена полей к спискам значений. Функция воспринимает именованные аргументы keep_blank_values и strict_parsing, которые имеют такое же значение, как и для конструктора класса FieldStorage (см. раздел 27.1.2).
parse_qsl(qs [, **keyword_args])
Работает аналогично функции parse_qs(), но возвращает список кортежей с именем поля и его значением.
parse_multipart(fp, pdict)
Обрабатывает данные в виде ‘multipart/form-data’ из потока fp и возвращает словарь, отображающий имена полей к спискам значений. Аргумент pdict должен быть словарем, содержащим параметры из заголовка ‘Content-Type’.
Заметим, что эта функция не обрабатывает вложенные ‘multipart/*’ части. Кроме того, она полностью считывает файл в память, что может быть нежелательным при загрузке больших файлов. Класс FieldStorage не обладает этими недостатками.
parse_header(string)
Обрабатывает MIME-заголовок в строке string и возвращает кортеж, содержащий основное значение и словарь параметров. Предполагается, что строка string не содержит самого имени заголовка, то есть для заголовка ‘Content-Type: text/plain; encoding=koi8-r’ аргумент должен быть равен ’text/plain; encoding=koi8-r’.
test()
Эта функция реализует готовую CGI-программу, предназначенный для тестирования: выводит минимальный HTTP-заголовок и всю переданную программе информацию в формате HTML. Функция test() вызывается при использовании файла модуля ‘cgi.py’ в качестве программы.
print_environ()
Выводит информацию о переменных окружения в формате HTML.
print_form(form)
Выводит значения полей формы, представленной объектом form (должен быть экземпляром класс FieldStorage), в формате HTML.
print_directory()
Выводит содержимое текущего каталога в формате HTML.
print_environ_usage()
Выводит список переменных окружения, которые могут быть использованы CGIпрограммой.
