<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2011 OpenERP s.a. (<http://openerp.com>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

""" WSGI stuffs (proof of concept for now)

This module offers a WSGI interface to OpenERP.

"""

from wsgiref.simple_server import make_server
from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
import httplib
import urllib
import xmlrpclib
import StringIO

import os
import signal
import sys
import time

import openerp
import openerp.tools.config as config
import openerp.service.websrv_lib as websrv_lib

def xmlrpc_return(start_response, service, method, params):
    """ Helper to call a service's method with some params, using a
    wsgi-supplied ``start_response`` callback."""
    # This mimics SimpleXMLRPCDispatcher._marshaled_dispatch() for exception
    # handling.
    try:
        result = openerp.netsvc.dispatch_rpc(service, method, params, None) # TODO auth
        response = xmlrpclib.dumps((result,), methodresponse=1, allow_none=False, encoding=None)
    except openerp.netsvc.OpenERPDispatcherException, e:
        fault = xmlrpclib.Fault(openerp.tools.exception_to_unicode(e.exception), e.traceback)
        response = xmlrpclib.dumps(fault, allow_none=False, encoding=None)
    except:
        exc_type, exc_value, exc_tb = sys.exc_info()
        fault = xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value))
        response = xmlrpclib.dumps(fault, allow_none=None, encoding=None)
    start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)))])
    return [response]

def wsgi_xmlrpc(environ, start_response):
    """ The main OpenERP WSGI handler."""
    if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith('/openerp/xmlrpc'):
        length = int(environ['CONTENT_LENGTH'])
        data = environ['wsgi.input'].read(length)

        params, method = xmlrpclib.loads(data)

        path = environ['PATH_INFO'][len('/openerp/xmlrpc'):]
        if path.startswith('/'): path = path[1:]
        if path.endswith('/'): p = path[:-1]
        path = path.split('/')

        # All routes are hard-coded. Need a way to register addons-supplied handlers.

        # No need for a db segment.
        if len(path) == 1:
            service = path[0]

            if service == 'common':
                if method in ('create_database', 'list', 'server_version'):
                    return xmlrpc_return(start_response, 'db', method, params)
                else:
                    return xmlrpc_return(start_response, 'common', method, params)
        # A db segment must be given.
        elif len(path) == 2:
            service, db_name = path
            params = (db_name,) + params

            if service == 'model':
                return xmlrpc_return(start_response, 'object', method, params)
            elif service == 'report':
                return xmlrpc_return(start_response, 'report', method, params)

        # TODO the body has been read, need to raise an exception (not return None).

def legacy_wsgi_xmlrpc(environ, start_response):
    if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith('/xmlrpc/'):
        length = int(environ['CONTENT_LENGTH'])
        data = environ['wsgi.input'].read(length)
        path = environ['PATH_INFO'][len('/xmlrpc/'):] # expected to be one of db, object, ...

        params, method = xmlrpclib.loads(data)
        return xmlrpc_return(start_response, path, method, params)

def wsgi_jsonrpc(environ, start_response):
    pass

def wsgi_modules(environ, start_response):
    """ WSGI handler dispatching to addons-provided entry points."""
    pass

def wsgi_webdav(environ, start_response):
    if environ['REQUEST_METHOD'] == 'OPTIONS' and environ['PATH_INFO'] == '*':
        return return_options(start_response)

    # Make sure the addons are loaded in the registry, so they have a chance
    # to register themselves in the 'service' layer.
    openerp.pooler.get_db_and_pool('xx', update_module=[], pooljobs=False)

    http_dir = websrv_lib.find_http_service(environ['PATH_INFO'])
    if http_dir:
        environ['PATH_INFO'] = '/' + environ['PATH_INFO'][len(http_dir.path):]
        return http_to_wsgi(http_dir)(environ, start_response)

def return_options(start_response):
    # TODO Microsoft specifi header, see websrv_lib do_OPTIONS 
    options = [('DAV', '1 2'), ('Allow', 'GET HEAD PROPFIND OPTIONS REPORT')]
    start_response("200 OK", [('Content-Length', str(0))] + options)
    return []

def http_to_wsgi(http_dir):
    """
    Turn BaseHTTPRequestHandler into a WSGI entry point.

    Actually the argument is not a bare BaseHTTPRequestHandler but is wrapped
    (as a class, so it needs to be instanciated) in a HTTPDir.

    This code is adapted from wbsrv_lib.MultiHTTPHandler._handle_one_foreign().
    It is a temporary solution: the HTTP sub-handlers (in particular the
    document_webdav addon) have to be WSGIfied.
    """
    def wsgi_handler(environ, start_response):

        # Extract from the WSGI environment the necessary data.
        scheme = environ['wsgi.url_scheme']

        headers = {}
        for key, value in environ.items():
            if key.startswith('HTTP_'):
                key = key[5:].replace('_', '-').title()
                headers[key] = value
            if key == 'CONTENT_LENGTH':
                key = key.replace('_', '-').title()
                headers[key] = value
        if environ.get('Content-Type'):
            headers['Content-Type'] = environ['Content-Type']

        path = urllib.quote(environ.get('PATH_INFO', ''))
        if environ.get('QUERY_STRING'):
            path += '?' + environ['QUERY_STRING']

        request_version = 'HTTP/1.1' # TODO
        request_line = "%s %s %s\n" % (environ['REQUEST_METHOD'], path, request_version)

        class Dummy(object):
            pass

        # Let's pretend we have a server to hand to the handler.
        server = Dummy()
        server.server_name = environ['SERVER_NAME']
        server.server_port = int(environ['SERVER_PORT'])
        con = openerp.service.websrv_lib.noconnection(environ['gunicorn.socket']) # None TODO

        # Initialize the underlying handler and associated auth. provider.
        handler = http_dir.instanciate_handler(openerp.service.websrv_lib.noconnection(con), environ['REMOTE_ADDR'], server)

        # Populate the handler as if it is called by a regular HTTP server
        # and the request is already parsed.
        handler.wfile = StringIO.StringIO()
        handler.rfile = environ['wsgi.input']
        handler.headers = headers
        handler.command = environ['REQUEST_METHOD']
        handler.path = path
        handler.request_version = request_version
        handler.close_connection = 1
        handler.raw_requestline = request_line
        handler.requestline = request_line

        # Handle authentication if there is an auth. provider associated to
        # the handler.
        if hasattr(handler, 'auth_provider'):
            try:
                handler.auth_provider.checkRequest(handler, path)
            except websrv_lib.AuthRequiredExc, ae:
                # Darwin 9.x.x webdav clients will report "HTTP/1.0" to us, while they support (and need) the
                # authorisation features of HTTP/1.1 
                if request_version != 'HTTP/1.1' and ('Darwin/9.' not in handler.headers.get('User-Agent', '')):
                    print 'self.log_error("Cannot require auth at %s", self.request_version)'
                    start_response("403 Forbidden", [])
                    return []
                start_response("401 Authorization required", [
                    ('WWW-Authenticate', '%s realm="%s"' % (ae.atype,ae.realm)),
                    # ('Connection', 'keep-alive'),
                    ('Content-Type', 'text/html'),
                    ('Content-Length', 4), # len(self.auth_required_msg)
                    ])
                return ['Blah'] # self.auth_required_msg
            except websrv_lib.AuthRejectedExc,e:
                print '("Rejected auth: %s" % e.args[0])'
                start_response("403 %s" % (e.args[0],))
                return []

        method_name = 'do_' + handler.command

        # Support the OPTIONS method even when not provided directly by the
        # handler. TODO I would prefer to remove it and fix the handler if
        # needed.
        if not hasattr(handler, method_name):
            if handler.command == 'OPTIONS':
                return return_options(start_response)
            start_response("501 Unsupported method (%r)" % handler.command)
            return []<commit_msg>[FIX] wsgi: missing argument to start_response, add "/" prefix only when needed.<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2011 OpenERP s.a. (<http://openerp.com>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

""" WSGI stuffs (proof of concept for now)

This module offers a WSGI interface to OpenERP.

"""

from wsgiref.simple_server import make_server
from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
import httplib
import urllib
import xmlrpclib
import StringIO

import os
import signal
import sys
import time

import openerp
import openerp.tools.config as config
import openerp.service.websrv_lib as websrv_lib

def xmlrpc_return(start_response, service, method, params):
    """ Helper to call a service's method with some params, using a
    wsgi-supplied ``start_response`` callback."""
    # This mimics SimpleXMLRPCDispatcher._marshaled_dispatch() for exception
    # handling.
    try:
        result = openerp.netsvc.dispatch_rpc(service, method, params, None) # TODO auth
        response = xmlrpclib.dumps((result,), methodresponse=1, allow_none=False, encoding=None)
    except openerp.netsvc.OpenERPDispatcherException, e:
        fault = xmlrpclib.Fault(openerp.tools.exception_to_unicode(e.exception), e.traceback)
        response = xmlrpclib.dumps(fault, allow_none=False, encoding=None)
    except:
        exc_type, exc_value, exc_tb = sys.exc_info()
        fault = xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value))
        response = xmlrpclib.dumps(fault, allow_none=None, encoding=None)
    start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)))])
    return [response]

def wsgi_xmlrpc(environ, start_response):
    """ The main OpenERP WSGI handler."""
    if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith('/openerp/xmlrpc'):
        length = int(environ['CONTENT_LENGTH'])
        data = environ['wsgi.input'].read(length)

        params, method = xmlrpclib.loads(data)

        path = environ['PATH_INFO'][len('/openerp/xmlrpc'):]
        if path.startswith('/'): path = path[1:]
        if path.endswith('/'): p = path[:-1]
        path = path.split('/')

        # All routes are hard-coded. Need a way to register addons-supplied handlers.

        # No need for a db segment.
        if len(path) == 1:
            service = path[0]

            if service == 'common':
                if method in ('create_database', 'list', 'server_version'):
                    return xmlrpc_return(start_response, 'db', method, params)
                else:
                    return xmlrpc_return(start_response, 'common', method, params)
        # A db segment must be given.
        elif len(path) == 2:
            service, db_name = path
            params = (db_name,) + params

            if service == 'model':
                return xmlrpc_return(start_response, 'object', method, params)
            elif service == 'report':
                return xmlrpc_return(start_response, 'report', method, params)

        # TODO the body has been read, need to raise an exception (not return None).

def legacy_wsgi_xmlrpc(environ, start_response):
    if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith('/xmlrpc/'):
        length = int(environ['CONTENT_LENGTH'])
        data = environ['wsgi.input'].read(length)
        path = environ['PATH_INFO'][len('/xmlrpc/'):] # expected to be one of db, object, ...

        params, method = xmlrpclib.loads(data)
        return xmlrpc_return(start_response, path, method, params)

def wsgi_jsonrpc(environ, start_response):
    pass

def wsgi_modules(environ, start_response):
    """ WSGI handler dispatching to addons-provided entry points."""
    pass

def wsgi_webdav(environ, start_response):
    if environ['REQUEST_METHOD'] == 'OPTIONS' and environ['PATH_INFO'] == '*':
        return return_options(start_response)

    # Make sure the addons are loaded in the registry, so they have a chance
    # to register themselves in the 'service' layer.
    openerp.pooler.get_db_and_pool('xx', update_module=[], pooljobs=False)

    http_dir = websrv_lib.find_http_service(environ['PATH_INFO'])
    if http_dir:
        path = environ['PATH_INFO'][len(http_dir.path):]
        if path.startswith('/'):
            environ['PATH_INFO'] = path
        else:
            environ['PATH_INFO'] = '/' + npath
        return http_to_wsgi(http_dir)(environ, start_response)

def return_options(start_response):
    # TODO Microsoft specifi header, see websrv_lib do_OPTIONS 
    options = [('DAV', '1 2'), ('Allow', 'GET HEAD PROPFIND OPTIONS REPORT')]
    start_response("200 OK", [('Content-Length', str(0))] + options)
    return []

def http_to_wsgi(http_dir):
    """
    Turn BaseHTTPRequestHandler into a WSGI entry point.

    Actually the argument is not a bare BaseHTTPRequestHandler but is wrapped
    (as a class, so it needs to be instanciated) in a HTTPDir.

    This code is adapted from wbsrv_lib.MultiHTTPHandler._handle_one_foreign().
    It is a temporary solution: the HTTP sub-handlers (in particular the
    document_webdav addon) have to be WSGIfied.
    """
    def wsgi_handler(environ, start_response):

        # Extract from the WSGI environment the necessary data.
        scheme = environ['wsgi.url_scheme']

        headers = {}
        for key, value in environ.items():
            if key.startswith('HTTP_'):
                key = key[5:].replace('_', '-').title()
                headers[key] = value
            if key == 'CONTENT_LENGTH':
                key = key.replace('_', '-').title()
                headers[key] = value
        if environ.get('Content-Type'):
            headers['Content-Type'] = environ['Content-Type']

        path = urllib.quote(environ.get('PATH_INFO', ''))
        if environ.get('QUERY_STRING'):
            path += '?' + environ['QUERY_STRING']

        request_version = 'HTTP/1.1' # TODO
        request_line = "%s %s %s\n" % (environ['REQUEST_METHOD'], path, request_version)

        class Dummy(object):
            pass

        # Let's pretend we have a server to hand to the handler.
        server = Dummy()
        server.server_name = environ['SERVER_NAME']
        server.server_port = int(environ['SERVER_PORT'])
        con = openerp.service.websrv_lib.noconnection(environ['gunicorn.socket']) # None TODO

        # Initialize the underlying handler and associated auth. provider.
        handler = http_dir.instanciate_handler(openerp.service.websrv_lib.noconnection(con), environ['REMOTE_ADDR'], server)

        # Populate the handler as if it is called by a regular HTTP server
        # and the request is already parsed.
        handler.wfile = StringIO.StringIO()
        handler.rfile = environ['wsgi.input']
        handler.headers = headers
        handler.command = environ['REQUEST_METHOD']
        handler.path = path
        handler.request_version = request_version
        handler.close_connection = 1
        handler.raw_requestline = request_line
        handler.requestline = request_line

        # Handle authentication if there is an auth. provider associated to
        # the handler.
        if hasattr(handler, 'auth_provider'):
            try:
                handler.auth_provider.checkRequest(handler, path)
            except websrv_lib.AuthRequiredExc, ae:
                # Darwin 9.x.x webdav clients will report "HTTP/1.0" to us, while they support (and need) the
                # authorisation features of HTTP/1.1 
                if request_version != 'HTTP/1.1' and ('Darwin/9.' not in handler.headers.get('User-Agent', '')):
                    print 'self.log_error("Cannot require auth at %s", self.request_version)'
                    start_response("403 Forbidden", [])
                    return []
                start_response("401 Authorization required", [
                    ('WWW-Authenticate', '%s realm="%s"' % (ae.atype,ae.realm)),
                    # ('Connection', 'keep-alive'),
                    ('Content-Type', 'text/html'),
                    ('Content-Length', 4), # len(self.auth_required_msg)
                    ])
                return ['Blah'] # self.auth_required_msg
            except websrv_lib.AuthRejectedExc,e:
                print '("Rejected auth: %s" % e.args[0])'
                start_response("403 %s" % (e.args[0],), [])
                return []

        method_name = 'do_' + handler.command

        # Support the OPTIONS method even when not provided directly by the
        # handler. TODO I would prefer to remove it and fix the handler if
        # needed.
        if not hasattr(handler, method_name):
            if handler.command == 'OPTIONS':
                return return_options(start_response)
            start_response("501 Unsupported method (%r)" % handler.command, [])
            return []
{'fraction_non_alphanumeric': 0.1259032073608151, 'fraction_numerical': 0.005094349430784426, 'mean_word_length': 2.7714173691433053, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 42}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3658869', 'n_tokens_mistral': 5583, 'n_tokens_neox': 5389, 'n_words': 1569}