Ejemplo n.º 1
0
Archivo: z.py Proyecto: dpla/zen
def get_resource(environ, start_response):
    slaveinfo, space_tag = setup_request(environ)
    #space_tag = shift_path_info(environ)
    
    #Forward the query to the slave, and get the result
    #FIXME: Zen should do some processing in order to assess/override/suppress etc. the rulesheet
    #Though this may be in the form of utility functions for the driver
    resource = slaveinfo.resource_factory()
    
    if resource is None or resource == '':
        start_response(status_response(slaveinfo.resp_status), slaveinfo.resp_headers)
        return ["Unable to access resource\n"]

    imt = requested_imt(environ)
    lang = requested_lang(environ)

    handler = resource.type.run_rulesheet(environ, 'GET', imt, lang)
    rendered = handler(resource)

    headers = [("Content-Type", str(handler.imt))]
    vary_header = "Accept"
    if handler.ttl:
        headers.append(("Cache-Control", "max-age="+str(handler.ttl)))
    if handler.lang:
        vary_header += ",Accept-Language"
        headers.append(("Content-Language", str(handler.lang)))
    headers.append(("Vary",vary_header))

    start_response(status_response(httplib.OK), headers)
    return rendered
Ejemplo n.º 2
0
def moin_error_wrapper(wsgiapp):
    @wraps(wsgiapp)
    def handler(environ, start_response):
        status_info = {}          # Dictionary of collected status information

        # Replacement for the WSGI start_response function.  This merely
        # collects response data in a dictionary for later use if no errors occur
        def local_start_response(status, headers):
            status_info['status'] = status
            status_info['headers'] = headers

        # Try to run the supplied WSGI handler
        try:
            body = wsgiapp(environ, local_start_response)

            # If control reaches here, no errors.  Proceed with normal WSGI response
            start_response(status_info['status'],status_info['headers'])
            return body

        # Error handling for specifying an invalid moin target name (i.e., not configured, misspelled)
        except BadTargetError,e:
            start_response(status_response(httplib.NOT_FOUND), [
                    ('Content-Type','text/plain')
                    ])
            return error_badtarget.safe_substitute(e.parms)

        # Error handling for back-end HTTP authorization failure.  For example,
        # if the HTTP server hosting MoinMoin has rejected our requests due to
        # bad HTTP authorization.
        except HTTPAuthorizationError,e:
            start_response(status_response(httplib.FORBIDDEN), [
                    ('Content-Type','text/plain')
                    ])
            return error_httpforbidden.safe_substitute(e.parms)
Ejemplo n.º 3
0
Archivo: z.py Proyecto: dpla/zen
def post_resource(environ, start_response):
    '''
    Create a new record with a resource type
    '''
    slaveinfo, space_tag = setup_request(environ)

    temp_fpath = read_http_body_to_temp(environ, start_response)
    body = open(temp_fpath, "r").read()

    resource_type = slaveinfo.resource_factory()
    imt = environ['CONTENT_TYPE'].split(';')[0]
    lang = environ.get('CONTENT_LANGUAGE')

    handler = resource_type.run_rulesheet(environ, environ['REQUEST_METHOD'], imt, lang)

    new_path, content = handler(resource_type, body)

    logger.debug('rulesheet transform output & new uri path (post_resource): ' + repr((content[:100], new_path)))

    #Comes back as Unicode, but we need to feed it to slave as encoded byte string
    content = content.encode('utf-8')
    environ['wsgi.input'] = cStringIO.StringIO(content)
    environ['CONTENT_LENGTH'] = len(content)

    response = slaveinfo.create_resource(new_path)

    if not slaveinfo.resp_status.startswith('2'):
        start_response(status_response(slaveinfo.resp_status), slaveinfo.resp_headers)
        return ["Unable to create resource\n"]

    start_response(slaveinfo.resp_status, slaveinfo.resp_headers)
    return response
Ejemplo n.º 4
0
def moin_error_wrapper(wsgiapp):
    @wraps(wsgiapp)
    def handler(environ, start_response):
        status_info = {}  # Dictionary of collected status information

        # Replacement for the WSGI start_response function.  This merely
        # collects response data in a dictionary for later use if no errors occur
        def local_start_response(status, headers):
            status_info['status'] = status
            status_info['headers'] = headers

        # Try to run the supplied WSGI handler
        try:
            body = wsgiapp(environ, local_start_response)

            # If control reaches here, no errors.  Proceed with normal WSGI response
            start_response(status_info['status'], status_info['headers'])
            return body

        # Error handling for specifying an invalid moin target name (i.e., not configured, misspelled)
        except BadTargetError, e:
            start_response(status_response(httplib.NOT_FOUND),
                           [('Content-Type', 'text/plain')])
            return error_badtarget.safe_substitute(e.parms)

        # Error handling for back-end HTTP authorization failure.  For example,
        # if the HTTP server hosting MoinMoin has rejected our requests due to
        # bad HTTP authorization.
        except HTTPAuthorizationError, e:
            start_response(status_response(httplib.FORBIDDEN),
                           [('Content-Type', 'text/plain')])
            return error_httpforbidden.safe_substitute(e.parms)
Ejemplo n.º 5
0
Archivo: z.py Proyecto: dpla/zen
def delete_resource(environ, start_response):
    slaveinfo, space_tag = setup_request(environ)
    response = slaveinfo.delete_resource()
    
    if not slaveinfo.resp_status.startswith('2'):
        start_response(status_response(slaveinfo.resp_status), slaveinfo.resp_headers)
        return ["Unable to delete resource\n"]

    start_response(slaveinfo.resp_status, slaveinfo.resp_headers)
    return response
Ejemplo n.º 6
0
Archivo: couchdb.py Proyecto: dpla/zen
    def prep_slave_response(self, resp):
        '''
        Convert CouchDB response to Zen response
        '''

        # Keep it conservative. etag? cache-control?
        COPY_HEADERS = lambda x: x[0] in ['date','content-type']
        self.resp_headers = filter(COPY_HEADERS,resp.iteritems())

        self.resp_status = status_response(resp.get('status') or '500')
Ejemplo n.º 7
0
Archivo: z.py Proyecto: dpla/zen
def put_resource(environ, start_response):
    slaveinfo, space_tag = setup_request(environ)

    resource_type = check_forced_type(environ, start_response, slaveinfo)

    imt = environ['CONTENT_TYPE'].split(';')[0]
    lang = environ.get('CONTENT_LANGUAGE') #FIXME support multiple 

    temp_fpath = read_http_body_to_temp(environ, start_response)
    body = open(temp_fpath, "r").read()

    if not resource_type:
        resource = slaveinfo.resource_factory()
        resource_type = resource.type

    handler = resource_type.run_rulesheet(environ, environ['REQUEST_METHOD'], imt, lang)

    content = handler(resource_type, body)

    logger.debug('rulesheet transform output (put_resource): ' + repr(content[:100]))

    #Comes back as Unicode, but we need to feed it to slave as encoded byte string
    content = content.encode('utf-8')
    environ['wsgi.input'] = cStringIO.StringIO(content)
    environ['CONTENT_LENGTH'] = len(content)

    #headers = req_headers
    #headers['Content-Type'] = 'text/plain'

    #if creds:
    #    user, passwd = creds
    #    H.add_credentials(user, passwd)
    
    #resp, content = H.request(zenuri_to_moinrest(environ), "PUT", body=wikified.encode('UTF-8'), headers=headers)

    #start_response(status_response(slave_resp_status), [("Content-Type", resp['content-type'])])

    response = slaveinfo.update_resource()

    if not slaveinfo.resp_status.startswith('2'):
        start_response(status_response(slaveinfo.resp_status), slaveinfo.resp_headers)
        return ["Unable to update resource\n"]

    start_response(slaveinfo.resp_status, slaveinfo.resp_headers)
    return response
Ejemplo n.º 8
0
    def handler(environ, start_response):
        status_info = {}  # Dictionary of collected status information

        # Replacement for the WSGI start_response function.  This merely
        # collects response data in a dictionary for later use if no errors occur
        def local_start_response(status, headers):
            status_info['status'] = status
            status_info['headers'] = headers

        # Try to run the supplied WSGI handler
        try:
            body = wsgiapp(environ, local_start_response)

            # If control reaches here, no errors.  Proceed with normal WSGI response
            start_response(status_info['status'], status_info['headers'])
            return body

        # Error handling for specifying an invalid moin target name (i.e., not configured, misspelled)
        except BadTargetError, e:
            start_response(status_response(httplib.NOT_FOUND),
                           [('Content-Type', 'text/plain')])
            return error_badtarget.safe_substitute(e.parms)
Ejemplo n.º 9
0
    def handler(environ, start_response):
        status_info = {}          # Dictionary of collected status information

        # Replacement for the WSGI start_response function.  This merely
        # collects response data in a dictionary for later use if no errors occur
        def local_start_response(status, headers):
            status_info['status'] = status
            status_info['headers'] = headers

        # Try to run the supplied WSGI handler
        try:
            body = wsgiapp(environ, local_start_response)

            # If control reaches here, no errors.  Proceed with normal WSGI response
            start_response(status_info['status'],status_info['headers'])
            return body

        # Error handling for specifying an invalid moin target name (i.e., not configured, misspelled)
        except BadTargetError,e:
            start_response(status_response(httplib.NOT_FOUND), [
                    ('Content-Type','text/plain')
                    ])
            return error_badtarget.safe_substitute(e.parms)
Ejemplo n.º 10
0
def get_page(environ, start_response):
    #logger.debug('get_page: ' + repr((environ['SCRIPT_NAME'], environ['PATH_INFO'])))
    req_headers = copy_headers_to_dict(environ,exclude=['HTTP_ACCEPT_ENCODING'])
    wiki_id, base, opener, original_page, wrapped_wiki_base = target(environ)
    page = environ['PATH_INFO'].lstrip('/')
    check_auth(environ, start_response, base, opener, req_headers)
    upstream_handler = None
    status = httplib.OK
    params = cgi.parse_qs(environ['QUERY_STRING'])
    #Note: probably a better solution here: http://code.google.com/p/mimeparse/
    accepted_imts = environ.get('HTTP_ACCEPT', '').split(',')
    #logger.debug('accepted_imts: ' + repr(accepted_imts))
    imt = first_item(dropwhile(lambda x: '*' in x, accepted_imts))
    #logger.debug('imt: ' + repr(imt))
    params_for_moin = {}
    cache_max_age = CACHE_MAX_AGE # max-age of this response. If set to None, it will not be used
    if NO_CACHE_PATHS and first_item(dropwhile(lambda x: x not in page, NO_CACHE_PATHS)):
        cache_max_age = None

    if 'rev' in params:
        #XXX: Not compatible with search
        #params_for_moin = {'rev' : params['rev'][0], 'action': 'recall'}
        params_for_moin = {'rev' : params['rev'][0]}
    if 'search' in params:
        searchq = params['search'][0]
        query = urllib.urlencode({'value' : searchq, 'action': 'fullsearch', 'context': '180', 'fullsearch': 'Text'})
        #?action=fullsearch&context=180&value=foo&=Text
        url = absolutize('?'+query, base)
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.RDF_IMT
        cache_max_age = None
    #elif 'action' in params and params['action'][0] == 'recall':
    elif moin.HTML_IMT in environ.get('HTTP_ACCEPT', ''):
        params = urllib.urlencode(params_for_moin)
        url = absolutize(page+'?'+params, base)
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.HTML_IMT
    elif moin.RDF_IMT in environ.get('HTTP_ACCEPT', ''):
        #FIXME: Make unique flag optional
        #url = base + '/RecentChanges?action=rss_rc&unique=1&ddiffs=1'
        url = absolutize('RecentChanges?action=rss_rc&unique=1&ddiffs=1', base)
        #print >> sys.stderr, (url, base, '/RecentChanges?action=rss_rc&unique=1&ddiffs=1', )
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.RDF_IMT
    elif moin.ATTACHMENTS_IMT in environ.get('HTTP_ACCEPT', ''):
        url = absolutize(page + '?action=AttachFile', base)
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.ATTACHMENTS_IMT
        def upstream_handler():
            #Sigh.  Sometimes you have to break some Tag soup eggs to make a RESTful omlette
            with closing(opener.open(request)) as resp:
                rbody = resp.read()
            doc = htmlparse(rbody)
            raise_embedded_error(doc)
            attachment_nodes = doc.xml_select(u'//*[contains(@href, "action=AttachFile") and contains(@href, "do=view")]')
            targets = []
            for node in attachment_nodes:
                target = [ param.split('=', 1)[1] for param in node.href.split(u'&') if param.startswith('target=') ][0]
                targets.append(target)
            output = structencoder(indent=u"yes")
            output.feed(
            ROOT(
                E((u'attachments'),
                    (E(u'attachment', {u'href': unicode(t)}) for t in targets)
                )
            ))
            return output.read(), ctype
    #Notes on use of URI parameters - http://markmail.org/message/gw6xbbvx4st6bksw
    elif ';attachment=' in page:
        page, attachment = page.split(';attachment=', 1)
        url = absolutize(page + '?action=AttachFile&do=get&target=' + attachment, base)
        request = urllib2.Request(url, None, req_headers)
        def upstream_handler():
            with closing(opener.open(request)) as resp:
                rbody = resp.read()
            return rbody, dict(resp.info())['content-type']
    #
    elif ';history' in page:
        cache_max_age = None
        page, discard = page.split(';history', 1)
        ctype = moin.XML_IMT
        def upstream_handler():
            revs = scrape_page_history(page, base, opener, req_headers)
            output = structencoder(indent=u"yes")
            output.feed(
            ROOT(
                E((u'history'),
                    (E(u'rev', {u'id': unicode(r['rev']), u'editor': unicode(r['editor']), u'date': unicode(r['date']).replace(' ', 'T')}) for r in revs)
                )
            ))
            return output.read(), ctype
    elif imt:
        params_for_moin.update({'mimetype': imt})
        params = urllib.urlencode(params_for_moin)
        url = absolutize(page, base) + '?' + params
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.DOCBOOK_IMT
    else:
        params_for_moin.update({'action': 'raw'})
        params = urllib.urlencode(params_for_moin)
        url = absolutize(page, base) + '?' + params
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.WIKITEXT_IMT
    try:
        if upstream_handler:
            rbody, ctype = upstream_handler()
        else:
            with closing(opener.open(request)) as resp:
                rbody = resp.read()
        
        #headers = {moin.ORIG_BASE_HEADER: base}
        #moin_base = absolutize(wiki_id, base)
        moin_base_info = base + ' ' + wrapped_wiki_base + ' ' + original_page
        response_headers = [("Content-Type", ctype),
                            ("Vary", "Accept"),
                            (moin.ORIG_BASE_HEADER, moin_base_info)]
        if cache_max_age:
            response_headers.append(("Cache-Control","max-age="+str(cache_max_age)))

        start_response(status_response(status), response_headers)
        return rbody
    except urllib2.URLError, e:
        if e.code == 401:
            raise HTTPAuthorizationError(url=request.get_full_url())
        if e.code == 403:
            raise MoinMustAuthenticateError(url=request.get_full_url(),target=wiki_id)
        if e.code == 404:
            raise MoinNotFoundError(fronturl=request_uri(environ),backurl=url)
        else:
            raise UnexpectedResponseError(url=url,code=e.code,error=str(e))
Ejemplo n.º 11
0
                    ])
            return error_badtarget.safe_substitute(e.parms)

        # Error handling for back-end HTTP authorization failure.  For example,
        # if the HTTP server hosting MoinMoin has rejected our requests due to
        # bad HTTP authorization.
        except HTTPAuthorizationError,e:
            start_response(status_response(httplib.FORBIDDEN), [
                    ('Content-Type','text/plain')
                    ])
            return error_httpforbidden.safe_substitute(e.parms)

        # Error handling for MoinMoin authorization failure.  This occurs
        # if the user and password supplied to MoinMoin is rejected.
        except MoinAuthorizationError,e:
            start_response(status_response(httplib.FORBIDDEN), [
                    ('Content-Type','text/plain')
                    ])
            return error_moinauthforbidden.safe_substitute(e.parms)

        # Error handling for unexpected HTTP status codes
        except UnexpectedResponseError,e:
            start_response(status_response(httplib.INTERNAL_SERVER_ERROR), [
                    ('Content-Type','text/plain')
                    ])
            return error_unexpectedresponse.safe_substitute(e.parms)

        # Authentication required by MoinMoin.  This isn't an error, but we
        # have to translate this into a 401 response to send back to the client
        # in order to get them to supply the appropriate username/password
        except MoinMustAuthenticateError,e:
Ejemplo n.º 12
0
def get_page(environ, start_response):
    #logger.debug('get_page: ' + repr((environ['SCRIPT_NAME'], environ['PATH_INFO'])))
    req_headers = copy_headers_to_dict(environ,
                                       exclude=['HTTP_ACCEPT_ENCODING'])
    wiki_id, base, opener, original_page, wrapped_wiki_base = target(environ)
    page = environ['PATH_INFO'].lstrip('/')
    check_auth(environ, start_response, base, opener, req_headers)
    upstream_handler = None
    status = httplib.OK
    params = cgi.parse_qs(environ['QUERY_STRING'])
    #Note: probably a better solution here: http://code.google.com/p/mimeparse/
    accepted_imts = environ.get('HTTP_ACCEPT', '').split(',')
    #logger.debug('accepted_imts: ' + repr(accepted_imts))
    imt = first_item(dropwhile(lambda x: '*' in x, accepted_imts))
    #logger.debug('imt: ' + repr(imt))
    params_for_moin = {}
    cache_max_age = CACHE_MAX_AGE  # max-age of this response. If set to None, it will not be used
    if NO_CACHE_PATHS and first_item(
            dropwhile(lambda x: x not in page, NO_CACHE_PATHS)):
        cache_max_age = None

    if 'rev' in params:
        #XXX: Not compatible with search
        #params_for_moin = {'rev' : params['rev'][0], 'action': 'recall'}
        params_for_moin = {'rev': params['rev'][0]}
    if 'search' in params:
        searchq = params['search'][0]
        query = urllib.urlencode({
            'value': searchq,
            'action': 'fullsearch',
            'context': '180',
            'fullsearch': 'Text'
        })
        #?action=fullsearch&context=180&value=foo&=Text
        url = absolutize('?' + query, base)
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.RDF_IMT
        cache_max_age = None
    #elif 'action' in params and params['action'][0] == 'recall':
    elif moin.HTML_IMT in environ.get('HTTP_ACCEPT', ''):
        params = urllib.urlencode(params_for_moin)
        url = absolutize(page + '?' + params, base)
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.HTML_IMT
    elif moin.RDF_IMT in environ.get('HTTP_ACCEPT', ''):
        #FIXME: Make unique flag optional
        #url = base + '/RecentChanges?action=rss_rc&unique=1&ddiffs=1'
        url = absolutize('RecentChanges?action=rss_rc&unique=1&ddiffs=1', base)
        #print >> sys.stderr, (url, base, '/RecentChanges?action=rss_rc&unique=1&ddiffs=1', )
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.RDF_IMT
    elif moin.ATTACHMENTS_IMT in environ.get('HTTP_ACCEPT', ''):
        url = absolutize(page + '?action=AttachFile', base)
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.ATTACHMENTS_IMT

        def upstream_handler():
            #Sigh.  Sometimes you have to break some Tag soup eggs to make a RESTful omlette
            with closing(opener.open(request)) as resp:
                rbody = resp.read()
            doc = htmlparse(rbody)
            raise_embedded_error(doc)
            attachment_nodes = doc.xml_select(
                u'//*[contains(@href, "action=AttachFile") and contains(@href, "do=view")]'
            )
            targets = []
            for node in attachment_nodes:
                target = [
                    param.split('=', 1)[1] for param in node.href.split(u'&')
                    if param.startswith('target=')
                ][0]
                targets.append(target)
            output = structencoder(indent=u"yes")
            output.feed(
                ROOT(
                    E((u'attachments'),
                      (E(u'attachment', {u'href': unicode(t)})
                       for t in targets))))
            return output.read(), ctype
    #Notes on use of URI parameters - http://markmail.org/message/gw6xbbvx4st6bksw
    elif ';attachment=' in page:
        page, attachment = page.split(';attachment=', 1)
        url = absolutize(
            page + '?action=AttachFile&do=get&target=' + attachment, base)
        request = urllib2.Request(url, None, req_headers)

        def upstream_handler():
            with closing(opener.open(request)) as resp:
                rbody = resp.read()
            return rbody, dict(resp.info())['content-type']
    #
    elif ';history' in page:
        cache_max_age = None
        page, discard = page.split(';history', 1)
        ctype = moin.XML_IMT

        def upstream_handler():
            revs = scrape_page_history(page, base, opener, req_headers)
            output = structencoder(indent=u"yes")
            output.feed(
                ROOT(
                    E((u'history'), (E(
                        u'rev', {
                            u'id': unicode(r['rev']),
                            u'editor': unicode(r['editor']),
                            u'date': unicode(r['date']).replace(' ', 'T')
                        }) for r in revs))))
            return output.read(), ctype
    elif imt:
        params_for_moin.update({'mimetype': imt})
        params = urllib.urlencode(params_for_moin)
        url = absolutize(page, base) + '?' + params
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.DOCBOOK_IMT
    else:
        params_for_moin.update({'action': 'raw'})
        params = urllib.urlencode(params_for_moin)
        url = absolutize(page, base) + '?' + params
        request = urllib2.Request(url, None, req_headers)
        ctype = moin.WIKITEXT_IMT
    try:
        if upstream_handler:
            rbody, ctype = upstream_handler()
        else:
            with closing(opener.open(request)) as resp:
                rbody = resp.read()

        #headers = {moin.ORIG_BASE_HEADER: base}
        #moin_base = absolutize(wiki_id, base)
        moin_base_info = base + ' ' + wrapped_wiki_base + ' ' + original_page
        response_headers = [("Content-Type", ctype), ("Vary", "Accept"),
                            (moin.ORIG_BASE_HEADER, moin_base_info)]
        if cache_max_age:
            response_headers.append(
                ("Cache-Control", "max-age=" + str(cache_max_age)))

        start_response(status_response(status), response_headers)
        return rbody
    except urllib2.URLError, e:
        if e.code == 401:
            raise HTTPAuthorizationError(url=request.get_full_url())
        if e.code == 403:
            raise MoinMustAuthenticateError(url=request.get_full_url(),
                                            target=wiki_id)
        if e.code == 404:
            raise MoinNotFoundError(fronturl=request_uri(environ), backurl=url)
        else:
            raise UnexpectedResponseError(url=url, code=e.code, error=str(e))
Ejemplo n.º 13
0
            start_response(status_response(httplib.NOT_FOUND),
                           [('Content-Type', 'text/plain')])
            return error_badtarget.safe_substitute(e.parms)

        # Error handling for back-end HTTP authorization failure.  For example,
        # if the HTTP server hosting MoinMoin has rejected our requests due to
        # bad HTTP authorization.
        except HTTPAuthorizationError, e:
            start_response(status_response(httplib.FORBIDDEN),
                           [('Content-Type', 'text/plain')])
            return error_httpforbidden.safe_substitute(e.parms)

        # Error handling for MoinMoin authorization failure.  This occurs
        # if the user and password supplied to MoinMoin is rejected.
        except MoinAuthorizationError, e:
            start_response(status_response(httplib.FORBIDDEN),
                           [('Content-Type', 'text/plain')])
            return error_moinauthforbidden.safe_substitute(e.parms)

        # Error handling for unexpected HTTP status codes
        except UnexpectedResponseError, e:
            start_response(status_response(httplib.INTERNAL_SERVER_ERROR),
                           [('Content-Type', 'text/plain')])
            return error_unexpectedresponse.safe_substitute(e.parms)

        # Authentication required by MoinMoin.  This isn't an error, but we
        # have to translate this into a 401 response to send back to the client
        # in order to get them to supply the appropriate username/password
        except MoinMustAuthenticateError, e:
            start_response(status_response(httplib.UNAUTHORIZED),
                           [('Content-Type', 'text/plain'),