예제 #1
0
def staticdir(section,
              dir,
              root="",
              match="",
              content_types=None,
              index="",
              generate_indexes=False):
    """Serve a static resource from the given (root +) dir.
    
    If 'match' is given, request.path_info will be searched for the given
    regular expression before attempting to serve static content.
    
    If content_types is given, it should be a Python dictionary of
    {file-extension: content-type} pairs, where 'file-extension' is
    a string (e.g. "gif") and 'content-type' is the value to write
    out in the Content-Type response header (e.g. "image/gif").
    
    If 'index' is provided, it should be the (relative) name of a file to
    serve for directory requests. For example, if the dir argument is
    '/home/me', the Request-URI is 'myapp', and the index arg is
    'index.html', the file '/home/me/myapp/index.html' will be sought.
    """
    if cherrypy.request.method not in ('GET', 'HEAD'):
        return False

    if match and not re.search(match, cherrypy.request.path_info):
        return False

    # Allow the use of '~' to refer to a user's home directory.
    dir = os.path.expanduser(dir)

    # If dir is relative, make absolute using "root".
    if not os.path.isabs(dir):
        if not root:
            msg = "Static dir requires an absolute dir (or root)."
            raise ValueError(msg)
        dir = os.path.join(root, dir)

    # Determine where we are in the object tree relative to 'section'
    # (where the static tool was defined).
    if section == 'global':
        section = "/"
    section = section.rstrip(r"\/")
    branch = cherrypy.request.path_info[len(section) + 1:]
    branch = urllib.unquote(branch.lstrip(r"\/"))

    # If branch is "", filename will end in a slash
    filename = os.path.join(dir, branch)

    # There's a chance that the branch pulled from the URL might
    # have ".." or similar uplevel attacks in it. Check that the final
    # filename is a child of dir.
    if not os.path.normpath(filename).startswith(os.path.normpath(dir)):
        raise cherrypy.HTTPError(403)  # Forbidden

    handled = _attempt(filename, content_types)
    if not handled:
        # Check for an index file if a folder was requested.
        if index:
            handled = _attempt(os.path.join(filename, index), content_types)
            if handled:
                cherrypy.request.is_index = filename[-1] in (r"\/")
        if not handled and generate_indexes:
            if callable(generate_indexes):
                handled = generate_indexes(filename, branch)
            else:
                handled = render_index(filename, branch)
    return handled
예제 #2
0
    def index(self, **kwargs):
        """ Output a search result page. """

        os = BaseSearcher.OpenSearch()
        os.log_request('search')

        if 'default_prefix' in kwargs:
            raise cherrypy.HTTPError(
                400, 'Bad Request. Unknown parameter: default_prefix')

        if os.start_index > BaseSearcher.MAX_RESULTS:
            raise cherrypy.HTTPError(
                400, 'Bad Request. Parameter start_index too high')

        sql = BaseSearcher.SQLStatement()
        sql.query = 'SELECT *'
        sql.from_ = ['v_appserver_books_4 as books']

        # let derived classes prepare the query
        try:
            self.setup(os, sql)
        except ValueError as what:
            raise cherrypy.HTTPError(400, 'Bad Request. ' + str(what))

        os.fix_sortorder()

        # execute the query
        try:
            BaseSearcher.SQLSearcher().search(os, sql)
        except DatabaseError as what:
            cherrypy.log("SQL Error: " + str(what),
                         context='REQUEST',
                         severity=logging.ERROR)
            raise cherrypy.HTTPError(400, 'Bad Request. Check your query.')

        # sync os.title and first entry header
        if os.entries:
            entry = os.entries[0]
            if os.title and not entry.header:
                entry.header = os.title
            elif entry.header and not os.title:
                os.title = entry.header

        os.template = os.page = 'results'

        # give derived class a chance to tweak result set
        self.fixup(os)

        # warn user about no records found
        if os.total_results == 0:
            self.nothing_found(os)

        # suggest alternate queries
        if os.total_results < 5:
            self.output_suggestions(os)

        # add sort by links
        if os.start_index == 1 and os.total_results > 1:
            if 'downloads' in os.alternate_sort_orders:
                self.sort_by_downloads(os)
            if 'release_date' in os.alternate_sort_orders:
                self.sort_by_release_date(os)
            if 'title' in os.alternate_sort_orders:
                self.sort_by_title(os)
            if 'alpha' in os.alternate_sort_orders:
                self.sort_alphabetically(os)
            if 'author' in os.alternate_sort_orders:
                self.sort_by_author(os)
            if 'quantity' in os.alternate_sort_orders:
                self.sort_by_quantity(os)

        os.finalize()
        self.finalize(os)

        if os.total_results > 0:
            # call this after finalize ()
            os.entries.insert(0, self.status_line(os))

        return self.format(os)
예제 #3
0
    def find_acceptable_charset(self):
        request = cherrypy.serving.request
        response = cherrypy.serving.response

        if self.debug:
            cherrypy.log('response.stream %r' % response.stream,
                         'TOOLS.ENCODE')
        if response.stream:
            encoder = self.encode_stream
        else:
            encoder = self.encode_string
            if 'Content-Length' in response.headers:
                # Delete Content-Length header so finalize() recalcs it.
                # Encoded strings may be of different lengths from their
                # unicode equivalents, and even from each other. For example:
                # >>> t = u"\u7007\u3040"
                # >>> len(t)
                # 2
                # >>> len(t.encode("UTF-8"))
                # 6
                # >>> len(t.encode("utf7"))
                # 8
                del response.headers['Content-Length']

        # Parse the Accept-Charset request header, and try to provide one
        # of the requested charsets (in order of user preference).
        encs = request.headers.elements('Accept-Charset')
        charsets = [enc.value.lower() for enc in encs]
        if self.debug:
            cherrypy.log('charsets %s' % repr(charsets), 'TOOLS.ENCODE')

        if self.encoding is not None:
            # If specified, force this encoding to be used, or fail.
            encoding = self.encoding.lower()
            if self.debug:
                cherrypy.log('Specified encoding %r' % encoding,
                             'TOOLS.ENCODE')
            if (not charsets) or '*' in charsets or encoding in charsets:
                if self.debug:
                    cherrypy.log('Attempting encoding %r' % encoding,
                                 'TOOLS.ENCODE')
                if encoder(encoding):
                    return encoding
        else:
            if not encs:
                if self.debug:
                    cherrypy.log(
                        'Attempting default encoding %r' %
                        self.default_encoding, 'TOOLS.ENCODE')
                # Any character-set is acceptable.
                if encoder(self.default_encoding):
                    return self.default_encoding
                else:
                    raise cherrypy.HTTPError(
                        500, self.failmsg % self.default_encoding)
            else:
                for element in encs:
                    if element.qvalue > 0:
                        if element.value == '*':
                            # Matches any charset. Try our default.
                            if self.debug:
                                cherrypy.log(
                                    'Attempting default encoding due '
                                    'to %r' % element, 'TOOLS.ENCODE')
                            if encoder(self.default_encoding):
                                return self.default_encoding
                        else:
                            encoding = element.value
                            if self.debug:
                                cherrypy.log(
                                    'Attempting encoding %s (qvalue >'
                                    '0)' % element, 'TOOLS.ENCODE')
                            if encoder(encoding):
                                return encoding

                if '*' not in charsets:
                    # If no "*" is present in an Accept-Charset field, then all
                    # character sets not explicitly mentioned get a quality
                    # value of 0, except for ISO-8859-1, which gets a quality
                    # value of 1 if not explicitly mentioned.
                    iso = 'iso-8859-1'
                    if iso not in charsets:
                        if self.debug:
                            cherrypy.log('Attempting ISO-8859-1 encoding',
                                         'TOOLS.ENCODE')
                        if encoder(iso):
                            return iso

        # No suitable encoding found.
        ac = request.headers.get('Accept-Charset')
        if ac is None:
            msg = 'Your client did not send an Accept-Charset header.'
        else:
            msg = 'Your client sent this Accept-Charset header: %s.' % ac
        _charsets = ', '.join(sorted(self.attempted_charsets))
        msg += ' We tried these charsets: %s.' % (_charsets, )
        raise cherrypy.HTTPError(406, msg)
예제 #4
0
    def run(self, method, path, query_string, req_protocol, headers, rfile):
        r"""Process the Request. (Core)

        method, path, query_string, and req_protocol should be pulled directly
        from the Request-Line (e.g. "GET /path?key=val HTTP/1.0").

        path
            This should be %XX-unquoted, but query_string should not be.

            When using Python 2, they both MUST be byte strings,
            not unicode strings.

            When using Python 3, they both MUST be unicode strings,
            not byte strings, and preferably not bytes \x00-\xFF
            disguised as unicode.

        headers
            A list of (name, value) tuples.

        rfile
            A file-like object containing the HTTP request entity.

        When run() is done, the returned object should have 3 attributes:

          * status, e.g. "200 OK"
          * header_list, a list of (name, value) tuples
          * body, an iterable yielding strings

        Consumer code (HTTP servers) should then access these response
        attributes to build the outbound stream.

        """
        response = cherrypy.serving.response
        self.stage = 'run'
        try:
            self.error_response = cherrypy.HTTPError(500).set_response

            self.method = method
            path = path or '/'
            self.query_string = query_string or ''
            self.params = {}

            # Compare request and server HTTP protocol versions, in case our
            # server does not support the requested protocol. Limit our output
            # to min(req, server). We want the following output:
            #     request    server     actual written   supported response
            #     protocol   protocol  response protocol    feature set
            # a     1.0        1.0           1.0                1.0
            # b     1.0        1.1           1.1                1.0
            # c     1.1        1.0           1.0                1.0
            # d     1.1        1.1           1.1                1.1
            # Notice that, in (b), the response will be "HTTP/1.1" even though
            # the client only understands 1.0. RFC 2616 10.5.6 says we should
            # only return 505 if the _major_ version is different.
            rp = int(req_protocol[5]), int(req_protocol[7])
            sp = int(self.server_protocol[5]), int(self.server_protocol[7])
            self.protocol = min(rp, sp)
            response.headers.protocol = self.protocol

            # Rebuild first line of the request (e.g. "GET /path HTTP/1.0").
            url = path
            if query_string:
                url += '?' + query_string
            self.request_line = '%s %s %s' % (method, url, req_protocol)

            self.header_list = list(headers)
            self.headers = httputil.HeaderMap()

            self.rfile = rfile
            self.body = None

            self.cookie = SimpleCookie()
            self.handler = None

            # path_info should be the path from the
            # app root (script_name) to the handler.
            self.script_name = self.app.script_name
            self.path_info = pi = path[len(self.script_name):]

            self.stage = 'respond'
            self.respond(pi)

        except self.throws:
            raise
        except Exception:
            if self.throw_errors:
                raise
            else:
                # Failure in setup, error handler or finalize. Bypass them.
                # Can't use handle_error because we may not have hooks yet.
                cherrypy.log(traceback=True, severity=40)
                if self.show_tracebacks:
                    body = format_exc()
                else:
                    body = ''
                r = bare_error(body)
                response.output_status, response.header_list, response.body = r

        if self.method == 'HEAD':
            # HEAD requests MUST NOT return a message-body in the response.
            response.body = []

        try:
            cherrypy.log.access()
        except Exception:
            cherrypy.log.error(traceback=True)

        return response
예제 #5
0
def ssh_connect(hostname=None, username=None, password=None):
    if slycat.web.server.config["slycat-web-server"]["remote-authentication"][
            "method"] != "certificate":
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(hostname=hostname, username=username, password=password)
        ssh.get_transport().set_keepalive(5)
    else:
        import requests
        import tempfile
        num_bits = 2056
        # create the private key
        pvt_key = paramiko.RSAKey.generate(num_bits)
        # create the public key
        pub_key = "ssh-rsa " + pvt_key.get_base64()  # SSO specific format
        # pub_key = "ssh-rsa " + pvt_key.get_base64()
        # + " " + principal + "\n"  # General Format, principal is <username>@<hostname>
        cherrypy.log.error(
            "ssh_connect cert method, POST to sso-auth-server for user: %s" %
            cherrypy.request.login)
        r = requests.post(slycat.web.server.config["slycat-web-server"]
                          ["sso-auth-server"]["url"],
                          cert=(slycat.web.server.config["slycat-web-server"]
                                ["ssl-certificate"]["cert-path"],
                                slycat.web.server.config["slycat-web-server"]
                                ["ssl-certificate"]["key-path"]),
                          data='{"principal": "' + cherrypy.request.login +
                          '", "pubkey": "' + pub_key + '"}',
                          headers={"Content-Type": "application/json"},
                          verify=False)

        cherrypy.log.error("ssh_connect cert method, POST result: %s" % str(r))
        # create a cert file obj
        # cert_file_object = tempfile.TemporaryFile().write(str(r.json()["certificate"])).seek(0) #this line crashes
        cert_file_object = tempfile.TemporaryFile()
        cert_file_object.write(str(r.json()["certificate"]))
        cert_file_object.seek(0)
        # create a key file obj
        key_file_object = tempfile.TemporaryFile()
        pvt_key.write_private_key(key_file_object)
        key_file_object.seek(0)
        # create the cert used for auth
        cert = paramiko.RSACert(privkey_file_obj=key_file_object,
                                cert_file_obj=cert_file_object)
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        cherrypy.log.error(
            "ssh_connect cert method, calling ssh.connect for user: %s" %
            cherrypy.request.login)
        import traceback
        try:
            ssh.connect(hostname=hostname,
                        username=cherrypy.request.login,
                        pkey=cert,
                        port=slycat.web.server.config["slycat-web-server"]
                        ["remote-authentication"]["port"])
        except paramiko.AuthenticationException as e:
            cherrypy.log.error(
                "ssh_connect cert method, authentication failed for %s@%s: %s"
                % (cherrypy.request.login, hostname, str(e)))
            cherrypy.log.error(
                "ssh_connect cert method, called ssh.connect traceback: %s" %
                traceback.print_exc())
            raise cherrypy.HTTPError("403 Remote authentication failed.")
        ssh.get_transport().set_keepalive(5)
        cert_file_object.close()
        key_file_object.close()
    return ssh
예제 #6
0
    def matches(self, n=0):
        n = int(n)
        event = self.getevent()
        datapath = 'data_' + event + '.db'
        self.database_exists(event)
        conn = sql.connect(datapath)
        cursor = conn.cursor()
        m = []

        headers = {"X-TBA-App-Id": "frc2067:scouting-system:v01"}
        try:
            if n:
                # request a specific team
                m = requests.get(
                    "http://www.thebluealliance.com/api/v2/team/frc{0}/event/{1}/matches"
                    .format(n, event),
                    params=headers)
            else:
                # get all the matches from this event
                m = requests.get(
                    "http://www.thebluealliance.com/api/v2/event/{0}/matches".
                    format(event),
                    params=headers)
            if m.status_code == 400:
                raise cherrypy.HTTPError(
                    400, "Request rejected by The Blue Alliance.")
            with open(event + "_matches.json", "w+") as file:
                file.write(str(m.text))
            m = m.json()
        except:
            try:
                with open(event + '_matches.json') as matches_data:
                    m = json.load(matches_data)
            except:
                m = []

        output = ''

        if 'feed' in m:
            raise cherrypy.HTTPError(
                503, "Unable to retrieve data about this event.")

        # assign weights, so we can sort the matches
        for match in m:
            match['value'] = match['match_number']
            type = match['comp_level']
            if type == 'qf':
                match['value'] += 1000
            elif type == 'sf':
                match['value'] += 2000
            elif type == 'f':
                match['value'] += 3000

        m = sorted(m, key=lambda k: k['value'])
        for match in m:
            if match['comp_level'] != 'qm':
                match['num'] = match['comp_level'].upper() + ' ' + str(
                    match['match_number'])
            else:
                match['num'] = match['match_number']
            output += '''
                <tr>
                    <td><a href="alliances?b1={1}&b2={2}&b3={3}&r1={4}&r2={5}&r3={6}">{0}</a></td>
                    <td><a href="team?n={1}">{1}</a></td>
                    <td><a href="team?n={2}">{2}</a></td>
                    <td><a href="team?n={3}">{3}</a></td>
                    <td><a href="team?n={4}">{4}</a></td>
                    <td><a href="team?n={5}">{5}</a></td>
                    <td><a href="team?n={6}">{6}</a></td>
                    <td>{7}</td>
                    <td>{8}</td>
                </tr>
                '''.format(match['num'],
                           match['alliances']['blue']['teams'][0][3:],
                           match['alliances']['blue']['teams'][1][3:],
                           match['alliances']['blue']['teams'][2][3:],
                           match['alliances']['red']['teams'][0][3:],
                           match['alliances']['red']['teams'][1][3:],
                           match['alliances']['red']['teams'][2][3:],
                           match['alliances']['blue']['score'],
                           match['alliances']['red']['score'])

        return '''
                <html>
                <head>
                    <title>PiScout</title>
                    <link href="https://fonts.googleapis.com/css?family=Oxygen" rel="stylesheet" type="text/css">
                    <link href="/static/css/style.css" rel="stylesheet">
                </head>
                <body>
                    <h1>Matches{0}</h1>
                    <h2><a style="color: #B20000" href='/'>PiScout Database</a></h2>
                    <br><br>
                    <table>
                    <thead><tr>
                        <th>Match</th>
                        <th>Blue 1</th>
                        <th>Blue 2</th>
                        <th>Blue 3</th>
                        <th>Red 1</th>
                        <th>Red 2</th>
                        <th>Red 3</th>
                        <th>Blue Score</th>
                        <th>Red Score</th>
                    </tr></thead>
                    <tbody>
                    {1}
                    </tbody>
                    </table>
                </body>
                </html>
            '''.format(": {}".format(n) if n else "", output)
예제 #7
0
파일: dispatchers.py 프로젝트: xieydd/mtt
    def POST(self, **kwargs):
        prefix = '[POST /submit/]'
        self.logger.debug(prefix)

        if not hasattr(cherrypy.request, "json"):
            self.logger.error(prefix + " No json data sent")
            raise cherrypy.HTTPError(400)

        data = cherrypy.request.json
        if 'metadata' not in data.keys():
            self.logger.error(prefix + " No 'metadata' in json data")
            raise cherrypy.HTTPError(400)

        self.logger.debug(
            "----------------------- All Data JSON (Start) ------------------ "
        )
        self.logger.debug( json.dumps( data, \
                                       sort_keys=True, \
                                       indent=4, \
                                       separators=(',', ': ') ) )
        self.logger.debug(
            "----------------------- All Data JSON (End  ) ------------------ "
        )

        data['metadata']['http_username'] = self._extract_http_username(
            cherrypy.request.headers['Authorization'])
        self.logger.debug(prefix + " Append to metadata 'http_username' = '" +
                          data['metadata']['http_username'] + "'")

        #
        # Make sure we have all the metadata we need
        #
        rtn = self._validate_metadata(data['metadata'])
        if rtn is not None:
            return rtn

        #
        # Convert the phase
        #
        phase = self._convert_phase(data["metadata"]['phase'])
        if phase == self._phase_unknown:
            return self._return_error(
                prefix, -1,
                "%s An unknown phase (%s) was specified in the metadata" %
                (prefix, data["metadata"]["phase"]))

        self.logger.debug("Phase: %2d = [%s]" %
                          (phase, data["metadata"]['phase']))

        if 'data' not in data.keys():
            self.logger.error(prefix + " No 'data' array in json data")
            raise cherrypy.HTTPError(400)

        rtn = {}

        #
        # Pushing data to the database
        #
        if 'data' in data.keys():
            #
            # Get the submission id
            # The client could be submitting one they want us to use,
            # otherwise create a new one.
            #
            submit_info = {}
            if 'submit_id' in data['metadata'].keys(
            ) and data['metadata']['submit_id'] > 0:
                self.logger.debug("************** submit_id: Existing %s" %
                                  (str(data['metadata']['submit_id'])))
                submit_info = {'submit_id': data['metadata']['submit_id']}
            else:
                self.logger.debug("************** submit_id: New...")
                rtn = self._validate_submit(data['metadata'])
                if rtn is not None:
                    return rtn
                submit_info = self._db.get_submit_id(data['metadata'])
                if "submit_id" not in submit_info.keys():
                    return self._return_error(
                        prefix, -1,
                        "%s Failed [%s]" % (prefix, submit_info['error_msg']))
            #
            # Submit each entry to the database
            #
            ids = []
            for entry in data['data']:
                value = None

                if phase is self._phase_mpi_install:
                    rtn = self._validate_mpi_install(submit_info['submit_id'],
                                                     data['metadata'], entry)
                    if rtn is not None:
                        return rtn
                    value = self._db.insert_mpi_install(
                        submit_info['submit_id'], data['metadata'], entry)
                elif phase is self._phase_test_build:
                    rtn = self._validate_test_build(submit_info['submit_id'],
                                                    data['metadata'], entry)
                    if rtn is not None:
                        return rtn
                    value = self._db.insert_test_build(
                        submit_info['submit_id'], data['metadata'], entry)
                elif phase is self._phase_test_run:
                    rtn = self._validate_test_run(submit_info['submit_id'],
                                                  data['metadata'], entry)
                    if rtn is not None:
                        return rtn
                    value = self._db.insert_test_run(submit_info['submit_id'],
                                                     data['metadata'], entry)
                else:
                    self.logger.error("Unkown phase...")

                if value is None:
                    #ids.append( {'error':'failed to submit this run'} )
                    return self._return_error(
                        prefix, -1,
                        "%s Failed to submit an entry (unknown reason)" %
                        (prefix))
                elif 'error_msg' in value.keys():
                    return self._return_error(prefix, -2, value['error_msg'])
                else:
                    ids.append(value)

            #
            # Return the ids for each of those submissions
            #
            rtn['ids'] = ids
            rtn['submit_id'] = submit_info['submit_id']

        #
        # Pulling data from the database
        #
        elif 'query' in data.keys():
            #
            # Execute query
            #
            table_name = data['query']['table_name']
            if 'filters' in data['query'].keys():
                filters = [
                    f['filter_left'] + " " + f['filter_mid'] + " " +
                    f['filter_right'] for f in data['query']['filters']
                ]
            else:
                filters = []
            if 'row_id' in data['query'].keys():
                row_id = data['query']['row_id']
            else:
                row_id = None
            if 'fields' in data['query'].keys():
                fields = data['query']['fields']
            else:
                fields = None

            query_data = self._db._query(table_name,
                                         filters=filters,
                                         row_id=row_id,
                                         fields=fields)

            if query_data is None:
                self.logger.error(prefix)
                return self._return_error(prefix, -1,
                                          "%s Query Failed" % (prefix))

            rtn['query_data'] = query_data

        rtn['status'] = 0
        rtn['status_message'] = 'Success'

        self.logger.debug(
            "----------------------- Return Values JSON (Start) ------------------ "
        )
        self.logger.debug( json.dumps( rtn, \
                                       sort_keys=True, \
                                       indent=4, \
                                       separators=(',', ': ') ) )
        self.logger.debug(
            "----------------------- Return Values JSON (End  ) ------------------ "
        )

        return rtn
예제 #8
0
 def raise500():
     raise cherrypy.HTTPError(500)
예제 #9
0
 def error(self, code=500):
     raise cherrypy.HTTPError(code)
예제 #10
0
파일: base.py 프로젝트: shaohef/kimchi
class Collection(object):
    """
    A Collection is a container for Resource objects.  To create a new
    Collection type, subclass this and make the following changes to the child
    class:

    - Set self.resource to the type of Resource that this Collection contains

    - Set self.resource_args.  This can remain an empty list if the Resources
      can be initialized with only one identifier.  Otherwise, include
      additional values as needed (eg. to identify a parent resource).

    - Set self.model_args.  Similar to above, this is needed only if the model
      needs additional information to identify this Collection.

    - Implement the base operations of 'create' and 'get_list' in the model.
    """
    def __init__(self, model):
        self.model = model
        self.resource = Resource
        self.resource_args = []
        self.model_args = []

    def create(self, params, *args):
        try:
            create = getattr(self.model, model_fn(self, 'create'))
        except AttributeError:
            e = InvalidOperation('KCHAPI0005E',
                                 {'resource': get_class_name(self)})
            raise cherrypy.HTTPError(405, e.message)

        validate_params(params, self, 'create')
        args = self.model_args + [params]
        name = create(*args)
        cherrypy.response.status = 201
        args = self.resource_args + [name]
        res = self.resource(self.model, *args)

        return res.get()

    def _get_resources(self, flag_filter):
        try:
            get_list = getattr(self.model, model_fn(self, 'get_list'))
            idents = get_list(*self.model_args, **flag_filter)
            res_list = []
            for ident in idents:
                # internal text, get_list changes ident to unicode for sorted
                args = self.resource_args + [ident]
                res = self.resource(self.model, *args)
                res.lookup()
                res_list.append(res)
            return res_list
        except AttributeError:
            return []

    def _cp_dispatch(self, vpath):
        if vpath:
            ident = vpath.pop(0)
            ident = urllib2.unquote(ident)
            # incoming text, from URL, is not unicode, need decode
            args = self.resource_args + [ident.decode("utf-8")]
            return self.resource(self.model, *args)

    def filter_data(self, resources, fields_filter):
        data = []
        for res in resources:
            if all(key in res.data and res.data[key] == val
                   for key, val in fields_filter.iteritems()):
                data.append(res.data)
        return data

    def get(self, filter_params):
        def _split_filter(params):
            flag_filter = dict()
            fields_filter = params
            for key, val in params.items():
                if key.startswith('_'):
                    flag_filter[key] = fields_filter.pop(key)
            return flag_filter, fields_filter

        flag_filter, fields_filter = _split_filter(filter_params)
        resources = self._get_resources(flag_filter)
        data = self.filter_data(resources, fields_filter)
        return kimchi.template.render(get_class_name(self), data)

    @cherrypy.expose
    def index(self, *args, **kwargs):
        method = validate_method(('GET', 'POST'))
        try:
            if method == 'GET':
                filter_params = cherrypy.request.params
                validate_params(filter_params, self, 'get_list')
                return self.get(filter_params)
            elif method == 'POST':
                return self.create(parse_request(), *args)
        except InvalidOperation, e:
            raise cherrypy.HTTPError(400, e.message)
        except InvalidParameter, e:
            raise cherrypy.HTTPError(400, e.message)
예제 #11
0
    def serve_raw_file(self,
                       file,
                       content_type=None,
                       disposition=None,
                       name=None):
        # Adapted from CherryPy's serve_file(), modified to work with file-like
        # objects

        response = cherrypy.response
        st = None

        if isinstance(file, str):

            path = file

            if not os.path.isabs(path):
                raise ValueError("'%s' is not an absolute path." % path)

            try:
                st = os.stat(path)
            except OSError:
                raise cherrypy.NotFound()

            if stat.S_ISDIR(st.st_mode):
                raise cherrypy.NotFound()

            response.headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime)
            cptools.validate_since()
            file = open(path, "rb")
        else:
            path = getattr(file, "name", None)
            if path:
                try:
                    st = os.stat(path)
                except OSError:
                    pass
            else:
                if not hasattr(file, "read"):
                    raise ValueError(
                        "Expected a file-like object, got %r instead "
                        "(object has no read() method)" % file)
                if not hasattr(file, "seek"):
                    raise ValueError("Can't serve file-like object %r "
                                     "(object has no seek() method)" % file)
                if not hasattr(file, "tell"):
                    raise ValueError("Can't serve file-like object %r "
                                     "(object has no tell() method)" % file)

        # Set the content type
        if content_type is None:

            if path:
                content_type = mimetypes.guess_type(path)[0]

            if not content_type:
                content_type = "text/plain"

        response.headers["Content-Type"] = content_type

        # Set the content disposition
        if disposition is not None:
            cd = disposition
            if not name and path:
                name = os.path.basename(path)
            if name:
                cd = rfc6266.build_header(name, cd)
            response.headers["Content-Disposition"] = cd

        if self.use_xsendfile and path:
            response.headers["X-Sendfile"] = path
            return ""

        # Find the size of the file
        if st is None:
            start = file.tell()
            file.seek(0, 2)  # Move to the end of the file
            c_len = file.tell() - start
            file.seek(start)
        else:
            c_len = st.st_size

        # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code
        if cherrypy.request.protocol >= (1, 1):
            response.headers["Accept-Ranges"] = "bytes"
            r = httputil.get_ranges(cherrypy.request.headers.get('Range'),
                                    c_len)
            if r == []:
                response.headers['Content-Range'] = "bytes */%s" % c_len
                message = "Invalid Range (first-byte-pos greater than Content-Length)"
                raise cherrypy.HTTPError(416, message)
            if r:
                if len(r) == 1:
                    # Return a single-part response.
                    start, stop = r[0]
                    if stop > c_len:
                        stop = c_len
                    r_len = stop - start
                    response.status = "206 Partial Content"
                    response.headers['Content-Range'] = (
                        "bytes %s-%s/%s" % (start, stop - 1, c_len))
                    response.headers['Content-Length'] = r_len
                    file.seek(start)
                    response.body = file_generator_limited(file, r_len)
                else:
                    # Return a multipart/byteranges response.
                    response.status = "206 Partial Content"
                    import mimetools
                    boundary = mimetools.choose_boundary()
                    ct = "multipart/byteranges; boundary=%s" % boundary
                    response.headers['Content-Type'] = ct
                    if "Content-Length" in response.headers:
                        # Delete Content-Length header so finalize() recalcs it.
                        del response.headers["Content-Length"]

                    def file_ranges():
                        # Apache compatibility:
                        yield "\r\n"

                        for start, stop in r:
                            yield "--" + boundary
                            yield "\r\nContent-type: %s" % content_type
                            yield (
                                "\r\nContent-range: bytes %s-%s/%s\r\n\r\n" %
                                (start, stop - 1, c_len))
                            file.seek(start)
                            for chunk in file_generator_limited(
                                    file, stop - start):
                                yield chunk
                            yield "\r\n"
                        # Final boundary
                        yield "--" + boundary + "--"

                        # Apache compatibility:
                        yield "\r\n"

                    response.body = file_ranges()
            else:
                response.headers['Content-Length'] = c_len
                response.body = file
        else:
            response.headers['Content-Length'] = c_len
            response.body = file

        return response.body
예제 #12
0
파일: base.py 프로젝트: shaohef/kimchi
                self._redirect(ident)
                uri_params = []
                for arg in self.model_args:
                    if arg is None:
                        arg = ''
                    uri_params.append(
                        urllib2.quote(arg.encode('utf-8'), safe=""))
                raise internal_redirect(self.uri_fmt % tuple(uri_params))
            except MissingParameter, e:
                raise cherrypy.HTTPError(400, e.message)
            except InvalidParameter, e:
                raise cherrypy.HTTPError(400, e.message)
            except InvalidOperation, e:
                raise cherrypy.HTTPError(400, e.message)
            except OperationFailed, e:
                raise cherrypy.HTTPError(500, e.message)
            except NotFoundError, e:
                raise cherrypy.HTTPError(404, e.message)
            except KimchiException, e:
                raise cherrypy.HTTPError(500, e.message)

        wrapper.__name__ = action_name
        wrapper.exposed = True
        return wrapper

    def lookup(self):
        try:
            lookup = getattr(self.model, model_fn(self, 'lookup'))
            self.info = lookup(*self.model_args)
        except AttributeError:
            self.info = {}
 def get_plot_cmp(self,
                  dbName1='',
                  acc1='',
                  tag1='',
                  since1='1',
                  fileType1='png',
                  png1='',
                  dbName2='',
                  acc2='',
                  tag2='',
                  since2='1',
                  fileType2='png',
                  png2='',
                  type='3',
                  istkmap='1'):
     self.check_dbName_acc(dbName1, acc1, since1)
     self.check_dbName_acc(dbName2, acc2, since2)
     if fileType1 != "png" and fileType2 != "png":
         cherrypy.HTTPError(405, "Bad file type !!!!!")
     tmpdb = self.masker.unmask_dbname(dbName1)
     db = av.get_validated_dbname(value=tmpdb,
                                  acc=self.masker.unmask_schema(
                                      tmpdb, acc1))
     vtag = av.get_validated_tag(dbName=db, value=tag1)
     vsince = av.get_validated_since(value=since1.strip(),
                                     db=db,
                                     tag=vtag,
                                     onlyone=True)
     plot = SubdetectorFactory.getPlotInstance(dbName=db,
                                               tag=vtag,
                                               since=vsince,
                                               fileType=fileType1,
                                               directory=self.__plotsdir,
                                               image=png1)
     img1 = plot.get(get_fname=True)
     tmpdb = self.masker.unmask_dbname(dbName2)
     db = av.get_validated_dbname(value=tmpdb,
                                  acc=self.masker.unmask_schema(
                                      tmpdb, acc2))
     vtag = av.get_validated_tag(dbName=db, value=tag2)
     vsince = av.get_validated_since(value=since2.strip(),
                                     db=db,
                                     tag=vtag,
                                     onlyone=True)
     plot = SubdetectorFactory.getPlotInstance(dbName=db,
                                               tag=vtag,
                                               since=vsince,
                                               fileType=fileType2,
                                               directory=self.__plotsdir,
                                               image=png2)
     img2 = plot.get(get_fname=True)
     #raise Exception('asdasd'+img2)
     '''if type == '1':
         img3 = ImageChops.subtract(img1, img2, scale=1, offset=128)
     elif type == '2':
         img3 = ImageChops.subtract(img2, img1, scale=1, offset=128)
     elif type == '3':
         img3 =  ImageChops.difference(img1, img2)
     elif type == '4':
         img3 = ImageChops.subtract(img1, img2, scale=1, offset=0)
     else:
         img3 = ImageChops.subtract(img2, img1, scale=1, offset=0)
     '''
     if not os.path.isdir(self.__tmpdir):
         os.makedirs(self.__tmpdir)
     temp = tempfile.TemporaryFile(dir=self.__tmpdir)
     plotTxt = ""
     if re.search('strip', vtag.lower()):
         plotTxt = 'ABSOLUTE DIFFERENCE  (The more lighter colors, the higher the difference.)'
     cmpPNG.CmpTrackerDiff(fileName1=img1,
                           fileName2=img2,
                           result=temp,
                           txt=plotTxt,
                           debug=False)
     #img3.save(temp, 'png')
     temp.seek(0)
     cherrypy.response.headers['Content-Type'] = 'image/' + fileType1
     data = temp.read()
     temp.close()
     return data
    def get_plot(self,
                 dbName='',
                 acc='',
                 tag='',
                 since='1',
                 fileType='png',
                 png='',
                 test=None):
        self.check_dbName_acc(dbName, acc, since)
        if fileType != "png":
            cherrypy.HTTPError(405, "Bad file type !!!!!")
        '''Returns plot image (changes response header content-type)
        All arguments in get_plot method have default value equal to '' just
        for avoiding exception if some parameter is missing.

        For testing:
        http://HOSTNAME:PORT/get_plot?dbName=oracle://cms_orcoff_prod/CMS_COND_31X_ECAL&tag=EcalIntercalibConstants_EBg50_EEnoB&since=1&fileType=root
        '''
        #try:
        #ArgumentValidator.validateArgs(dbName = dbName, tag = tag, since = since, onesince = True)
        #c = readXML()
        #db	=	str(c.dbMap_reverse[dbName]+"/CMS_COND_"+acc)
        connectionString = getFrontierConnectionString(acc, dbName)
        shortConnectionString = getFrontierConnectionString(acc,
                                                            dbName,
                                                            short=True)
        vtag = str(tag)
        vsince = av.get_validated_since(value=since.strip(),
                                        db=connectionString,
                                        tag=vtag,
                                        onlyone=True)
        plot = SubdetectorFactory.getPlotInstance(
            dbName=connectionString,
            tag=vtag,
            since=vsince,
            fileType=fileType,
            directory=self.__plotsdir,
            image=png,
            shortName=shortConnectionString)
        plotData = plot.get()
        #return plotData
        '''except ValueError, e:
            return 'Wrong parameter value. ERROR returned: %s' % str(e)
        except TypeError, e:
            return 'Wrong parameter type. ERROR returned: %s' % str(e)       
        except IOError, e:
            return 'Could not access file %s. ERROR returned: %s' % (self.__plotsdir, e)
        except AttributeError, e:
            return 'Couldn\t generate plot instance. ERROR returned: %s' % str(e)
        except RuntimeError,e:
            return 'Error connecting to DB. ERROR returned: %s' % str(e)   
        except Exception, e:
            return 'Plot is not implemented for this tag. ERROR returned: %s ' % str(e)
        else:
            if (fileType == 'root'):
                cherrypy.response.headers['Content-Disposition'] = \
                'attachment;filename=' + plot.get_name()
                cherrypy.response.headers['Content-Type'] = 'text/plain'
            else:'''
        cherrypy.response.headers['Content-Type'] = 'image/' + fileType
        return plotData
예제 #15
0
    def team(self, n="2067"):
        if not n.isdigit():
            raise cherrypy.HTTPRedirect('/')
        if int(n) == 666:
            raise cherrypy.HTTPError(
                403,
                'Satan has commanded me to not disclose his evil strategy secrets.'
            )
        conn = sql.connect(self.datapath())
        cursor = conn.cursor()
        entries = cursor.execute(
            'SELECT * FROM scout WHERE d0=? ORDER BY d1 DESC',
            (n, )).fetchall()
        averages = cursor.execute('SELECT * FROM averages WHERE team=?',
                                  (n, )).fetchall()
        assert len(
            averages) < 2  # ensure there aren't two entries for one team
        if len(averages):
            s = averages[0]
            print(s)
        else:
            s = [0] * 7  # generate zeros if no data exists for the team yet

        comments = cursor.execute('SELECT * FROM comments WHERE team=?',
                                  (n, )).fetchall()
        conn.close()

        # Generate html for comments section
        commentstr = ''
        #for comment in comments:
        #   commentstr += '<div class="commentbox"><p>{}</p></div>'.format(comment[1])

        # Iterate through all the data entries and generate some text to go in the main table
        # this entire section will need to change from year to year
        output = ''
        dataset = []
        for e in entries:
            # Important: the index of e refers to the number of the field set in main.py
            # For example e[1] gets value #1 from main.py
            # Important: the index of e refers to the number of the field set in main.py
            # For example e[1] gets value #0 from main.py
            dp = {
                "match": e[1],
                "autoswitch": 0,
                "autoscale": 0,
                "teleswitch": 0,
                "telescale": 0,
                "teleexch": 0,
                "teledrop": 0
            }
            a = ''
            a += 'baseline, ' if e[6] else ''
            dp['autoswitch'] += e[2]
            a += str(e[2]) + 'x switch, ' if e[2] else ''
            a += str(e[3]) + 'x scale, ' if e[3] else ''
            a += str(e[4]) + 'x exch, ' if e[4] else ''
            a += str(e[5]) + 'x dropped, ' if e[5] else ''
            dp['autoscale'] += e[3]

            d = ''
            d += str(e[7]) + 'x switch, ' if e[7] else ''
            d += str(e[11]) + 'x opp switch, ' if e[11] else ''
            d += str(e[8]) + 'x scale, ' if e[8] else ''
            d += str(e[9]) + 'x exch, ' if e[9] else ''
            d += str(e[10]) + 'x drop ' if e[10] else ''
            dp['teleswitch'] = e[7]
            dp['telescale'] += e[8]
            dp['teleexch'] += e[9]
            dp["teledrop"] += e[10]

            end = ''
            end += 'climb, ' if e[12] else ''
            end += 'park ' if e[13] else ''
            end += 'climbed bot ' if e[14] else ''

            o = ''
            o += 'defense, ' if e[15] else ''
            o += 'defended,' if e[16] else ''
            c = ''
            c += e[17]

            # Generate a row in the table for each match
            output += '''
            <tr {6}>
                <td>{0}</td>
                <td>{1}</td>
                <td>{2}</td>
                <td>{3}</td>
                <td>{4}</td>
                <td>{5}</td>
                <td><a class="flag" href="javascript:flag({6}, {7});">X</a></td>
            </tr>'''.format(e[1], a, d, end, o, c,
                            'style="color: #B20000"' if e[18] else '', e[1],
                            e[18])
            for key, val in dp.items():
                dp[key] = round(val, 2)
            if not e[18]:  # if flagged
                dataset.append(
                    dp
                )  # add it to dataset, which is an array of data that is fed into the graphs
        dataset.reverse()  # reverse so that graph is in the correct order

        # Grab the image from the blue alliance
        imcode = ''
        headers = {"X-TBA-App-Id": "frc2067:scouting-system:v01"}
        m = []
        try:
            # get the picture for a given team
            m = self.get(
                "http://www.thebluealliance.com/api/v2/team/frc{0}/media".
                format(n),
                params=headers).json()
            if m.status_code == 400:
                m = []
        except:
            pass  # swallow the error lol
        for media in m:
            if media[
                    'type'] == 'imgur':  # check if there's an imgur image on TBA
                imcode = '''<br>
                    <div style="text-align: center">
                    <p style="font-size: 32px; line-height: 0em;">Image</p>
                    <img src=http://i.imgur.com/{}.jpg></img>
                    </div>'''.format(media['foreign_key'])
                break
            if media['type'] == 'cdphotothread':
                imcode = '''<br>
                    <div style="text-align: center">
                    <p style="font-size: 32px; line-height: 0em;">Image</p>
                    <img src=http://chiefdelphi.com/media/img/{}></img>
                    </div>'''.format(media['details']['image_partial'].replace(
                    '_l', '_m'))
                break

                # Every year, update the labels for the graphs. The data will come from the variable dataset
                # Then update all the column headers and stuff
        return '''
        <html>
            <head>
                <title>{0} | PiScout</title>
                <link href="https://fonts.googleapis.com/css?family=Oxygen" rel="stylesheet" type="text/css">
                <link href="/static/css/style.css" rel="stylesheet">
                <script type="text/javascript" src="/static/js/amcharts.js"></script>
                <script type="text/javascript" src="/static/js/serial.js"></script>
                <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
                <script>
                if (typeof jQuery === 'undefined')
                  document.write(unescape('%3Cscript%20src%3D%22/static/js/jquery.js%22%3E%3C/script%3E'));
                </script>
                <script>
                    var chart;
                    var graph;

                    var chartData = {9};

                    AmCharts.ready(function () {{
                        // SERIAL CHART
                        chart = new AmCharts.AmSerialChart();

                        chart.dataProvider = chartData;
                        chart.marginLeft = 10;
                        chart.categoryField = "match";

                        // AXES
                        // category
                        var categoryAxis = chart.categoryAxis;
                        categoryAxis.dashLength = 3;
                        categoryAxis.minorGridEnabled = true;
                        categoryAxis.minorGridAlpha = 0.1;

                        // value
                        var valueAxis = new AmCharts.ValueAxis();
                        valueAxis.position = "left";
                        valueAxis.axisColor = "#111111";
                        valueAxis.gridAlpha = 0;
                        valueAxis.axisThickness = 2;
                        chart.addValueAxis(valueAxis)

                        var valueAxis2 = new AmCharts.ValueAxis();
                        valueAxis2.position = "right";
                        valueAxis2.axisColor = "#FCD202";
                        valueAxis2.gridAlpha = 0;
                        valueAxis2.axisThickness = 2;
                        chart.addValueAxis(valueAxis2);

                        // GRAPH
                        graph = new AmCharts.AmGraph();
                        graph.title = "Auto Switch";
                        graph.valueAxis = valueAxis;
                        graph.type = "smoothedLine"; // this line makes the graph smoothed line.
                        graph.lineColor = "#637bb6";
                        graph.bullet = "round";
                        graph.bulletSize = 8;
                        graph.bulletBorderColor = "#FFFFFF";
                        graph.bulletBorderAlpha = 1;
                        graph.bulletBorderThickness = 2;
                        graph.lineThickness = 2;
                        graph.valueField = "autoswitch";
                        graph.balloonText = "Auto Switch:<br><b><span style='font-size:14px;'>[[value]]</span></b>";
                        chart.addGraph(graph);

                        graph2 = new AmCharts.AmGraph();
                        graph2.title = "Auto Scale";
                        graph2.valueAxis = valueAxis2;
                        graph2.type = "smoothedLine"; // this line makes the graph smoothed line.
                        graph2.lineColor = "#187a2e";
                        graph2.bullet = "round";
                        graph2.bulletSize = 8;
                        graph2.bulletBorderColor = "#FFFFFF";
                        graph2.bulletBorderAlpha = 1;
                        graph2.bulletBorderThickness = 2;
                        graph2.lineThickness = 2;
                        graph2.valueField = "autoscale";
                        graph2.balloonText = "Auto Scale:<br><b><span style='font-size:14px;'>[[value]]</span></b>";
                        chart.addGraph(graph2);

                        graph3 = new AmCharts.AmGraph();
                        graph3.title = "Tele Switch";
                        graph3.valueAxis = valueAxis;
                        graph3.type = "smoothedLine"; // this line makes the graph smoothed line.
                        graph3.lineColor = "#FF6600";
                        graph3.bullet = "round";
                        graph3.bulletSize = 8;
                        graph3.bulletBorderColor = "#FFFFFF";
                        graph3.bulletBorderAlpha = 1;
                        graph3.bulletBorderThickness = 2;
                        graph3.lineThickness = 2;
                        graph3.valueField = "teleswitch";
                        graph3.balloonText = "Tele Switch:<br><b><span style='font-size:14px;'>[[value]]</span></b>";
                        chart.addGraph(graph3);

                        graph4 = new AmCharts.AmGraph();
                        graph4.valueAxis = valueAxis2;
                        graph4.title = "Tele Exchange";
                        graph4.type = "smoothedLine"; // this line makes the graph smoothed line.
                        graph4.lineColor = "#FCD202";
                        graph4.bullet = "round";
                        graph4.bulletSize = 8;
                        graph4.bulletBorderColor = "#FFFFFF";
                        graph4.bulletBorderAlpha = 1;
                        graph4.bulletBorderThickness = 2;
                        graph4.lineThickness = 2;
                        graph4.valueField = "teleexch";
                        graph4.balloonText = "Tele Exchange:<br><b><span style='font-size:14px;'>[[value]]</span></b>";
                        chart.addGraph(graph4);

                        graph5 = new AmCharts.AmGraph();
                        graph5.valueAxis = valueAxis2;
                        graph5.title = "Dropped Gears";
                        graph5.type = "smoothedLine"; // this line makes the graph smoothed line.
                        graph5.lineColor = "#FF0000";
                        graph5.bullet = "round";
                        graph5.bulletSize = 8;
                        graph5.bulletBorderColor = "#FFFFFF";
                        graph5.bulletBorderAlpha = 1;
                        graph5.bulletBorderThickness = 2;
                        graph5.lineThickness = 2;
                        graph5.valueField = "cubedrop";
                        graph5.balloonText = "Dropped Cubes:<br><b><span style='font-size:14px;'>[[value]]</span></b>";
                        chart.addGraph(graph5);
                        
                        graph6 = new AmCharts.AmGraph();
                        graph6.valueAxis = valueAxis2;
                        graph6.title = "Tele Scale";
                        graph6.type = "smoothedLine"; // this line makes the graph smoothed line.
                        graph6.lineColor = "#FF2200";
                        graph6.bullet = "round";
                        graph6.bulletSize = 8;
                        graph6.bulletBorderColor = "#FFFFFF";
                        graph6.bulletBorderAlpha = 1;
                        graph6.bulletBorderThickness = 2;
                        graph6.lineThickness = 2;
                        graph6.valueField = "telescale";
                        graph6.balloonText = "Tele Scale:<br><b><span style='font-size:14px;'>[[value]]</span></b>";
                        chart.addGraph(graph6);

                        // CURSOR
                        var chartCursor = new AmCharts.ChartCursor();
                        chartCursor.cursorAlpha = 0;
                        chartCursor.cursorPosition = "mouse";
                        chart.addChartCursor(chartCursor);

                        var legend = new AmCharts.AmLegend();
                        legend.marginLeft = 110;
                        legend.useGraphSettings = true;
                        chart.addLegend(legend);
                        chart.creditsPosition = "bottom-right";

                        // WRITE
                        chart.write("chartdiv");
                    }});

                    function flag(m, f)
                    {{
                        $.post(
                            "flag",
                            {{num: {0}, match: m, flagval: f}}
                        );
                        window.location.reload(true);
                    }}
                </script>
            </head>
            <body>
                <h1 class="big">Team {0}</h1>
                <h2><a style="color: #B20000" href='/'>PiScout Database</a></h2>
                <br><br>
                <div style="text-align:center;">
                    <div id="apr">
                        <p class="statbox" style="font-weight:bold; font-size:100%">Average Total:</p>
                        <p style="font-size: 400%; line-height: 0em">{2}</p>
                    </div>
                    <div id="stats">
                        <p class="statbox" style="font-weight:bold">Average Match:</p>
                        <p class="statbox">Auto Switch: {3}</p>
                        <p class="statbox">Auto Scale: {4}</p>
                        <p class="statbox">Tele Switch: {5}</p>
                        <p class="statbox">Tele Scale: {6}</p>
                        <p class="statbox">Tele Exchange: {7}</p>
                        <p class="statbox">Endgame Points: {8}</p>
                    </div>
                </div>
                <br>
                <div id="chartdiv" style="width:1000px; height:400px; margin: 0 auto;"></div>
                <br>
                <table>
                    <thead><tr>
                        <th>Match</th>
                        <th>Auto</th>
                        <th>Teleop</th>
                        <th>Endgame</th>
                        <th>Other</th>
                        <th>Comments</th>
                        <th>Flag</th>
                    </tr></thead>{1}
                </table>
                {10}
                <br>
                <br>
                <p style="text-align: center; font-size: 24px"><a href="/matches?n={0}">View this team's match schedule</a></p>
            </body>
        </html>'''.format(n, output, s[2], s[3], s[4], s[5], s[6], s[7], s[8],
                          str(dataset).replace("'", '"'), imcode, commentstr)
예제 #16
0
 def error(self, code):
     # raise an error based on the get query
     raise cherrypy.HTTPError(
         "403 Forbidden",
         "You are not allowed to access this resource.")
예제 #17
0
    def alliances(self, b1='', b2='', b3='', r1='', r2='', r3=''):
        nums = [b1, b2, b3, r1, r2, r3]
        averages = []
        conn = sql.connect(self.datapath())
        cursor = conn.cursor()
        # start a div table for the comparison
        # to later be formatted with sum APR
        apr = []
        output = ''
        # iterate through all six teams
        for i, n in enumerate(nums):
            # at halfway pointm switch to the second row
            if not n.isdigit():
                raise cherrypy.HTTPError(
                    400, "You fool! Enter six valid team numbers!")
            average = cursor.execute('SELECT * FROM averages WHERE team=?',
                                     (n, )).fetchall()
            assert len(average) < 2
            if len(average):
                entry = average[0]
            else:
                entry = [0] * 7
            apr.append(entry[1])
            output += '''<div style="text-align:center; display: inline-block; margin: 16px;">
                                <p><a href="/team?n={0}" style="font-size: 32px; line-height: 0em;">Team {0}</a></p>
                                <div id="apr">
                                    <p style="font-size: 100%; margin: 0.65em; line-height: 0.1em">Average Cubes</p>
                                    <p style="font-size: 400%; line-height: 0em">{7}</p>
                                </div>
                                <div id="stats">
                                    <p class="statbox" style="font-weight:bold">Match Averages:</p>
                                    <p class="statbox">Auto Switch: {1}</p>
                                    <p class="statbox">Auto Scale: {2}</p>
                                    <p class="statbox">Tele Switch: {3}</p>
                                    <p class="statbox">Tele Scale: {4}</p>
                                    <p class="statbox">Tele Exch: {5}</p>
                                    <p class="statbox">Endgame: {6}</p>
                                </div>
                            </div>'''.format(n, entry[3], entry[4], entry[5],
                                             entry[6], entry[7], entry[8],
                                             round(entry[2],
                                                   1))  # unpack the elements
        output += "</div></div>"
        prob_red = 1 / (1 + math.e**(-0.08099 *
                                     (sum(apr[3:6]) - sum(apr[0:3])))
                        )  # calculates win probability from 2016 data
        output = output.format(sum(apr[0:3]), sum(apr[3:6]),
                               round((1 - prob_red) * 100, 1),
                               round(prob_red * 100, 1))
        output = output.format()
        conn.close()

        return '''
            <html>
                <head>
                    <title>PiScout</title>
                    <link href="https://fonts.googleapis.com/css?family=Oxygen" rel="stylesheet" type="text/css">
                    <link href="/static/css/style.css" rel="stylesheet">
                </head>
                <body>
                    <h1 class="big">Compare Alliances</h1>
                    <h2><a style="color: #B20000" href='/'>PiScout Database</a></h2>
                    <br><br>
                    <div style="margin: 0 auto; text-align: center; max-width: 1000px;">
                    {0}
                    <br><br><br>
                    </div>
                </body>
            </html>'''.format(output)
예제 #18
0
 def PUT(self, id):
     enable_crossdomain()
     raise cherrypy.HTTPError(405, "Not allowed.")
예제 #19
0
    def adduserform(self):
        if self.checkauth(returntopage=True) != 'admin':
            raise cherrypy.HTTPError(
                "403 Forbidden", "Only admin allowed to access this resource.")

        return logon.Logon.base_page % '''
예제 #20
0
 def error(self, code):
     # raise an error based on the get query
     raise cherrypy.HTTPError(status=code)
예제 #21
0
class Request(object):
    """An HTTP request.

    This object represents the metadata of an HTTP request message;
    that is, it contains attributes which describe the environment
    in which the request URL, headers, and body were sent (if you
    want tools to interpret the headers and body, those are elsewhere,
    mostly in Tools). This 'metadata' consists of socket data,
    transport characteristics, and the Request-Line. This object
    also contains data regarding the configuration in effect for
    the given URL, and the execution plan for generating a response.
    """

    prev = None
    """
    The previous Request object (if any). This should be None
    unless we are processing an InternalRedirect."""

    # Conversation/connection attributes
    local = httputil.Host('127.0.0.1', 80)
    'An httputil.Host(ip, port, hostname) object for the server socket.'

    remote = httputil.Host('127.0.0.1', 1111)
    'An httputil.Host(ip, port, hostname) object for the client socket.'

    scheme = 'http'
    """
    The protocol used between client and server. In most cases,
    this will be either 'http' or 'https'."""

    server_protocol = 'HTTP/1.1'
    """
    The HTTP version for which the HTTP server is at least
    conditionally compliant."""

    base = ''
    """The (scheme://host) portion of the requested URL.
    In some cases (e.g. when proxying via mod_rewrite), this may contain
    path segments which cherrypy.url uses when constructing url's, but
    which otherwise are ignored by CherryPy. Regardless, this value
    MUST NOT end in a slash."""

    # Request-Line attributes
    request_line = ''
    """
    The complete Request-Line received from the client. This is a
    single string consisting of the request method, URI, and protocol
    version (joined by spaces). Any final CRLF is removed."""

    method = 'GET'
    """
    Indicates the HTTP method to be performed on the resource identified
    by the Request-URI. Common methods include GET, HEAD, POST, PUT, and
    DELETE. CherryPy allows any extension method; however, various HTTP
    servers and gateways may restrict the set of allowable methods.
    CherryPy applications SHOULD restrict the set (on a per-URI basis)."""

    query_string = ''
    """
    The query component of the Request-URI, a string of information to be
    interpreted by the resource. The query portion of a URI follows the
    path component, and is separated by a '?'. For example, the URI
    'http://www.cherrypy.org/wiki?a=3&b=4' has the query component,
    'a=3&b=4'."""

    query_string_encoding = 'utf8'
    """
    The encoding expected for query string arguments after % HEX HEX decoding).
    If a query string is provided that cannot be decoded with this encoding,
    404 is raised (since technically it's a different URI). If you want
    arbitrary encodings to not error, set this to 'Latin-1'; you can then
    encode back to bytes and re-decode to whatever encoding you like later.
    """

    protocol = (1, 1)
    """The HTTP protocol version corresponding to the set
    of features which should be allowed in the response. If BOTH
    the client's request message AND the server's level of HTTP
    compliance is HTTP/1.1, this attribute will be the tuple (1, 1).
    If either is 1.0, this attribute will be the tuple (1, 0).
    Lower HTTP protocol versions are not explicitly supported."""

    params = {}
    """
    A dict which combines query string (GET) and request entity (POST)
    variables. This is populated in two stages: GET params are added
    before the 'on_start_resource' hook, and POST params are added
    between the 'before_request_body' and 'before_handler' hooks."""

    # Message attributes
    header_list = []
    """
    A list of the HTTP request headers as (name, value) tuples.
    In general, you should use request.headers (a dict) instead."""

    headers = httputil.HeaderMap()
    """
    A dict-like object containing the request headers. Keys are header
    names (in Title-Case format); however, you may get and set them in
    a case-insensitive manner. That is, headers['Content-Type'] and
    headers['content-type'] refer to the same value. Values are header
    values (decoded according to :rfc:`2047` if necessary). See also:
    httputil.HeaderMap, httputil.HeaderElement."""

    cookie = SimpleCookie()
    """See help(Cookie)."""

    rfile = None
    """
    If the request included an entity (body), it will be available
    as a stream in this attribute. However, the rfile will normally
    be read for you between the 'before_request_body' hook and the
    'before_handler' hook, and the resulting string is placed into
    either request.params or the request.body attribute.

    You may disable the automatic consumption of the rfile by setting
    request.process_request_body to False, either in config for the desired
    path, or in an 'on_start_resource' or 'before_request_body' hook.

    WARNING: In almost every case, you should not attempt to read from the
    rfile stream after CherryPy's automatic mechanism has read it. If you
    turn off the automatic parsing of rfile, you should read exactly the
    number of bytes specified in request.headers['Content-Length'].
    Ignoring either of these warnings may result in a hung request thread
    or in corruption of the next (pipelined) request.
    """

    process_request_body = True
    """
    If True, the rfile (if any) is automatically read and parsed,
    and the result placed into request.params or request.body."""

    methods_with_bodies = ('POST', 'PUT', 'PATCH')
    """
    A sequence of HTTP methods for which CherryPy will automatically
    attempt to read a body from the rfile. If you are going to change
    this property, modify it on the configuration (recommended)
    or on the "hook point" `on_start_resource`.
    """

    body = None
    """
    If the request Content-Type is 'application/x-www-form-urlencoded'
    or multipart, this will be None. Otherwise, this will be an instance
    of :class:`RequestBody<cherrypy._cpreqbody.RequestBody>` (which you
    can .read()); this value is set between the 'before_request_body' and
    'before_handler' hooks (assuming that process_request_body is True)."""

    # Dispatch attributes
    dispatch = cherrypy.dispatch.Dispatcher()
    """
    The object which looks up the 'page handler' callable and collects
    config for the current request based on the path_info, other
    request attributes, and the application architecture. The core
    calls the dispatcher as early as possible, passing it a 'path_info'
    argument.

    The default dispatcher discovers the page handler by matching path_info
    to a hierarchical arrangement of objects, starting at request.app.root.
    See help(cherrypy.dispatch) for more information."""

    script_name = ''
    """
    The 'mount point' of the application which is handling this request.

    This attribute MUST NOT end in a slash. If the script_name refers to
    the root of the URI, it MUST be an empty string (not "/").
    """

    path_info = '/'
    """
    The 'relative path' portion of the Request-URI. This is relative
    to the script_name ('mount point') of the application which is
    handling this request."""

    login = None
    """
    When authentication is used during the request processing this is
    set to 'False' if it failed and to the 'username' value if it succeeded.
    The default 'None' implies that no authentication happened."""

    # Note that cherrypy.url uses "if request.app:" to determine whether
    # the call is during a real HTTP request or not. So leave this None.
    app = None
    """The cherrypy.Application object which is handling this request."""

    handler = None
    """
    The function, method, or other callable which CherryPy will call to
    produce the response. The discovery of the handler and the arguments
    it will receive are determined by the request.dispatch object.
    By default, the handler is discovered by walking a tree of objects
    starting at request.app.root, and is then passed all HTTP params
    (from the query string and POST body) as keyword arguments."""

    toolmaps = {}
    """
    A nested dict of all Toolboxes and Tools in effect for this request,
    of the form: {Toolbox.namespace: {Tool.name: config dict}}."""

    config = None
    """
    A flat dict of all configuration entries which apply to the
    current request. These entries are collected from global config,
    application config (based on request.path_info), and from handler
    config (exactly how is governed by the request.dispatch object in
    effect for this request; by default, handler config can be attached
    anywhere in the tree between request.app.root and the final handler,
    and inherits downward)."""

    is_index = None
    """
    This will be True if the current request is mapped to an 'index'
    resource handler (also, a 'default' handler if path_info ends with
    a slash). The value may be used to automatically redirect the
    user-agent to a 'more canonical' URL which either adds or removes
    the trailing slash. See cherrypy.tools.trailing_slash."""

    hooks = HookMap(hookpoints)
    """
    A HookMap (dict-like object) of the form: {hookpoint: [hook, ...]}.
    Each key is a str naming the hook point, and each value is a list
    of hooks which will be called at that hook point during this request.
    The list of hooks is generally populated as early as possible (mostly
    from Tools specified in config), but may be extended at any time.
    See also: _cprequest.Hook, _cprequest.HookMap, and cherrypy.tools."""

    error_response = cherrypy.HTTPError(500).set_response
    """
    The no-arg callable which will handle unexpected, untrapped errors
    during request processing. This is not used for expected exceptions
    (like NotFound, HTTPError, or HTTPRedirect) which are raised in
    response to expected conditions (those should be customized either
    via request.error_page or by overriding HTTPError.set_response).
    By default, error_response uses HTTPError(500) to return a generic
    error response to the user-agent."""

    error_page = {}
    """
    A dict of {error code: response filename or callable} pairs.

    The error code must be an int representing a given HTTP error code,
    or the string 'default', which will be used if no matching entry
    is found for a given numeric code.

    If a filename is provided, the file should contain a Python string-
    formatting template, and can expect by default to receive format
    values with the mapping keys %(status)s, %(message)s, %(traceback)s,
    and %(version)s. The set of format mappings can be extended by
    overriding HTTPError.set_response.

    If a callable is provided, it will be called by default with keyword
    arguments 'status', 'message', 'traceback', and 'version', as for a
    string-formatting template. The callable must return a string or
    iterable of strings which will be set to response.body. It may also
    override headers or perform any other processing.

    If no entry is given for an error code, and no 'default' entry exists,
    a default template will be used.
    """

    show_tracebacks = True
    """
    If True, unexpected errors encountered during request processing will
    include a traceback in the response body."""

    show_mismatched_params = True
    """
    If True, mismatched parameters encountered during PageHandler invocation
    processing will be included in the response body."""

    throws = (KeyboardInterrupt, SystemExit, cherrypy.InternalRedirect)
    """The sequence of exceptions which Request.run does not trap."""

    throw_errors = False
    """
    If True, Request.run will not trap any errors (except HTTPRedirect and
    HTTPError, which are more properly called 'exceptions', not errors)."""

    closed = False
    """True once the close method has been called, False otherwise."""

    stage = None
    """
    A string containing the stage reached in the request-handling process.
    This is useful when debugging a live server with hung requests."""

    unique_id = None
    """A lazy object generating and memorizing UUID4 on ``str()`` render."""

    namespaces = reprconf.NamespaceSet(
        **{
            'hooks': hooks_namespace,
            'request': request_namespace,
            'response': response_namespace,
            'error_page': error_page_namespace,
            'tools': cherrypy.tools,
        })

    def __init__(self,
                 local_host,
                 remote_host,
                 scheme='http',
                 server_protocol='HTTP/1.1'):
        """Populate a new Request object.

        local_host should be an httputil.Host object with the server info.
        remote_host should be an httputil.Host object with the client info.
        scheme should be a string, either "http" or "https".
        """
        self.local = local_host
        self.remote = remote_host
        self.scheme = scheme
        self.server_protocol = server_protocol

        self.closed = False

        # Put a *copy* of the class error_page into self.
        self.error_page = self.error_page.copy()

        # Put a *copy* of the class namespaces into self.
        self.namespaces = self.namespaces.copy()

        self.stage = None

        self.unique_id = LazyUUID4()

    def close(self):
        """Run cleanup code. (Core)"""
        if not self.closed:
            self.closed = True
            self.stage = 'on_end_request'
            self.hooks.run('on_end_request')
            self.stage = 'close'

    def run(self, method, path, query_string, req_protocol, headers, rfile):
        r"""Process the Request. (Core)

        method, path, query_string, and req_protocol should be pulled directly
        from the Request-Line (e.g. "GET /path?key=val HTTP/1.0").

        path
            This should be %XX-unquoted, but query_string should not be.

            When using Python 2, they both MUST be byte strings,
            not unicode strings.

            When using Python 3, they both MUST be unicode strings,
            not byte strings, and preferably not bytes \x00-\xFF
            disguised as unicode.

        headers
            A list of (name, value) tuples.

        rfile
            A file-like object containing the HTTP request entity.

        When run() is done, the returned object should have 3 attributes:

          * status, e.g. "200 OK"
          * header_list, a list of (name, value) tuples
          * body, an iterable yielding strings

        Consumer code (HTTP servers) should then access these response
        attributes to build the outbound stream.

        """
        response = cherrypy.serving.response
        self.stage = 'run'
        try:
            self.error_response = cherrypy.HTTPError(500).set_response

            self.method = method
            path = path or '/'
            self.query_string = query_string or ''
            self.params = {}

            # Compare request and server HTTP protocol versions, in case our
            # server does not support the requested protocol. Limit our output
            # to min(req, server). We want the following output:
            #     request    server     actual written   supported response
            #     protocol   protocol  response protocol    feature set
            # a     1.0        1.0           1.0                1.0
            # b     1.0        1.1           1.1                1.0
            # c     1.1        1.0           1.0                1.0
            # d     1.1        1.1           1.1                1.1
            # Notice that, in (b), the response will be "HTTP/1.1" even though
            # the client only understands 1.0. RFC 2616 10.5.6 says we should
            # only return 505 if the _major_ version is different.
            rp = int(req_protocol[5]), int(req_protocol[7])
            sp = int(self.server_protocol[5]), int(self.server_protocol[7])
            self.protocol = min(rp, sp)
            response.headers.protocol = self.protocol

            # Rebuild first line of the request (e.g. "GET /path HTTP/1.0").
            url = path
            if query_string:
                url += '?' + query_string
            self.request_line = '%s %s %s' % (method, url, req_protocol)

            self.header_list = list(headers)
            self.headers = httputil.HeaderMap()

            self.rfile = rfile
            self.body = None

            self.cookie = SimpleCookie()
            self.handler = None

            # path_info should be the path from the
            # app root (script_name) to the handler.
            self.script_name = self.app.script_name
            self.path_info = pi = path[len(self.script_name):]

            self.stage = 'respond'
            self.respond(pi)

        except self.throws:
            raise
        except Exception:
            if self.throw_errors:
                raise
            else:
                # Failure in setup, error handler or finalize. Bypass them.
                # Can't use handle_error because we may not have hooks yet.
                cherrypy.log(traceback=True, severity=40)
                if self.show_tracebacks:
                    body = format_exc()
                else:
                    body = ''
                r = bare_error(body)
                response.output_status, response.header_list, response.body = r

        if self.method == 'HEAD':
            # HEAD requests MUST NOT return a message-body in the response.
            response.body = []

        try:
            cherrypy.log.access()
        except Exception:
            cherrypy.log.error(traceback=True)

        return response

    def respond(self, path_info):
        """Generate a response for the resource at self.path_info. (Core)"""
        try:
            try:
                try:
                    self._do_respond(path_info)
                except (cherrypy.HTTPRedirect, cherrypy.HTTPError):
                    inst = sys.exc_info()[1]
                    inst.set_response()
                    self.stage = 'before_finalize (HTTPError)'
                    self.hooks.run('before_finalize')
                    cherrypy.serving.response.finalize()
            finally:
                self.stage = 'on_end_resource'
                self.hooks.run('on_end_resource')
        except self.throws:
            raise
        except Exception:
            if self.throw_errors:
                raise
            self.handle_error()

    def _do_respond(self, path_info):
        response = cherrypy.serving.response

        if self.app is None:
            raise cherrypy.NotFound()

        self.hooks = self.__class__.hooks.copy()
        self.toolmaps = {}

        # Get the 'Host' header, so we can HTTPRedirect properly.
        self.stage = 'process_headers'
        self.process_headers()

        self.stage = 'get_resource'
        self.get_resource(path_info)

        self.body = _cpreqbody.RequestBody(self.rfile,
                                           self.headers,
                                           request_params=self.params)

        self.namespaces(self.config)

        self.stage = 'on_start_resource'
        self.hooks.run('on_start_resource')

        # Parse the querystring
        self.stage = 'process_query_string'
        self.process_query_string()

        # Process the body
        if self.process_request_body:
            if self.method not in self.methods_with_bodies:
                self.process_request_body = False
        self.stage = 'before_request_body'
        self.hooks.run('before_request_body')
        if self.process_request_body:
            self.body.process()

        # Run the handler
        self.stage = 'before_handler'
        self.hooks.run('before_handler')
        if self.handler:
            self.stage = 'handler'
            response.body = self.handler()

        # Finalize
        self.stage = 'before_finalize'
        self.hooks.run('before_finalize')
        response.finalize()

    def process_query_string(self):
        """Parse the query string into Python structures. (Core)"""
        try:
            p = httputil.parse_query_string(
                self.query_string, encoding=self.query_string_encoding)
        except UnicodeDecodeError:
            raise cherrypy.HTTPError(
                404, 'The given query string could not be processed. Query '
                'strings for this resource must be encoded with %r.' %
                self.query_string_encoding)

        # Python 2 only: keyword arguments must be byte strings (type 'str').
        if six.PY2:
            for key, value in p.items():
                if isinstance(key, six.text_type):
                    del p[key]
                    p[key.encode(self.query_string_encoding)] = value
        self.params.update(p)

    def process_headers(self):
        """Parse HTTP header data into Python structures. (Core)"""
        # Process the headers into self.headers
        headers = self.headers
        for name, value in self.header_list:
            # Call title() now (and use dict.__method__(headers))
            # so title doesn't have to be called twice.
            name = name.title()
            value = value.strip()

            headers[name] = httputil.decode_TEXT_maybe(value)

            # Some clients, notably Konquoror, supply multiple
            # cookies on different lines with the same key. To
            # handle this case, store all cookies in self.cookie.
            if name == 'Cookie':
                try:
                    self.cookie.load(value)
                except CookieError as exc:
                    raise cherrypy.HTTPError(400, str(exc))

        if not dict.__contains__(headers, 'Host'):
            # All Internet-based HTTP/1.1 servers MUST respond with a 400
            # (Bad Request) status code to any HTTP/1.1 request message
            # which lacks a Host header field.
            if self.protocol >= (1, 1):
                msg = "HTTP/1.1 requires a 'Host' request header."
                raise cherrypy.HTTPError(400, msg)
        host = dict.get(headers, 'Host')
        if not host:
            host = self.local.name or self.local.ip
        self.base = '%s://%s' % (self.scheme, host)

    def get_resource(self, path):
        """Call a dispatcher (which sets self.handler and .config). (Core)"""
        # First, see if there is a custom dispatch at this URI. Custom
        # dispatchers can only be specified in app.config, not in _cp_config
        # (since custom dispatchers may not even have an app.root).
        dispatch = self.app.find_config(path, 'request.dispatch',
                                        self.dispatch)

        # dispatch() should set self.handler and self.config
        dispatch(path)

    def handle_error(self):
        """Handle the last unanticipated exception. (Core)"""
        try:
            self.hooks.run('before_error_response')
            if self.error_response:
                self.error_response()
            self.hooks.run('after_error_response')
            cherrypy.serving.response.finalize()
        except cherrypy.HTTPRedirect:
            inst = sys.exc_info()[1]
            inst.set_response()
            cherrypy.serving.response.finalize()
예제 #22
0
 def messageArg(self):
     message = ("If you construct an HTTPError with a 'message' "
                'argument, it wil be placed on the error page '
                '(underneath the status line by default).')
     raise cherrypy.HTTPError(500, message=message)
예제 #23
0
 def _get_file_path(self):
     f = os.path.join(self.storage_path, self.SESSION_PREFIX + self.id)
     if not os.path.abspath(f).startswith(self.storage_path):
         raise cherrypy.HTTPError(400, 'Invalid session id in cookie.')
     return f
예제 #24
0
	def index(self):
		if cherrypy.request.method == 'GET':
			# List ALL THE TASKS!
			return json.dumps(self.magic.get_tasks(),indent=1)
		raise cherrypy.HTTPError(405)
예제 #25
0
def test_callable_spec(callable, callable_args, callable_kwargs):
    """
    Inspect callable and test to see if the given args are suitable for it.

    When an error occurs during the handler's invoking stage there are 2
    erroneous cases:
    1.  Too many parameters passed to a function which doesn't define
        one of *args or **kwargs.
    2.  Too little parameters are passed to the function.

    There are 3 sources of parameters to a cherrypy handler.
    1.  query string parameters are passed as keyword parameters to the handler.
    2.  body parameters are also passed as keyword parameters.
    3.  when partial matching occurs, the final path atoms are passed as
        positional args.
    Both the query string and path atoms are part of the URI.  If they are
    incorrect, then a 404 Not Found should be raised. Conversely the body
    parameters are part of the request; if they are invalid a 400 Bad Request.
    """
    show_mismatched_params = getattr(cherrypy.serving.request,
                                     'show_mismatched_params', False)
    try:
        (args, varargs, varkw, defaults) = inspect.getargspec(callable)
    except TypeError:
        if isinstance(callable, object) and hasattr(callable, '__call__'):
            (args, varargs, varkw,
             defaults) = inspect.getargspec(callable.__call__)
        else:
            # If it wasn't one of our own types, re-raise
            # the original error
            raise

    if args and args[0] == 'self':
        args = args[1:]

    arg_usage = dict([(
        arg,
        0,
    ) for arg in args])
    vararg_usage = 0
    varkw_usage = 0
    extra_kwargs = set()

    for i, value in enumerate(callable_args):
        try:
            arg_usage[args[i]] += 1
        except IndexError:
            vararg_usage += 1

    for key in callable_kwargs.keys():
        try:
            arg_usage[key] += 1
        except KeyError:
            varkw_usage += 1
            extra_kwargs.add(key)

    # figure out which args have defaults.
    args_with_defaults = args[-len(defaults or []):]
    for i, val in enumerate(defaults or []):
        # Defaults take effect only when the arg hasn't been used yet.
        if arg_usage[args_with_defaults[i]] == 0:
            arg_usage[args_with_defaults[i]] += 1

    missing_args = []
    multiple_args = []
    for key, usage in arg_usage.items():
        if usage == 0:
            missing_args.append(key)
        elif usage > 1:
            multiple_args.append(key)

    if missing_args:
        # In the case where the method allows body arguments
        # there are 3 potential errors:
        # 1. not enough query string parameters -> 404
        # 2. not enough body parameters -> 400
        # 3. not enough path parts (partial matches) -> 404
        #
        # We can't actually tell which case it is,
        # so I'm raising a 404 because that covers 2/3 of the
        # possibilities
        #
        # In the case where the method does not allow body
        # arguments it's definitely a 404.
        message = None
        if show_mismatched_params:
            message = "Missing parameters: %s" % ",".join(missing_args)
        raise cherrypy.HTTPError(404, message=message)

    # the extra positional arguments come from the path - 404 Not Found
    if not varargs and vararg_usage > 0:
        raise cherrypy.HTTPError(404)

    body_params = cherrypy.serving.request.body.params or {}
    body_params = set(body_params.keys())
    qs_params = set(callable_kwargs.keys()) - body_params

    if multiple_args:
        if qs_params.intersection(set(multiple_args)):
            # If any of the multiple parameters came from the query string then
            # it's a 404 Not Found
            error = 404
        else:
            # Otherwise it's a 400 Bad Request
            error = 400

        message = None
        if show_mismatched_params:
            message="Multiple values for parameters: "\
                    "%s" % ",".join(multiple_args)
        raise cherrypy.HTTPError(error, message=message)

    if not varkw and varkw_usage > 0:

        # If there were extra query string parameters, it's a 404 Not Found
        extra_qs_params = set(qs_params).intersection(extra_kwargs)
        if extra_qs_params:
            message = None
            if show_mismatched_params:
                message="Unexpected query string "\
                        "parameters: %s" % ", ".join(extra_qs_params)
            raise cherrypy.HTTPError(404, message=message)

        # If there were any extra body parameters, it's a 400 Not Found
        extra_body_params = set(body_params).intersection(extra_kwargs)
        if extra_body_params:
            message = None
            if show_mismatched_params:
                message="Unexpected body parameters: "\
                        "%s" % ", ".join(extra_body_params)
            raise cherrypy.HTTPError(400, message=message)
예제 #26
0
    def read_lines_to_boundary(self, fp_out=None):
        """Read bytes from self.fp and return or write them to a file.

        If the 'fp_out' argument is None (the default), all bytes read are
        returned in a single byte string.

        If the 'fp_out' argument is not None, it must be a file-like
        object that supports the 'write' method; all bytes read will be
        written to the fp, and that fp is returned.
        """
        endmarker = self.boundary + ntob("--")
        delim = ntob("")
        prev_lf = True
        lines = []
        seen = 0
        while True:
            line = self.fp.readline(1 << 16)
            if not line:
                raise EOFError("Illegal end of multipart body.")
            if line.startswith(ntob("--")) and prev_lf:
                strippedline = line.strip()
                if strippedline == self.boundary:
                    break
                if strippedline == endmarker:
                    self.fp.finish()
                    break

            line = delim + line

            if line.endswith(ntob("\r\n")):
                delim = ntob("\r\n")
                line = line[:-2]
                prev_lf = True
            elif line.endswith(ntob("\n")):
                delim = ntob("\n")
                line = line[:-1]
                prev_lf = True
            else:
                delim = ntob("")
                prev_lf = False

            if fp_out is None:
                lines.append(line)
                seen += len(line)
                if seen > self.maxrambytes:
                    fp_out = self.make_file()
                    for line in lines:
                        fp_out.write(line)
            else:
                fp_out.write(line)

        if fp_out is None:
            result = ntob('').join(lines)
            for charset in self.attempt_charsets:
                try:
                    result = result.decode(charset)
                except UnicodeDecodeError:
                    pass
                else:
                    self.charset = charset
                    return result
            else:
                raise cherrypy.HTTPError(
                    400,
                    "The request entity could not be decoded. The following "
                    "charsets were attempted: %s" % repr(self.attempt_charsets)
                )
        else:
            fp_out.seek(0)
            return fp_out
예제 #27
0
    def handle_before_request(cls, e):

        controller = e.source

        if not controller.allowed_publication_targets:
            raise cherrypy.HTTPError(403, "Forbidden")
예제 #28
0
    def read(self, size=None, fp_out=None):
        """Read bytes from the request body and return or write them to a file.

        A number of bytes less than or equal to the 'size' argument are read
        off the socket. The actual number of bytes read are tracked in
        self.bytes_read. The number may be smaller than 'size' when 1) the
        client sends fewer bytes, 2) the 'Content-Length' request header
        specifies fewer bytes than requested, or 3) the number of bytes read
        exceeds self.maxbytes (in which case, 413 is raised).

        If the 'fp_out' argument is None (the default), all bytes read are
        returned in a single byte string.

        If the 'fp_out' argument is not None, it must be a file-like
        object that supports the 'write' method; all bytes read will be
        written to the fp, and None is returned.
        """

        if self.length is None:
            if size is None:
                remaining = inf
            else:
                remaining = size
        else:
            remaining = self.length - self.bytes_read
            if size and size < remaining:
                remaining = size
        if remaining == 0:
            self.finish()
            if fp_out is None:
                return ntob('')
            else:
                return None

        chunks = []

        # Read bytes from the buffer.
        if self.buffer:
            if remaining is inf:
                data = self.buffer
                self.buffer = ntob('')
            else:
                data = self.buffer[:remaining]
                self.buffer = self.buffer[remaining:]
            datalen = len(data)
            remaining -= datalen

            # Check lengths.
            self.bytes_read += datalen
            if self.maxbytes and self.bytes_read > self.maxbytes:
                raise cherrypy.HTTPError(413)

            # Store the data.
            if fp_out is None:
                chunks.append(data)
            else:
                fp_out.write(data)

        # Read bytes from the socket.
        while remaining > 0:
            chunksize = min(remaining, self.bufsize)
            try:
                data = self.fp.read(chunksize)
            except Exception:
                e = sys.exc_info()[1]
                if e.__class__.__name__ == 'MaxSizeExceeded':
                    # Post data is too big
                    raise cherrypy.HTTPError(
                        413, "Maximum request length: %r" % e.args[1])
                else:
                    raise
            if not data:
                self.finish()
                break
            datalen = len(data)
            remaining -= datalen

            # Check lengths.
            self.bytes_read += datalen
            if self.maxbytes and self.bytes_read > self.maxbytes:
                raise cherrypy.HTTPError(413)

            # Store the data.
            if fp_out is None:
                chunks.append(data)
            else:
                fp_out.write(data)

        if fp_out is None:
            return ntob('').join(chunks)
예제 #29
0
def gzip(compress_level=5,
         mime_types=['text/html', 'text/plain'],
         debug=False):
    """Try to gzip the response body if Content-Type in mime_types.

    cherrypy.response.headers['Content-Type'] must be set to one of the
    values in the mime_types arg before calling this function.

    The provided list of mime-types must be of one of the following form:
        * `type/subtype`
        * `type/*`
        * `type/*+subtype`

    No compression is performed if any of the following hold:
        * The client sends no Accept-Encoding request header
        * No 'gzip' or 'x-gzip' is present in the Accept-Encoding header
        * No 'gzip' or 'x-gzip' with a qvalue > 0 is present
        * The 'identity' value is given with a qvalue > 0.

    """
    request = cherrypy.serving.request
    response = cherrypy.serving.response

    set_vary_header(response, 'Accept-Encoding')

    if not response.body:
        # Response body is empty (might be a 304 for instance)
        if debug:
            cherrypy.log('No response body', context='TOOLS.GZIP')
        return

    # If returning cached content (which should already have been gzipped),
    # don't re-zip.
    if getattr(request, 'cached', False):
        if debug:
            cherrypy.log('Not gzipping cached response', context='TOOLS.GZIP')
        return

    acceptable = request.headers.elements('Accept-Encoding')
    if not acceptable:
        # If no Accept-Encoding field is present in a request,
        # the server MAY assume that the client will accept any
        # content coding. In this case, if "identity" is one of
        # the available content-codings, then the server SHOULD use
        # the "identity" content-coding, unless it has additional
        # information that a different content-coding is meaningful
        # to the client.
        if debug:
            cherrypy.log('No Accept-Encoding', context='TOOLS.GZIP')
        return

    ct = response.headers.get('Content-Type', '').split(';')[0]
    for coding in acceptable:
        if coding.value == 'identity' and coding.qvalue != 0:
            if debug:
                cherrypy.log('Non-zero identity qvalue: %s' % coding,
                             context='TOOLS.GZIP')
            return
        if coding.value in ('gzip', 'x-gzip'):
            if coding.qvalue == 0:
                if debug:
                    cherrypy.log('Zero gzip qvalue: %s' % coding,
                                 context='TOOLS.GZIP')
                return

            if ct not in mime_types:
                # If the list of provided mime-types contains tokens
                # such as 'text/*' or 'application/*+xml',
                # we go through them and find the most appropriate one
                # based on the given content-type.
                # The pattern matching is only caring about the most
                # common cases, as stated above, and doesn't support
                # for extra parameters.
                found = False
                if '/' in ct:
                    ct_media_type, ct_sub_type = ct.split('/')
                    for mime_type in mime_types:
                        if '/' in mime_type:
                            media_type, sub_type = mime_type.split('/')
                            if ct_media_type == media_type:
                                if sub_type == '*':
                                    found = True
                                    break
                                elif '+' in sub_type and '+' in ct_sub_type:
                                    ct_left, ct_right = ct_sub_type.split('+')
                                    left, right = sub_type.split('+')
                                    if left == '*' and ct_right == right:
                                        found = True
                                        break

                if not found:
                    if debug:
                        cherrypy.log('Content-Type %s not in mime_types %r' %
                                     (ct, mime_types),
                                     context='TOOLS.GZIP')
                    return

            if debug:
                cherrypy.log('Gzipping', context='TOOLS.GZIP')
            # Return a generator that compresses the page
            response.headers['Content-Encoding'] = 'gzip'
            response.body = compress(response.body, compress_level)
            if 'Content-Length' in response.headers:
                # Delete Content-Length header so finalize() recalcs it.
                del response.headers['Content-Length']

            return

    if debug:
        cherrypy.log('No acceptable encoding found.', context='GZIP')
    cherrypy.HTTPError(406, 'identity, gzip').set_response()
예제 #30
0
def serve_file(path, content_type=None, disposition=None, name=None):
    """Set status, headers, and body in order to serve the given file.
    
    The Content-Type header will be set to the content_type arg, if provided.
    If not provided, the Content-Type will be guessed by the file extension
    of the 'path' argument.
    
    If disposition is not None, the Content-Disposition header will be set
    to "<disposition>; filename=<name>". If name is None, it will be set
    to the basename of path. If disposition is None, no Content-Disposition
    header will be written.
    """

    response = cherrypy.response

    # If path is relative, users should fix it by making path absolute.
    # That is, CherryPy should not guess where the application root is.
    # It certainly should *not* use cwd (since CP may be invoked from a
    # variety of paths). If using tools.static, you can make your relative
    # paths become absolute by supplying a value for "tools.static.root".
    if not os.path.isabs(path):
        raise ValueError("'%s' is not an absolute path." % path)

    try:
        st = os.stat(path)
    except OSError:
        raise cherrypy.NotFound()

    # Check if path is a directory.
    if stat.S_ISDIR(st.st_mode):
        # Let the caller deal with it as they like.
        raise cherrypy.NotFound()

    # Set the Last-Modified response header, so that
    # modified-since validation code can work.
    response.headers['Last-Modified'] = http.HTTPDate(st.st_mtime)
    cptools.validate_since()

    if content_type is None:
        # Set content-type based on filename extension
        ext = ""
        i = path.rfind('.')
        if i != -1:
            ext = path[i:].lower()
        content_type = mimetypes.types_map.get(ext, "text/plain")
    response.headers['Content-Type'] = content_type

    if disposition is not None:
        if name is None:
            name = os.path.basename(path)
        cd = '%s; filename="%s"' % (disposition, name)
        response.headers["Content-Disposition"] = cd

    # Set Content-Length and use an iterable (file object)
    #   this way CP won't load the whole file in memory
    c_len = st.st_size
    bodyfile = open(path, 'rb')

    # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code
    if cherrypy.request.protocol >= (1, 1):
        response.headers["Accept-Ranges"] = "bytes"
        r = http.get_ranges(cherrypy.request.headers.get('Range'), c_len)
        if r == []:
            response.headers['Content-Range'] = "bytes */%s" % c_len
            message = "Invalid Range (first-byte-pos greater than Content-Length)"
            raise cherrypy.HTTPError(416, message)
        if r:
            if len(r) == 1:
                # Return a single-part response.
                start, stop = r[0]
                if stop > c_len:
                    stop = c_len
                r_len = stop - start
                response.status = "206 Partial Content"
                response.headers['Content-Range'] = ("bytes %s-%s/%s" %
                                                     (start, stop - 1, c_len))
                response.headers['Content-Length'] = r_len
                bodyfile.seek(start)
                response.body = file_generator_limited(bodyfile, r_len)
            else:
                # Return a multipart/byteranges response.
                response.status = "206 Partial Content"
                import mimetools
                boundary = mimetools.choose_boundary()
                ct = "multipart/byteranges; boundary=%s" % boundary
                response.headers['Content-Type'] = ct
                if response.headers.has_key("Content-Length"):
                    # Delete Content-Length header so finalize() recalcs it.
                    del response.headers["Content-Length"]

                def file_ranges():
                    # Apache compatibility:
                    yield "\r\n"

                    for start, stop in r:
                        yield "--" + boundary
                        yield "\r\nContent-type: %s" % content_type
                        yield ("\r\nContent-range: bytes %s-%s/%s\r\n\r\n" %
                               (start, stop - 1, c_len))
                        bodyfile.seek(start)
                        for chunk in file_generator_limited(
                                bodyfile, stop - start):
                            yield chunk
                        yield "\r\n"
                    # Final boundary
                    yield "--" + boundary + "--"

                    # Apache compatibility:
                    yield "\r\n"

                response.body = file_ranges()
        else:
            response.headers['Content-Length'] = c_len
            response.body = bodyfile
    else:
        response.headers['Content-Length'] = c_len
        response.body = bodyfile
    return response.body