Upgrade to Pro — share decks privately, control downloads, hide ads and more …

wsgi-on-cafebabepy-plone-conf-2018

yotchang4s
November 08, 2018

 wsgi-on-cafebabepy-plone-conf-2018

cafebabepy is yet another Python 3 implementation written in Java that runs on JVM.

This session explains how to run WSGI on cafebabepy.
You can better understand WSGI by knowing how to implement it on cafebabepy.

yotchang4s

November 08, 2018
Tweet

More Decks by yotchang4s

Other Decks in Programming

Transcript

  1. Who am I? ❖ Yoshiaki Shibutani (澁谷 典明) ➢ yotchang4s

    (よっちゃん) https://twitter.com/yotcang4s ❖ Python usage history ➢ I've been using Python for 1 year and 6 month. ❖ Work ➢ I am programming with Scala.
  2. What will I talk about in this session? This session

    explains how to run WSGI on cafebabepy. You can better understand WSGI by knowing how to implement it on cafebabepy.
  3. Table of contents 1. What is cafebabepy? 2. What is

    WSGI? 3. WSGI on cafebabepy 4. DEMO 5. In closing
  4. Overview of cafebabepy cafebabepy is yet another Python 3 implementation

    written in Java that runs on JVM. The name of cafebabepy comes from cafebabe which is the magic number of the Java class file. I've been developing cafebabepy for 1 year and 6 months. I am still developing cafebabepy. cafebabepy does not work perfectly as Python 3...
  5. Start Python 3! 1. Let's use Jython! 2. Jython does

    not support Python 3... 3. and Jython has not been updated since 2015… 4. If so...
  6. Motivation I am a Python beginner. I could not write

    Python. If I make a Python implementation, I should be able to write Python! It's so much fun!! \(^o^)/
  7. Overview of WSGI WSGI is Web Server Gateway Interface. WSGI

    is defined in PEP 333 and PEP 3333. WSGI is a standard interface for connecting Web server and Web application.
  8. Why is WSGI necessary? Before the WSGI was created, Web

    server that Web application can use was different. Because it was implemented in various ways such as mod_python and CGI. Therefore, WSGI was created. WSGI solved the problem in Python by defining standard specifications for connecting Web application and Web server.
  9. PEP 333 PEP 333 is the specification of WSGI made

    for Python 2. However, there was a problem due to Python 3 specification change. It's because Python 3 changed the handling of string and binary. In WSGI, HTTP response body is binary.
  10. Python 2 and Python 3 strings and binaries ❖ Python

    2 ➢ string: unicode ➢ binary: str ❖ Python 3 ➢ string: str ➢ binary: bytes
  11. PEP 3333 PEP 3333 update PEP 333. It's for Python

    3. In Python 3, the Unicode string is 'str' and the binary is 'bytes'. String and binary are separated in Python 3. Therefore, PEP 3333 defined the response body as 'bytes'.
  12. WSGI on cafebabepy Java comes in from here. cafebabepy can

    not handle 'wsgiref' module. Therefore, cafebabepy on the Java Servlet and realizes the WSGI specification. Java Servlet is a specification that runs Web applications in Java.
  13. Flow in which WSGIServlet is executed 1. cafebabepy initialize. 2.

    GET, POST etc. request from client. 3. doGet, doPost, doHead, doTrace, doPut, doDelete and doOptions method is executed. 4. Run the WSGI application endpoint with cafebabepy. 5. Make the result of executing the WSGI application a response.
  14. Make environ dict Create a environ dict with WSGIServlet for

    cafebabepy. WSGIServlet get the request from the client and put it into environ dict.
  15. Create environ dict in Java code WSGIServlet.java private PyObject getEnviron(HttpServletRequest

    req) { LinkedHashMap<PyObject, PyObject> environ = new LinkedHashMap<>(); environ.put(this.runtime.str("REQUEST_METHOD"), this.runtime.str(req.getMethod().toUpperCase())); ... return this.runtime.dict(environ); }
  16. Make start_response start_response is callable. This is the requirement. 1.

    Call start_response from the WSGI application. 2. WSGIServlet holds arguments of start_response called from the WSGI application. WSGIServlet then passes it to the servlet's response. To satisfy these two In WSGI on cafebabepy, start_response is Python code.
  17. Python code to create start_response① cafebabepy/wsgi.py class Server: def __init__(self):

    self._status = None self._response_headers = [] def start_response(self, status, response_headers, exc_info=None): self._status = status; self._response_headers = response_headers @property def status(self): return self._status
  18. Python code to create start_response② cafebabepy/wsgi.py @status.setter def status(self, status):

    self.status = self._status @property def response_headers(self): return self._response_headers @response_headers.setter def response_headers(self, response_headers): self._response_headers = response_headers
  19. Call WSGI application endpoint WSGI on cafebabepy calls the endpoint

    of the WSGI application. The arguments are environ and start_response.
  20. Set endpoint of WSGI application @WebServlet(name = "Hello Plone Conf",

    urlPatterns = {"/*"}, initParams = { @WebInitParam( name = InitParam.MODULE, value = "hello_plone_conf" // WSGI Application module ), @WebInitParam( name = InitParam.FUNCTION, value = "app") // WSGI Application endpoint }) public class HelloPloneConf2018WSGIServlet extends WSGIServlet { }
  21. Initialize WSGIServlet public class WSGIServlet extends HttpServlet { @Override public

    void init(ServletConfig config) { String module = config.getInitParameter(InitParam.MODULE); String function = config.getInitParameter(InitParam.FUNCTION); this.runtime = Python.createRuntime(); PyObject context = this.runtime.evalModule(module); PyObject wsgiModule = this.runtime.evalModule("cafebabepy.wsgi"); this.server = this.runtime.getattr(wsgiModule, "Server").call(); this.startResponse = this.runtime.getattr( this.server, "start_response"); this.function = this.runtime.getattr(context, function); } }
  22. When a request comes to WSGIServer① private void doXXXX(HttpServletRequest req,

    HttpServletResponse resp)  throws IOException { PyObject environ = getEnviron(req); PyObject results = this.function.call(environ, this.startResponse); PyObject status = this.runtime.getattr(this.server, "status"); PyObject headers = this.runtime.getattr(this.server, "response_headers"); int statusCode = Integer.parseInt(status.toJava(String.class) .split(" ")[0]); resp.setStatus(statusCode); ...
  23. When a request comes to WSGIServer② … this.runtime.iter(headers, header ->

    { PyObject[] keyAndValue = new PyObject[2]; int[] i = new int[1]; this.runtime.iter(header, kv -> keyAndValue[i[0]++] = kv); resp.setHeader( keyAndValue[0].toJava(String.class), keyAndValue[1].toJava(String.class) ); });
  24. When a request comes to WSGIServer③ … OutputStream os =

    resp.getOutputStream(); try { this.runtime.iter(results, bytes -> { try { int[] ints = bytes.toJava(int[].class); for (int i : ints) { os.write(i); } } catch (IOException e) { throw new IOExceptionWrapper(e); } }); } catch (IOExceptionWrapper e) { throw e.e; } }
  25. DEMO WSGI application hello_plone_conf_2018.py def app(environ, start_response): start_response("200 OK", [

    ('Content-type', 'text/plain; charset=UTF-8')]) return [ "Hello Plone Conf 2018 Tokyo!!\n" "こんにちはPlone Conf 2018 Tokyo!!" .encode("utf-8") ]
  26. In closing I explained why WSGI is necessary. I explained

    the specification of WSGI. I explained how to realize WSGI with cafebabepy. I will be glad if you understand the outline of the specification of WSGI by my explanation. I'm happy if you understand how to implement WSGI on cafebabepy. This is all for my session.