Apache and Python with ModPython #2

Posted 2008. 10. 12. 22:31 by MINOK
= Python API =
여기서부터는 문서량이 너무 많기 때문에 개괄적인 내용만 번역하겠습니다. 죄송합니다. 
복수의 인터프리터 :
mod-python을 사용할 때 파이썬은 실제로 파이썬 그 자체로 쓰여진 걸로 실행되지 않습니다. C language API 실제로는 C를 통해서 호출 되는 거거든요. Python C API는 subinterpreters를 생성하도록 제공 되어집니다. 보다 자세한 내용은  Py_NewInterpreter() 함수에 대한 문서를 통해서 알 수 있습니다. Subinterpreter는 같은 아파치 서버에서 분리된 프로그램을 동작시키는데 매우 유용합니다.  둘은 간섭을 받지 않은 상태로 동작할 수 있습니다.
서버가 시작하거나 mod-python이 초기화 될 때 main함수를 호출하게 됩니다. 그리고 main 인터프리터는 subinterpreter의 자료를 가지고 있고, 처음에는 초기화 되어 있다가 요청이 오면 생성을 합니다. 그리고 계속 재사용하는 것이죠. 메인 인터프리터의 이름은 main_interpreter 이고 다른 인터프리터는 PythonInterp* 를 통해서 제어 됩니다. 기본적인 행동은 아파치의 가상 서버 이름을
통해서 이름을 짓는 것입니다. 이 뜻은 모든 스크립트가 같은 서브 인터프리터를 통해서 실행되지만 다른 건 다르게 실행된다는 말입니다. ㅋㅋ 나도 잘 몰라요! 버철 디렉토리가 틀리면 다르게 실행된다는 말 같은데, 뭐 실제로 테스트 해보지 않았으니까.
여하튼 지금 돌고 있는 인터프리터는  req.interpreter 를 통해서 알아 볼 수 있습니다. 만약 서드파트로 만들어진 C 컴포넌트
요건 Global Interpreter Lock에 접속할 수 있는 간단한 API를 쓸 수 있는 거죠. 여하튼 이건 꼭 main_interpreter에 강제로 set 되어야 합니다. 이건 모듈이 처음 만들어진 파이썬 문맥에서 실행될 수 있고요? 안그러면 에러를 내뱉는다고

Request Handler 의 개괄 설명 :
요청에 대한 단계에서 handler는 기능을 수행합니다. 아파치 처리는 요청을 읽고 헤더를 처리하고 내용을 전달합니다. 모든 단계에서 아파치 또는 modpython에서 제공하는 모듈을 지원합니다. 예를 들어 modpython에서 사용자에 의해 쓰여진 파이썬 코드를 지원합니다. 이는 C코드로 쓰여진 핸들러와 차이점이 없습니다.

핸들러 함수는 다음의 레퍼런스 객체를 리턴해 줍니다. ( 이 메뉴얼에서는 req는 request객체로 부르겠습니다.)

- apache.OK 에러 없이 처리 되었다는 메세지
- apache.DECLINED 현재 처리되는 핸들러에 의해 처리가 되지 않아 아래 핸들러에게 다시 요구를 한다는 메세지
- apache.HTTP_ERROR HTTP_ERROR가 발생했다는 메세지

핸들러는 req.write() 함수를 사용해 클라이언트 통해서 내용을 쓸 수 있습니다. 또 req.read()를 통해서는 POST 요청을 읽을 수
있습니다.
NOTE: 아파치의 디렉토리가 prepended 된다는 데.... prepended 이 단어를 모르겠음.. 사전에 안나옴...

최소한의 핸들러 예제
from mod_python import apachedef requesthandler(req):
req.content_type = "text/plain"
req.write("Hello World!")
return apache.OK

Filter Handler 의 개괄 설명 :
필터 핸들러는 서버에서 들어오고 나가는 데이터를 교체해 주는 역할을 한다. 그 종류에는 input and output 두 종류가 있다.
현재에는 mod_python은 request_level의 필터만을 제공합니다. 이 말은 HTTP request and response의 body만을 필터링함을
뜻합니다. filter handler는 filter object를 받습니다. request object는 filter.req를 통해서 사용할 수 있습니다. 하지만 모든
읽기와 쓰기는 filter 객체의 read와 write를 통해서만 할 수 있습니다. filter는 읽기 객체가 none 객체를 반환하면 닫아야 합니다.
필터의 리턴값이 무시된다. 필터는 핸들러처럼 수행하지 않지만 filter.pass_on()을 통해서 같은 효과를 얻을 수 있습니다.

필터는 꼭 PythonInputFilter 또는 PythonOutputFilter 을 등록해야 하고, Apache Add/SetInputFilter 또는 Add/SetOutputFilter 디렉토리에 들어있어야 합니다.
다음은 outfilter의 전형적인 예입니다. 서버의 모든 .py는 CAPITALIZE 필터를 수행합니다.

PythonOutputFilter capitalize CAPITALIZE
AddOutputFilter CAPITALIZE .py

여기 capitalize.py 코드가 있습니다.

from mod_python import apache
    def outputfilter(filter):
    s = filter.read()
    while s:
        filter.write(s.upper())
        s = filter.read()
        if s is None:
        filter.close()

필터를 프로그래밍할 때는 이 필터가 몇번이고 불려질 수 있다는 점을 기억하라. 예를 들어 하나의 request는 몇번의 필터가 불리어 질 수 있다는 점이 있다. EOS( None returened from a read operation )이 오기 전까지는 계속 불려질 수 있다.

Connection Handler의 개괄 설명 :
커넥션 핸들러는 커넥션을 관리합니다. TCP 커넥션 포인트에서 즉시 시작합니다. HTTP 핸들러와는 다르게 커넥션 핸들러는
Argument를 Connection 을 받습니다. 여기 echo server 의 예가 있습니다.

아파치 서버 셋팅은 다음과 같이 합니다.:
PythonConnectionHandler echo

echo.py 코드는 다음과 같습니다.
from mod_python import apache
    def connectionhandler(conn):
    while 1:
        conn.write(conn.readline())
        return apache.OK


아파치 설명 :
mod_python에서는 아파치 내부에 대한 인터페이스를 제공합니다. 정말 많은 기능을 제공하므로 직접 문서를 읽어보세요.

유틸 / 기타 유틸리티들 :
util 모듈은 웹 개발자에게 유용한 유틸리티들을 제공합니다. 이 유틸리티들은 standard CGI에서와 같은 기능을 제공하고
이는 아파치의 CGI를 직접 호출하기 때문에 보다 더 효율적입니다.
다음과 같은 유틸리티가 있습니다.
FieldStorage Class
Field Class

쿠키 HTTP 상태 관리자 :
넷스케이프에서 표준화된 쿠키를 읽고 저장하는 기능을 합니다.
쿠키 클래스를 사용해서 HTTP State Management 기능을 수행합니다.
여기 예제가 있습니다.
from mod_python import Cookie, apache
import time
    def handler(req):
        cookie = Cookie.Cookie(’eggs’, ’spam’)
        cookie.expires = time.time() + 300
        Cookie.add_cookie(req, cookie)
        req.write(’This response contains a cookie!\n’)
        return apache.OK


세션 :
세션 모듈은 지속적인 연결을 유지할 수 있게 해줍니다.
이 세션 모듈은 BaseSession 클래스를 사용합니다. 하지만 이 클래스를 바로 사용하는 것이 아니라, DbmSessoin 또는
FileSession을 사용해서 접근합니다.
예제는 아래와 같습니다.
from mod_python import Session
    def handler(req):
        session = Session.Session(req)
        try:
            session[’hits’] += 1
        except:
            session[’hits’] = 1
            session.save()
            req.content_type = ’text/plain’
            req.write(’Hits: %d\n’ % session[’hits’])
            return apache.OK


PSP 파이선 서버 페이지 :
파이썬을 ASP나 PHP 처럼 서버사이드 스크립트로 사용할 수 있게 만들어주는 모듈입니다.

= 아파치 설정 지시문 =
아파치 핸들러에 대한 지시문을 설명합니다.
대략 4가지로 나누어집니다. 첫째, Request handler 둘째,Filter 셋째, Connection Handler 넷째, 기타들...
각각은 다음과 같은 문법으로 표현됩니다.
Syntax: Python*Handler Syntax
Context: server config, virtual host
Override: not None
Module: mod python.c

너무 많아서 자세한 사항은 지시문을 읽어보세요.

= 서버 사이드 파이썬 코드 =
파이썬 코드를 HTML에 직접 입력해서 사용할 수 있도록 만들어진 페이지입니다. SSI는 다음과 같은 문법을 갖습니다.
<!--#element attribute=value attribute=value ... -->
3.3 버전 이전 mod_python에서는 SSI를 지원하지 않습니다. 그리고 아파치는 옵션에서 IncludesNOEXEC 를 off로 만들어줘야
합니다. 그렇지 않으면 SSI는 실행 되지 않습니다.

다음은 Global Data에 대한 SSI에 대한 예제입니다.
<!--#python exec="
import cgi, time, os
    def _escape(object):
    return cgi.escape(str(object))
now = time.time()
" -->
<html>
<body>
<pre>
<!--#python eval="_escape(time.asctime(time.localtime(now)))"-->
<!--#python exec="
keys = os.environ.keys()
keys.sort()
for key in keys:
    print >> filter, _escape(key),
    print >> filter, ’=’,
    print >> filter, _escape(repr(os.environ.get(key)))
" -->
</pre>
</body>
</html>

대충 알것 같지 않은가? Global Data를 접근하기 위해서는 아파치의 multithread를 사용해야 한다고 합니다.

= 파이썬 기본 핸들러 =
개발 방법이 참 많다. 기본 핸들러는 빠른 개발을 위해 Zope에서 영감을 받아 만들어졌다.

기본 핸들러는 3가지가 있다. Publisher,PSP,CGI
우선 Publisher를 살펴보자.
아파치 셋팅은 다음과 같이 한다.
<Directory /some/path>
    SetHandler mod_python
    PythonHandler mod_python.publisher
</Directory>

코드는 다음과 같다. hello.py
""" Publisher example """
    def say(req, what="NOTHING"):
    return "I am saying %s" % what
다음의 URL로 접근하면 http://www.mysite.com/hello.py/say  ‘I am saying NOTHING’. 를 반환하고
다음의 URL로 접근하면
http://www.mysite.com/hello.py/say?what=hello‘I am saying hello’.  반환한다.
Form Data는 FieldStorage 클래스를 생성하고 이 클래스를 통해 Request 객체의 form 속성에 저장됩니다.
다음으로 PSP 핸들러를 알아보자.
Python Server Page를 만들려면 아래처럼 http.conf에 셋팅합니다.
AddHandler mod_python .psp
PythonHandler mod_python.psp

디버깅을 위해서는 아래처럼 만듭니다.
AddHandler mod_python .psp .psp_
PythonHandler mod_python.psp
PythonDebug On

언더바를 붙이는 이유는 원래의 코드를 얻을 수 있기 때문에 디버깅에 도움이 된다고 합니다.

마지막으로 CGI 핸들러를 알아보자.
mod_python에서 CGI를 다루기 위해 에뮬레이팅하는 핸들러입니다.
.htaccess에 다음의 줄을 추가시켜줍니다.
SetHandler mod_python
PythonHandler mod_python.cgihandler


= 보안 =
보안에 대한 설명은 modpython의 categorysecury를 참조하세요.