wsgiref --- ابزارهای WSGI و پیاده‌سازی مرجع

کد منبع: Lib/wsgiref


هشدار

wsgiref یک پیاده‌سازی مرجع است و برای استفاده در محیط عملیاتی توصیه نمی‌شود. این ماژول تنها بررسی‌های امنیتی پایه را انجام می‌دهد.

رابط دروازه‌ی سرور وب (WSGI) یک رابط استاندارد میان نرم‌افزار سرور وب و برنامه‌های وب نوشته‌شده با پایتون است. داشتن یک رابط استاندارد، استفاده از برنامه‌ای را که از WSGI پشتیبانی می‌کند با تعدادی از سرورهای وب مختلف آسان می‌سازد.

تنها نویسندگان وب‌سرورها و چارچوب‌های برنامه‌نویسی نیاز دارند که تمام جزئیات و حالت‌های خاص طراحی WSGI را بدانند. شما صرفاً برای نصب یک برنامه WSGI یا نوشتن یک برنامه وب با استفاده از یک چارچوب موجود، نیازی به درک تمام جزئیات WSGI ندارید.

wsgiref یک پیاده‌سازی مرجع از مشخصات WSGI است که می‌توان از آن برای افزودن پشتیبانی از WSGI به یک وب‌سرور یا چارچوب استفاده کرد. این ماژول ابزارهایی برای دستکاری متغیرهای محیطی WSGI و سرآیند‌های پاسخ، کلاس‌های پایه برای پیاده‌سازی سرورهای WSGI، یک سرور HTTP نمایشی که به برنامه‌های WSGI سرویس می‌دهد، انواعی برای بررسی ایستای نوع، و یک ابزار اعتبارسنجی را فراهم می‌کند که سرورها و برنامه‌های WSGI را از نظر انطباق با مشخصات WSGI (PEP 3333) بررسی می‌کند.

برای اطلاعات بیشتر درباره WSGI و پیوندهایی به آموزش‌ها و سایر منابع، به wsgi.readthedocs.io مراجعه کنید.

wsgiref.util -- ابزارهای سودمند محیط WSGI

این ماژول توابع کاربردی متنوعی برای کار با محیط‌های WSGI فراهم می‌کند. محیط WSGI دیکشنری حاوی متغیرهای درخواست HTTP است که در PEP 3333 توصیف شده است. تمام توابعی که پارامتر environ می‌پذیرند، انتظار دارند یک دیکشنری مطابق با WSGI ارائه شود؛ لطفاً برای مشخصات دقیق، PEP 3333 و برای نام مستعار نوعی که می‌تواند در حاشیه‌نویسی‌های نوع استفاده شود، WSGIEnvironment را ببینید.

wsgiref.util.guess_scheme(environ)

با بررسی متغیر محیطی HTTPS در دیکشنری environ، حدسی درباره‌ی اینکه wsgi.url_scheme باید "http" باشد یا "https" برمی‌گرداند. مقدار بازگشتی یک رشته است.

این تابع هنگام ایجاد درگاهی که CGI یا پروتکلی مشابه CGI مانند FastCGI را پوشش می‌دهد، مفید است. معمولاً سرورهایی که چنین پروتکل‌هایی را ارائه می‌دهند، هنگامی که درخواستی از طریق SSL دریافت می‌شود، شامل یک متغیر HTTPS با مقدار "1"، "yes" یا "on" هستند. بنابراین، این تابع در صورت یافتن چنین مقداری، "https" و در غیر این صورت "http" را برمی‌گرداند.

wsgiref.util.request_uri(environ, include_query=True)

URI کامل درخواست را، به‌صورت اختیاری شامل رشته‌ی کوئری، با استفاده از الگوریتم موجود در بخش «URL Reconstruction» در PEP 3333 برمی‌گرداند. اگر include_query نادرست باشد، رشته‌ی کوئری در URI حاصل گنجانده نمی‌شود.

wsgiref.util.application_uri(environ)

مشابه request_uri()، با این تفاوت که متغیرهای PATH_INFO و QUERY_STRING نادیده گرفته می‌شوند. نتیجه، URI پایه‌ی شیء برنامه‌ی مورد اشاره‌ی درخواست است.

wsgiref.util.shift_path_info(environ)

یک نام را از PATH_INFO به SCRIPT_NAME جابه‌جا می‌کند و نام را برمی‌گرداند. دیکشنری environ به‌صورت درجا تغییر می‌یابد؛ اگر نیاز دارید PATH_INFO یا SCRIPT_NAME اصلی را دست‌نخورده نگه دارید، از یک کپی استفاده کنید.

اگر هیچ بخش مسیر باقی‌مانده‌ای در PATH_INFO وجود نداشته باشد، None برگردانده می‌شود.

معمولاً از این تابع برای پردازش هر بخش از مسیر URI درخواست استفاده می‌شود، برای مثال برای اینکه با مسیر به‌عنوان دنباله‌ای از کلیدهای دیکشنری رفتار شود. این تابع محیط داده‌شده را تغییر می‌دهد تا برای فراخوانی یک برنامه WSGI دیگر که در URI هدف قرار دارد مناسب شود. برای مثال، اگر یک برنامه WSGI در /foo وجود داشته باشد، و مسیر URI درخواست /foo/bar/baz باشد، و برنامه WSGI در /foo تابع shift_path_info() را فراخوانی کند، رشته "bar" را دریافت خواهد کرد، و محیط به‌گونه‌ای به‌روزرسانی می‌شود که برای ارسال به یک برنامه WSGI در /foo/bar مناسب باشد. یعنی SCRIPT_NAME از /foo به /foo/bar تغییر می‌کند، و PATH_INFO از /bar/baz به /baz تغییر می‌کند.

هنگامی که PATH_INFO فقط یک "/" باشد، این رویه یک رشته خالی برمی‌گرداند و یک اسلش پایانی به SCRIPT_NAME می‌افزاید، هرچند بخش‌های خالی مسیر معمولاً نادیده گرفته می‌شوند و SCRIPT_NAME معمولاً به اسلش ختم نمی‌شود. این رفتار عمدی است تا اطمینان حاصل شود که یک برنامه کاربردی می‌تواند هنگام استفاده از این رویه برای پیمایش شیء، تفاوت میان URIهایی که به /x ختم می‌شوند و آن‌هایی که به /x/ ختم می‌شوند را تشخیص دهد.

wsgiref.util.setup_testing_defaults(environ)

environ را با پیش‌فرض‌های ساده برای اهداف آزمایش به‌روزرسانی کنید.

این روال، پارامترهای مختلفی را که برای WSGI مورد نیاز هستند اضافه می‌کند، از جمله HTTP_HOST، SERVER_NAME، SERVER_PORT، REQUEST_METHOD، SCRIPT_NAME، PATH_INFO و همه‌ی متغیرهای wsgi.* تعریف‌شده در PEP 3333. این روال تنها مقادیر پیش‌فرض را فراهم می‌کند و هیچ‌یک از تنظیمات موجود برای این متغیرها را جایگزین نمی‌کند.

این روتین در نظر گرفته شده است تا راه‌اندازی محیط‌های ساختگی را برای آزمون‌های واحد سرورها و برنامه‌های WSGI آسان‌تر کند. سرورها یا برنامه‌های WSGI واقعی نباید از آن استفاده کنند، زیرا داده‌ها جعلی هستند!

نمونه استفاده (همچنین برای نمونه‌ای دیگر demo_app() را ببینید):

from wsgiref.util import setup_testing_defaults
from wsgiref.simple_server import make_server

# A relatively simple WSGI application. It's going to print out the
# environment dictionary after being updated by setup_testing_defaults
def simple_app(environ, start_response):
    setup_testing_defaults(environ)

    status = '200 OK'
    headers = [('Content-type', 'text/plain; charset=utf-8')]

    start_response(status, headers)

    ret = [("%s: %s\n" % (key, value)).encode("utf-8")
           for key, value in environ.items()]
    return ret

with make_server('', 8000, simple_app) as httpd:
    print("Serving on port 8000...")
    httpd.serve_forever()

علاوه بر توابع محیطی بالا، ماژول wsgiref.util این ابزارهای متفرقه را نیز فراهم می‌کند:

wsgiref.util.is_hop_by_hop(header_name)

اگر 'header_name' یک سرآیند HTTP/1.1 از نوع «Hop-by-Hop» باشد، همان‌طور که در RFC 2616 تعریف شده است، True برمی‌گرداند.

class wsgiref.util.FileWrapper(filelike, blksize=8192)

یک پیاده‌سازی عینی از پروتکل wsgiref.types.FileWrapper که برای تبدیل یک شیء شبه‌پرونده به یک پیمایش‌گر به کار می‌رود. اشیای حاصل، پیمایش‌پذیر هستند. هنگامی که شیء مورد تکرار قرار می‌گیرد، پارامتر اختیاری blksize به‌طور مکرر به متد read() شیء filelike پاس داده خواهد شد تا رشته‌های بایتی برای yield به دست آیند. هنگامی که read() یک رشته بایتی خالی برگرداند، تکرار پایان می‌یابد و قابل از سرگیری نیست.

اگر filelike دارای متد close() باشد، شیء برگردانده‌شده نیز دارای متد close() خواهد بود و هنگام فراخوانی، متد close() شیء filelike را فراخوانی می‌کند.

نمونه استفاده:

from io import StringIO
from wsgiref.util import FileWrapper

# We're using a StringIO-buffer for as the file-like object
filelike = StringIO("This is an example file-like object"*10)
wrapper = FileWrapper(filelike, blksize=5)

for chunk in wrapper:
    print(chunk)

تغییر یافته در نسخه‌ی 3.11: پشتیبانی از متد __getitem__() حذف شده است.

wsgiref.headers -- ابزارهای سرآیند پاسخ WSGI

این ماژول یک کلاس واحد، Headers، را برای دستکاری آسان سرآیندهای پاسخ WSGI با استفاده از یک رابط نگاشت‌مانند ارائه می‌دهد.

class wsgiref.headers.Headers([headers])

یک شیء نگاشت‌مانند ایجاد کنید که پوششی برای headers است؛ headers باید فهرستی از تاپل‌های نام/مقدار سرآیند باشد، همان‌طور که در PEP 3333 توضیح داده شده است. مقدار پیش‌فرض headers یک فهرست خالی است.

اشیای Headers از عملیات معمول نگاشت پشتیبانی می‌کنند، از جمله __getitem__()، get()، __setitem__()، setdefault()، __delitem__() و __contains__(). برای هر یک از این متدها، کلید نام سرآیند است (بدون حساسیت به بزرگی و کوچکی حروف در نظر گرفته می‌شود)، و مقدار نخستین مقدار مرتبط با آن نام سرآیند است. تنظیم یک سرآیند تمام مقدارهای موجود برای آن سرآیند را حذف می‌کند، سپس یک مقدار جدید را در انتهای فهرست سرآیندهای تحت پوشش اضافه می‌کند. ترتیب موجود سرآیندها به‌طور کلی حفظ می‌شود، و سرآیندهای جدید به انتهای فهرست تحت پوشش اضافه می‌شوند.

برخلاف دیکشنری، اشیای Headers هنگامی که سعی می‌کنید کلیدی را که در فهرست سرآیندهای دربرگرفته‌شده نیست دریافت یا حذف کنید، خطایی پرتاب نمی‌کنند. دریافت یک سرآیند ناموجود فقط None را برمی‌گرداند و حذف یک سرآیند ناموجود هیچ کاری انجام نمی‌دهد.

اشیای Headers همچنین از متدهای keys()، values() و items() پشتیبانی می‌کنند. فهرست‌های برگردانده‌شده توسط keys() و items() می‌توانند در صورت وجود سرآیند چندمقداری، یک کلید یکسان را بیش از یک بار شامل شوند. len() یک شیء Headers برابر با طول items() آن است، که خود برابر با طول فهرست سرآیند دربرگرفته‌شده است. در واقع، متد items() فقط یک کپی از فهرست سرآیند دربرگرفته‌شده را برمی‌گرداند.

فراخوانی bytes() روی یک شیء Headers یک رشته‌بایت (bytestring) قالب‌بندی‌شده مناسب برای انتقال به‌عنوان سرآیندهای پاسخ HTTP را برمی‌گرداند. هر سرآیند همراه با مقدارش در یک خط قرار می‌گیرد؛ سرآیند و مقدار با یک دونقطه و یک فاصله از هم جدا می‌شوند. هر خط با یک بازگشت به ابتدای سطر (carriage return) و یک تغذیه‌ی سطر (line feed) پایان می‌یابد و رشته‌بایت با یک خط خالی پایان می‌یابد.

علاوه بر رابط نگاشت و قابلیت‌های قالب‌بندی آن‌ها، اشیاء Headers همچنین دارای متدهای زیر برای پرس‌وجو و افزودن سرآیند‌های چندمقداری، و برای افزودن سرآیند‌ها با پارامترهای MIME هستند:

get_all(name)

فهرستی از تمام مقدارهای سرآیند نام‌برده‌شده را برمی‌گرداند.

فهرست برگردانده‌شده به همان ترتیبی که در فهرست سرآیند اصلی ظاهر شده‌اند یا به این نمونه افزوده شده‌اند، مرتب خواهد شد و ممکن است شامل موارد تکراری باشد. هر فیلدی که حذف و دوباره درج شود، همیشه به فهرست سرآیند افزوده می‌شود. اگر هیچ فیلدی با نام داده‌شده وجود نداشته باشد، یک فهرست خالی برمی‌گرداند.

add_header(name, value, **_params)

یک سرآیند (احتمالاً چندمقداری) اضافه کنید، با پارامترهای MIME اختیاری که از طریق آرگومان‌های کلیدواژه‌ای مشخص می‌شوند.

name فیلد سرآیندی است که اضافه می‌شود. می‌توان از آرگومان‌های کلیدواژه‌ای برای تنظیم پارامترهای MIME برای فیلد سرآیند استفاده کرد. هر پارامتر باید یک رشته یا None باشد. زیرسطرها در نام‌های پارامتر به خط‌تیره تبدیل می‌شوند، زیرا خط‌تیره در شناسه‌های پایتون غیرمجاز است، اما بسیاری از نام‌های پارامتر MIME شامل خط‌تیره هستند. اگر مقدار پارامتر یک رشته باشد، به پارامترهای مقدار سرآیند در قالب name="value" اضافه می‌شود. اگر None باشد، فقط نام پارامتر اضافه می‌شود. (این برای پارامترهای MIME بدون مقدار استفاده می‌شود.) نمونه استفاده:

h.add_header('content-disposition', 'attachment', filename='bud.gif')

مورد بالا سرآیندی اضافه می‌کند که به شکل زیر است:

Content-Disposition: attachment; filename="bud.gif"

تغییر یافته در نسخه‌ی 3.5: پارامتر headers اختیاری است.

wsgiref.simple_server -- یک سرور HTTP ساده WSGI

این ماژول یک سرور HTTP ساده (بر پایه‌ی http.server) پیاده‌سازی می‌کند که اپلیکیشن‌های WSGI را سرویس می‌دهد. هر نمونه از سرور، یک اپلیکیشن WSGI واحد را روی یک میزبان و پورت مشخص سرویس می‌دهد. اگر می‌خواهید چندین اپلیکیشن را روی یک میزبان و پورت واحد سرویس دهید، باید یک اپلیکیشن WSGI بسازید که PATH_INFO را تجزیه کند تا انتخاب کند برای هر درخواست کدام اپلیکیشن فراخوانی شود. (برای مثال، با استفاده از تابع shift_path_info() از wsgiref.util.)

wsgiref.simple_server.make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler)

یک سرور WSGI جدید ایجاد کنید که روی host و port گوش می‌دهد و اتصالات را برای app می‌پذیرد. مقدار بازگشتی، نمونه‌ای از server_class ارائه‌شده است و درخواست‌ها را با استفاده از handler_class مشخص‌شده پردازش می‌کند. app باید یک شیء برنامه WSGI باشد، همان‌طور که در PEP 3333 تعریف شده است.

نمونه استفاده:

from wsgiref.simple_server import make_server, demo_app

with make_server('', 8000, demo_app) as httpd:
    print("Serving HTTP on port 8000...")

    # Respond to requests until process is killed
    httpd.serve_forever()

    # Alternative: serve one request, then exit
    httpd.handle_request()
wsgiref.simple_server.demo_app(environ, start_response)

این تابع یک برنامه‌ی WSGI کوچک اما کامل است که یک صفحه‌ی متنی شامل پیام «Hello world!» و فهرستی از جفت‌های کلید/مقدار ارائه‌شده در پارامتر environ را برمی‌گرداند. این تابع برای تأیید اینکه یک سرور WSGI (مانند wsgiref.simple_server) می‌تواند یک برنامه‌ی WSGI ساده را به‌درستی اجرا کند، مفید است.

شیء فراخوانی‌پذیر start_response باید از پروتکل StartResponse پیروی کند.

class wsgiref.simple_server.WSGIServer(server_address, RequestHandlerClass)

یک نمونه از WSGIServer ایجاد کنید. server_address باید یک تاپل (host,port) باشد، و RequestHandlerClass باید زیرکلاس http.server.BaseHTTPRequestHandler باشد که برای پردازش درخواست‌ها استفاده خواهد شد.

معمولاً نیازی نیست این سازنده را فراخوانی کنید، زیرا تابع make_server() می‌تواند تمام جزئیات را برای شما مدیریت کند.

WSGIServer یک زیرکلاس از http.server.HTTPServer است، بنابراین همه‌ی متدهای آن (مانند serve_forever() و handle_request()) در دسترس هستند. WSGIServer همچنین این متدهای ویژه‌ی WSGI را نیز ارائه می‌کند:

set_app(application)

فراخوانی‌پذیر application را به‌عنوان برنامه WSGI که درخواست‌ها را دریافت خواهد کرد، تنظیم می‌کند.

get_app()

برنامه‌ی فراخوانی‌پذیر تنظیم‌شده‌ی کنونی را برمی‌گرداند.

با این حال، معمولاً نیازی به استفاده از این متدهای اضافی ندارید، زیرا set_app() معمولاً توسط make_server() فراخوانی می‌شود و get_app() عمدتاً برای استفاده‌ی نمونه‌های هندلر درخواست وجود دارد.

class wsgiref.simple_server.WSGIRequestHandler(request, client_address, server)

یک مدیر HTTP (HTTP handler) برای request داده‌شده (یعنی یک سوکت)، client_address (یک تاپل (host,port)) و server (نمونه‌ای از WSGIServer) ایجاد کنید.

شما نیازی به ایجاد مستقیم نمونه‌های این کلاس ندارید؛ آن‌ها به‌صورت خودکار در صورت نیاز توسط اشیای WSGIServer ایجاد می‌شوند. با این حال، می‌توانید یک زیرکلاس از این کلاس بسازید و آن را به‌عنوان handler_class به تابع make_server() ارائه دهید. برخی متدهای احتمالاً مرتبط برای بازنویسی در زیرکلاس‌ها:

get_environ()

یک دیکشنری WSGIEnvironment برای یک درخواست برمی‌گرداند. پیاده‌سازی پیش‌فرض، محتوای ویژگی دیکشنری base_environ شیء WSGIServer را کپی می‌کند و سپس سرآیندهای مختلفی را که از درخواست HTTP به‌دست می‌آیند، اضافه می‌کند. هر فراخوانی این متد باید یک دیکشنری جدید حاوی تمام متغیرهای محیطی CGI مرتبط، همان‌طور که در PEP 3333 مشخص شده است، برگرداند.

get_stderr()

شیءای را که باید به‌عنوان جریان wsgi.errors استفاده شود، برمی‌گرداند. پیاده‌سازی پیش‌فرض فقط sys.stderr را برمی‌گرداند.

handle()

درخواست HTTP را پردازش می‌کند. پیاده‌سازی پیش‌فرض، با استفاده از کلاسی از wsgiref.handlers، نمونه‌ای از هندلر ایجاد می‌کند تا رابط واقعی برنامه‌ی WSGI را پیاده‌سازی کند.

wsgiref.validate --- بررسی‌کننده‌ی انطباق WSGI

هنگام ایجاد اشیاء برنامه WSGI، چارچوب‌ها، سرورها یا میان‌افزارهای جدید، می‌توانید انطباق کد جدید را با استفاده از wsgiref.validate اعتبارسنجی کنید. این ماژول تابعی فراهم می‌کند که اشیاء برنامه WSGI را ایجاد می‌کند؛ این اشیاء ارتباطات بین یک سرور یا درگاه WSGI و یک شیء برنامه WSGI را اعتبارسنجی می‌کنند تا انطباق هر دو طرف با پروتکل بررسی شود.

توجه داشته باشید که این ابزار انطباق کامل با PEP 3333 را تضمین نمی‌کند؛ نبود خطا از سوی این ماژول لزوماً به این معنا نیست که هیچ خطایی وجود ندارد. با این حال، اگر این ماژول خطایی تولید کند، عملاً قطعی است که یا سرور یا برنامه ۱۰۰٪ منطبق نیست.

این ماژول بر پایه‌ی ماژول paste.lint از کتابخانه‌ی «Python Paste» متعلق به Ian Bicking است.

wsgiref.validate.validator(application)

application را در بر می‌گیرد و یک شیء برنامه WSGI جدید برمی‌گرداند. برنامه برگردانده‌شده تمام درخواست‌ها را به application اصلی هدایت می‌کند و بررسی می‌کند که هم application و هم سروری که آن را فراخوانی می‌کند، با مشخصات WSGI و RFC 2616 مطابقت دارند.

هرگونه عدم انطباق شناسایی‌شده منجر به پرتاب AssertionError می‌شود؛ با این حال توجه داشته باشید که چگونگی مدیریت این خطاها وابسته به سرور است. برای مثال، wsgiref.simple_server و سایر سرورهای مبتنی بر wsgiref.handlers (که متدهای مدیریت خطا را برای انجام کار دیگری بازنویسی نمی‌کنند) صرفاً پیامی مبنی بر وقوع یک خطا را خروجی می‌دهند و ردگیری پشته را در sys.stderr یا جریان خطای دیگری می‌نویسند.

این دربرگیرنده ممکن است همچنین با استفاده از ماژول warnings خروجی تولید کند تا رفتارهایی را که پرسش‌برانگیز هستند اما ممکن است در واقع در PEP 3333 ممنوع نشده باشند، نشان دهد. مگر اینکه این هشدارها با استفاده از گزینه‌های خط فرمان پایتون یا API ماژول warnings مهار شوند، هر یک از این هشدارها در sys.stderr نوشته خواهند شد (نه wsgi.errors، مگر اینکه این دو اتفاقاً یک شیء باشند).

نمونه استفاده:

from wsgiref.validate import validator
from wsgiref.simple_server import make_server

# Our callable object which is intentionally not compliant to the
# standard, so the validator is going to break
def simple_app(environ, start_response):
    status = '200 OK'  # HTTP Status
    headers = [('Content-type', 'text/plain')]  # HTTP Headers
    start_response(status, headers)

    # This is going to break because we need to return a list, and
    # the validator is going to inform us
    return b"Hello World"

# This is the application wrapped in a validator
validator_app = validator(simple_app)

with make_server('', 8000, validator_app) as httpd:
    print("Listening on port 8000....")
    httpd.serve_forever()

wsgiref.handlers -- کلاس‌های پایه‌ی سرور/درگاه

این ماژول، کلاس‌های پایه‌ی هندلر را برای پیاده‌سازی سرورها و دروازه‌های WSGI فراهم می‌کند. این کلاس‌های پایه، بیشتر کار ارتباط با یک برنامه‌ی WSGI را انجام می‌دهند، مشروط بر اینکه محیطی شبهCGI به همراه جریان‌های ورودی، خروجی و خطا به آن‌ها داده شود.

class wsgiref.handlers.CGIHandler

فراخوانی مبتنی بر CGI از طریق sys.stdin، sys.stdout، sys.stderr و os.environ. این زمانی مفید است که یک برنامه WSGI دارید و می‌خواهید آن را به‌عنوان یک اسکریپت CGI اجرا کنید. کافی است CGIHandler().run(app) را فراخوانی کنید، که در آن app شیء برنامه WSGI است که می‌خواهید فراخوانی شود.

این کلاس، زیرکلاسی از BaseCGIHandler است که wsgi.run_once را روی درست، wsgi.multithread را روی نادرست و wsgi.multiprocess را روی درست تنظیم می‌کند و همیشه برای به دست آوردن جریان‌ها و محیط CGI مورد نیاز، از sys و os استفاده می‌کند.

class wsgiref.handlers.IISCGIHandler

یک جایگزین تخصصی برای CGIHandler، برای استفاده هنگام استقرار روی وب‌سرور IIS مایکروسافت، بدون اینکه گزینه‌ی پیکربندی allowPathInfo (IIS>=7) یا metabase allowPathInfoForScriptMappings (IIS<7) تنظیم شده باشد.

به‌طور پیش‌فرض، IIS یک PATH_INFO می‌دهد که در ابتدای آن SCRIPT_NAME را تکرار می‌کند و برای برنامه‌های WSGI که مایل به پیاده‌سازی مسیریابی هستند، مشکل ایجاد می‌کند. این هندلر هرگونه مسیر تکراری از این دست را حذف می‌کند.

می‌توان IIS را به‌گونه‌ای پیکربندی کرد که PATH_INFO درست را ارسال کند، اما این کار سبب اشکال دیگری می‌شود که در آن PATH_TRANSLATED نادرست است. خوشبختانه این متغیر به‌ندرت استفاده می‌شود و در WSGI تضمین نشده است. با این حال، در IIS<7، این تنظیم فقط می‌تواند در سطح میزبان مجازی (vhost) اعمال شود و بر تمام نگاشت‌های اسکریپتی دیگر تأثیر می‌گذارد؛ بسیاری از آن‌ها در صورت مواجهه با اشکال PATH_TRANSLATED از کار می‌افتند. به همین دلیل، IIS<7 تقریباً هرگز همراه با این اصلاحیه مستقر نمی‌شود (حتی IIS7 نیز به‌ندرت از آن استفاده می‌کند، زیرا هنوز هیچ رابط کاربری برای آن وجود ندارد.)

هیچ راهی برای کد CGI وجود ندارد که تشخیص دهد گزینه تنظیم شده است یا نه، بنابراین یک کلاس هندلر جداگانه ارائه شده است. این کلاس به همان روش CGIHandler استفاده می‌شود، یعنی با فراخوانی IISCGIHandler().run(app)، که در آن app شیء برنامه WSGI است که می‌خواهید فراخوانی کنید.

اضافه شده در نسخه‌ی 3.2.

class wsgiref.handlers.BaseCGIHandler(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)

مشابه CGIHandler، اما به‌جای استفاده از ماژول‌های sys و os، محیط CGI و جریان‌های I/O به‌صورت صریح مشخص می‌شوند. مقادیر multithread و multiprocess برای تنظیم پرچم‌های wsgi.multithread و wsgi.multiprocess برای هر برنامه‌ای که توسط نمونه‌ی هندلر اجرا می‌شود، استفاده می‌شوند.

این کلاس، زیرکلاسی از SimpleHandler است که برای استفاده با نرم‌افزارهایی غیر از «سرورهای مبدأ HTTP» (origin servers) در نظر گرفته شده است. اگر در حال نوشتن پیاده‌سازی پروتکل دروازه (gateway protocol) هستید (مانند CGI، FastCGI، SCGI و غیره) که از سرآیند Status: برای ارسال وضعیت HTTP استفاده می‌کند، احتمالاً می‌خواهید به‌جای SimpleHandler، زیرکلاسی از این کلاس بسازید.

class wsgiref.handlers.SimpleHandler(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)

مشابه BaseCGIHandler، اما برای استفاده با سرورهای مبدأ HTTP طراحی شده است. اگر در حال نوشتن پیاده‌سازی یک سرور HTTP هستید، احتمالاً می‌خواهید به‌جای BaseCGIHandler، از این کلاس یک زیرکلاس بسازید.

این کلاس زیرکلاسی از BaseHandler است. این کلاس متدهای __init__()، get_stdin()، get_stderr()، add_cgi_vars()، _write() و _flush() را بازنویسی می‌کند تا از تنظیم صریح محیط و جریان‌ها از طریق سازنده پشتیبانی کند. محیط و جریان‌های ارائه‌شده در ویژگی‌های stdin، stdout، stderr و environ ذخیره می‌شوند.

متد write() مربوط به stdout باید هر تکه (chunk) را به‌طور کامل بنویسد، مانند io.BufferedIOBase.

class wsgiref.handlers.BaseHandler

این یک کلاس پایه انتزاعی برای اجرای برنامه‌های WSGI است. هر نمونه یک درخواست HTTP واحد را مدیریت خواهد کرد، هرچند در اصل می‌توانید زیرکلاسی ایجاد کنید که برای چندین درخواست قابل استفاده مجدد باشد.

نمونه‌های BaseHandler تنها یک متد برای استفاده بیرونی دارند:

run(app)

برنامه WSGI مشخص‌شده، app را اجرا کنید.

تمامی متدهای دیگر BaseHandler توسط این متد در فرایند اجرای برنامه فراخوانی می‌شوند، و بنابراین عمدتاً وجود دارند تا امکان سفارشی‌سازی این فرایند را فراهم کنند.

متدهای زیر باید در یک زیرکلاس بازنویسی شوند:

_write(data)

بایت‌های data را برای ارسال به کلاینت در بافر قرار دهید. اگر این متد واقعاً داده‌ها را ارسال کند، اشکالی ندارد؛ BaseHandler فقط عملیات نوشتن و تخلیه را برای کارایی بیشتر هنگامی که سیستم زیربنایی واقعاً چنین تمایزی دارد، از هم جدا می‌کند.

_flush()

داده‌های بافرشده را به‌اجبار به کلاینت ارسال می‌کند. اشکالی ندارد اگر این متد عملیات بی‌اثر (no-op) باشد (یعنی اگر _write() در واقع داده‌ها را ارسال می‌کند).

get_stdin()

یک شیء سازگار با InputStream برمی‌گرداند که برای استفاده به‌عنوان wsgi.input درخواستی که هم‌اکنون در حال پردازش است، مناسب است.

get_stderr()

یک شیء سازگار با ErrorStream را برمی‌گرداند که برای استفاده به‌عنوان wsgi.errors درخواستی که در حال پردازش است مناسب است.

add_cgi_vars()

متغیرهای CGI برای درخواست جاری را در ویژگی environ درج می‌کند.

در اینجا چند متد و ویژگی دیگر آمده است که ممکن است بخواهید آن‌ها را بازنویسی کنید. البته این فهرست تنها یک خلاصه است و شامل همه‌ی متدهایی که می‌توان آن‌ها را بازنویسی کرد نمی‌شود. پیش از اقدام برای ایجاد یک زیرکلاس سفارشی‌شده از BaseHandler، برای اطلاعات بیشتر به رشته‌های مستند و کد منبع مراجعه کنید.

ویژگی‌ها و متدها برای سفارشی‌سازی محیط WSGI:

wsgi_multithread

مقداری که برای متغیر محیطی wsgi.multithread استفاده می‌شود. مقدار پیش‌فرض آن در BaseHandler برابر true است، اما ممکن است در سایر زیرکلاس‌ها پیش‌فرض متفاوتی داشته باشد (یا توسط سازنده تنظیم شود).

wsgi_multiprocess

مقدار مورد استفاده برای متغیر محیطی wsgi.multiprocess. مقدار پیش‌فرض آن در BaseHandler برابر true است، اما ممکن است در زیرکلاس‌های دیگر پیش‌فرض متفاوتی داشته باشد (یا توسط سازنده تنظیم شود).

wsgi_run_once

مقداری که برای متغیر محیطی wsgi.run_once استفاده می‌شود. مقدار پیش‌فرض آن در BaseHandler برابر false است، اما CGIHandler آن را به‌طور پیش‌فرض روی true تنظیم می‌کند.

os_environ

متغیرهای محیطی پیش‌فرض که باید در محیط WSGI هر درخواست گنجانده شوند. به‌طور پیش‌فرض، این یک نسخه از os.environ در زمانی است که wsgiref.handlers ایمپورت شد، اما زیرکلاس‌ها می‌توانند نسخه‌ی خود را در سطح کلاس یا نمونه ایجاد کنند. توجه داشته باشید که دیکشنری باید فقط‌خواندنی در نظر گرفته شود، زیرا مقدار پیش‌فرض بین چندین کلاس و نمونه مشترک است.

server_software

اگر ویژگی origin_server تنظیم شده باشد، از مقدار این ویژگی برای تنظیم مقدار پیش‌فرض متغیر محیطی SERVER_SOFTWARE در WSGI و نیز تنظیم یک سرآیند پیش‌فرض Server: در پاسخ‌های HTTP استفاده می‌شود. این مقدار برای هندلرهایی (مانند BaseCGIHandler و CGIHandler) که سرورهای مبدأ HTTP نیستند، نادیده گرفته می‌شود.

تغییر یافته در نسخه‌ی 3.3: اصطلاح «Python» با اصطلاح خاص پیاده‌سازی مانند «CPython»، «Jython» و غیره جایگزین می‌شود.

get_scheme()

طرح‌واره URL مورد استفاده برای درخواست جاری را برمی‌گرداند. پیاده‌سازی پیش‌فرض از تابع guess_scheme() در wsgiref.util استفاده می‌کند تا بر اساس متغیرهای environ درخواست جاری حدس بزند که طرح‌واره باید "http" یا "https" باشد.

setup_environ()

ویژگی environ را روی یک محیط WSGI کاملاً مقداردهی‌شده تنظیم کنید. پیاده‌سازی پیش‌فرض از تمام متدها و ویژگی‌های بالا، به‌همراه متدهای get_stdin()، get_stderr() و add_cgi_vars() و ویژگی wsgi_file_wrapper استفاده می‌کند. همچنین اگر کلید SERVER_SOFTWARE وجود نداشته باشد، مشروط بر اینکه ویژگی origin_server مقدار درست داشته باشد و ویژگی server_software تنظیم‌شده باشد، آن را درج می‌کند.

متدها و ویژگی‌ها برای سفارشی‌سازی مدیریت استثنا:

log_exception(exc_info)

تاپل exc_info را در گزارش سرور ثبت کنید. exc_info یک تاپل (type, value, traceback) است. پیاده‌سازی پیش‌فرض به‌سادگی ردگیری پشته را در جریان wsgi.errors درخواست می‌نویسد و آن را تخلیه می‌کند. زیرکلاس‌ها می‌توانند این متد را بازنویسی کنند تا قالب را تغییر دهند، خروجی را به مقصد دیگری هدایت کنند، ردگیری پشته را با ایمیل برای مدیر ارسال کنند، یا هر اقدام دیگری که مناسب تشخیص داده شود انجام دهند.

traceback_limit

حداکثر تعداد فریم‌ها برای درج در ردگیری‌های پشته‌ی خروجی‌داده‌شده توسط متد پیش‌فرض log_exception(). اگر None باشد، تمام فریم‌ها درج می‌شوند.

error_output(environ, start_response)

این متد یک برنامه‌ی WSGI برای تولید صفحه‌ی خطا برای کاربر است. این متد تنها در صورتی فراخوانی می‌شود که خطایی پیش از ارسال سرآیند‌ها به کلاینت رخ دهد.

این متد می‌تواند با استفاده از sys.exception() به خطای جاری دسترسی پیدا کند و باید هنگام فراخوانی آن، آن اطلاعات را به start_response منتقل کند (همان‌طور که در بخش «Error Handling» از PEP 3333 توضیح داده شده است). به‌ویژه، فراخوانی‌پذیر start_response باید از پروتکل StartResponse پیروی کند.

پیاده‌سازی پیش‌فرض فقط از ویژگی‌های error_status، error_headers و error_body برای تولید یک صفحه خروجی استفاده می‌کند. زیرکلاس‌ها می‌توانند این را بازنویسی کنند تا خروجی خطای پویاتری تولید کنند.

با این حال، توجه داشته باشید که از دیدگاه امنیتی توصیه نمی‌شود پیام‌های تشخیصی را در اختیار هر کاربری قرار دهید؛ در حالت ایده‌آل، باید برای فعال کردن خروجی تشخیصی کار خاصی انجام دهید، به همین دلیل پیاده‌سازی پیش‌فرض شامل هیچ خروجی تشخیصی نیست.

error_status

وضعیت HTTP مورد استفاده برای پاسخ‌های خطا. این باید یک رشته وضعیت، مطابق تعریف PEP 3333 باشد؛ مقدار پیش‌فرض آن یک کد و پیام ۵۰۰ است.

error_headers

سرآیندهای HTTP مورد استفاده برای پاسخ‌های خطا. این باید فهرستی از سرآیندهای پاسخ WSGI (تاپل‌های (name, value)) باشد، همان‌طور که در PEP 3333 توضیح داده شده است. فهرست پیش‌فرض فقط نوع محتوا را روی text/plain تنظیم می‌کند.

error_body

بدنه‌ی پاسخ خطا. این باید یک رشته‌بایت (bytestring) برای بدنه‌ی پاسخ HTTP باشد. مقدار پیش‌فرض آن متن ساده‌ی «خطای سرور رخ داد. لطفاً با مدیر تماس بگیرید.» است.

متدها و ویژگی‌های مربوط به قابلیت «مدیریت اختیاری پرونده وابسته به سکو» در PEP 3333:

wsgi_file_wrapper

یک کارخانه wsgi.file_wrapper، سازگار با wsgiref.types.FileWrapper، یا None. مقدار پیش‌فرض این ویژگی، کلاس wsgiref.util.FileWrapper است.

sendfile()

برای پیاده‌سازی انتقال پرونده مختص پلتفرم، این متد را بازنویسی کنید. این متد تنها زمانی فراخوانی می‌شود که مقدار بازگشتی برنامه، نمونه‌ای از کلاسی باشد که توسط ویژگی wsgi_file_wrapper مشخص شده است. این متد باید در صورتی که بتواند پرونده را با موفقیت منتقل کند، مقداری درست برگرداند تا کد انتقال پیش‌فرض اجرا نشود. پیاده‌سازی پیش‌فرض این متد فقط مقداری نادرست برمی‌گرداند.

متدها و ویژگی‌های متفرقه:

origin_server

این ویژگی باید به یک مقدار درست تنظیم شود اگر از _write() و _flush() هندلر برای برقراری ارتباط مستقیم با کلاینت استفاده می‌شود، نه از طریق یک پروتکل دروازه‌ای مشابه CGI که وضعیت HTTP را در یک سرآیند Status: خاص می‌خواهد.

مقدار پیش‌فرض این ویژگی در BaseHandler برابر با درست است، اما در BaseCGIHandler و CGIHandler برابر با نادرست است.

http_version

اگر origin_server درست باشد، این ویژگی رشته‌ای برای تنظیم نسخه HTTP پاسخ ارسال‌شده به کلاینت استفاده می‌شود. مقدار پیش‌فرض آن "1.0" است.

wsgiref.handlers.read_environ()

متغیرهای CGI را از os.environ به رشته‌های «bytes in unicode» مطابق PEP 3333 بازکدگذاری (transcode) می‌کند و یک دیکشنری جدید برمی‌گرداند. این تابع توسط CGIHandler و IISCGIHandler به‌جای استفاده‌ی مستقیم از os.environ استفاده می‌شود، که لزوماً در همه‌ی پلتفرم‌ها و وب‌سرورهایی که از Python 3 استفاده می‌کنند با WSGI سازگار نیست؛ به‌ویژه آن‌هایی که محیط واقعی سیستم‌عامل آن‌ها یونیکد است (یعنی Windows)، یا آن‌هایی که محیط به‌صورت بایت است، اما کدگذاری سیستمی که پایتون برای کدگشایی آن استفاده می‌کند چیزی غیر از ISO-8859-1 است (مثلاً سیستم‌های Unix که از UTF-8 استفاده می‌کنند).

اگر در حال پیاده‌سازی یک هندلر مبتنی بر CGI خودتان هستید، احتمالاً می‌خواهید به‌جای کپی کردن مستقیم مقادیر از os.environ، از این روال استفاده کنید.

اضافه شده در نسخه‌ی 3.2.

wsgiref.types -- انواع WSGI برای بررسی ایستای نوع

این ماژول انواع مختلفی را برای بررسی ایستای نوع فراهم می‌کند، همان‌طور که در PEP 3333 توضیح داده شده است.

اضافه شده در نسخه‌ی 3.11.

class wsgiref.types.StartResponse

یک typing.Protocol که فراخوانی‌پذیرهای start_response() را توصیف می‌کند (PEP 3333).

wsgiref.types.WSGIEnvironment

یک نام مستعار نوع که دیکشنری محیط WSGI را توصیف می‌کند.

wsgiref.types.WSGIApplication

یک نام‌مستعار نوع که یک شیء فراخوانی‌پذیر برنامه WSGI را توصیف می‌کند.

class wsgiref.types.InputStream

یک typing.Protocol که یک WSGI Input Stream را توصیف می‌کند.

class wsgiref.types.ErrorStream

یک typing.Protocol که WSGI Error Stream را توصیف می‌کند.

class wsgiref.types.FileWrapper

یک typing.Protocol که یک دربرگیرنده‌ی پرونده را توصیف می‌کند. برای یک پیاده‌سازی عینی از این پروتکل، wsgiref.util.FileWrapper را ببینید.

مثال‌ها

این یک برنامه کاربردی WSGI «Hello World» قابل‌اجرا است، که در آن شیء فراخوانی‌پذیر start_response باید از پروتکل StartResponse پیروی کند:

"""
Every WSGI application must have an application object - a callable
object that accepts two arguments. For that purpose, we're going to
use a function (note that you're not limited to a function, you can
use a class for example). The first argument passed to the function
is a dictionary containing CGI-style environment variables and the
second variable is the callable object.
"""
from wsgiref.simple_server import make_server


def hello_world_app(environ, start_response):
    status = "200 OK"  # HTTP Status
    headers = [("Content-type", "text/plain; charset=utf-8")]  # HTTP Headers
    start_response(status, headers)

    # The returned object is going to be printed
    return [b"Hello World"]

with make_server("", 8000, hello_world_app) as httpd:
    print("Serving on port 8000...")

    # Serve until process is killed
    httpd.serve_forever()

مثالی از یک برنامه‌ی WSGI که پوشه‌ی جاری را سرو می‌کند و پوشه و شماره‌ی پورت را به‌صورت اختیاری از خط فرمان می‌پذیرد (پیش‌فرض: ۸۰۰۰):

"""
Small wsgiref based web server. Takes a path to serve from and an
optional port number (defaults to 8000), then tries to serve files.
MIME types are guessed from the file names, 404 errors are raised
if the file is not found.
"""
import mimetypes
import os
import sys
from wsgiref import simple_server, util


def app(environ, respond):
    # Get the file name and MIME type
    fn = os.path.join(path, environ["PATH_INFO"][1:])
    if "." not in fn.split(os.path.sep)[-1]:
        fn = os.path.join(fn, "index.html")
    mime_type = mimetypes.guess_file_type(fn)[0]

    # Return 200 OK if file exists, otherwise 404 Not Found
    if os.path.exists(fn):
        respond("200 OK", [("Content-Type", mime_type)])
        return util.FileWrapper(open(fn, "rb"))
    else:
        respond("404 Not Found", [("Content-Type", "text/plain")])
        return [b"not found"]


if __name__ == "__main__":
    # Get the path and port from command-line arguments
    path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 8000

    # Make and start the server until control-c
    httpd = simple_server.make_server("", port, app)
    print(f"Serving {path} on port {port}, control-C to stop")
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("Shutting down.")
        httpd.server_close()