Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

[ Россум, Дрейк, Откидач ] Язык программирования Python

.pdf
Скачиваний:
300
Добавлен:
25.04.2014
Размер:
1.5 Mб
Скачать

26.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программой.