Beispiel #1
0
def _error_response(traceback_string):
    """Create a flask response for an error."""
    response = flask.Response(traceback_string,
                              status=500,
                              mimetype='text/plain')
    response.headers.add('Access-Control-Allow-Origin', '*')
    return response
Beispiel #2
0
def quit():
    # Taken from http://flask.pocoo.org/snippets/67/
    shutdown_func = flask.request.environ.get('werkzeug.server.shutdown')
    if shutdown_func is None:
        raise RuntimeError('Not running with the Werkzeug Server: %s'
                           % flask.request.environ)
    shutdown_func()
    return flask.Response('Server shutting down...', mimetype='text/plain')
Beispiel #3
0
def ping():
    """Simple handler used to check if the server is running.

    If 'genfiles' arg is specified, only respond with a 200 if our
    genfiles dir is the same as the specified one.

    See: kake.server_client.start_server
    """
    if flask.request.args.get('genfiles'):
        if project_root.join('genfiles') != flask.request.args.get('genfiles'):
            flask.abort(400)
            return

    return flask.Response('pong', mimetype='text/plain')
Beispiel #4
0
def serve_sourcemap(filename):
    """The sourcemap is automatically created along with its file."""
    # This forces the .map file to get made too, if filename has one.
    non_map_response = serve_genfile(filename)
    # We'll say the .map file was last modified when its corresponding
    # .js/.css file was.
    last_modified_time = non_map_response.headers['Last-modified']

    abspath = project_root.join('genfiles', filename + '.map')
    try:
        with open(abspath) as f:
            content = f.read()
    except (IOError, OSError):
        flask.abort(404)

    # The consensus is that sourcemap files should have type json:
    #    http://stackoverflow.com/questions/18809567/what-is-the-correct-mime-type-for-min-map-javascript-source-files
    response = flask.Response(content, mimetype='application/json')
    _add_caching_headers(response, last_modified_time)

    # TODO(jlfwong): We always return a 200 for sourcemap files, when really we
    # should be returning a 304 sometimes based on the If-Modified-Since
    # header, like we do for non-sourcemap files.
    return response
Beispiel #5
0
def outdir():
    """Simple handler to report the directory where we write our files.

    See: kake.server_client.start_server
    """
    return flask.Response(project_root.join('genfiles'), mimetype='text/plain')
Beispiel #6
0
def serve_genfile(filename):
    """Serve a file from genfiles/, building it first if necessary.

    Arguments:
        filename: the filename to serve, relative to ka-root/genfiles/
        _force: force re-build of filename even if it's up-to-date
        (query parameters): all other parameters a=b, where a does not
           start with an underscore, are added to the kake
           context-dict (as {a: b}).  Parameters starting with _
           are *not* added to the context dict.
    """
    abspath = project_root.join('genfiles', filename)

    # This converts a werkzeug MultiDict to a normal dict.
    context = dict((k, v) for (k, v) in flask.request.args.iteritems()
                   if not k.startswith('_'))
    force = flask.request.args.get('_force', False)

    # The call to build below will modify the context, but we want
    # the original context to pass through to the SourceMap header.
    user_context = context.copy()

    # TODO(csilvers): use a file-watcher to remove files from
    #    _LASTMOD_TIMES as they change.  Then we don't need to call
    #    kake.make.build() at all if filename is in _LASTMOD_TIMES.
    #    To do this, we'd need to keep a map from filename to all
    #    files that depend on it.  We could also update filemod_db's
    #    mtime-cache via this file-watcher.
    try:
        with _BUILD_LOCK:
            # We pass in None for the checkpoint interval to prevent automatic
            # syncing of the filemod db, since we do that ourselves.
            file_changed = kake.make.build(os.path.join('genfiles', filename),
                                           context, force=force,
                                           checkpoint_interval=None)
            maybe_sync_filemod_db()
    except compile_rule.GracefulCompileFailure as e:
        # If the page is requested directly, just let the regular werkzeug
        # debugger display the error, otherwise serve the graceful response.
        if flask.request.accept_mimetypes.best == 'text/html':
            raise

        mimetype = mimetypes.guess_type(filename)[0]
        response = flask.Response(e.graceful_response, mimetype=mimetype)
        response.headers.add('Access-Control-Allow-Origin', '*')
        return response
    except compile_rule.BadRequestFailure as failure:
        return flask.Response(
            "BAD REQUEST: %s\n" % failure.message,
            mimetype="text/*",
            status=400)
    except Exception:
        # If it's a normal http request, re-raise and get the cool
        # werkzeug debugger output.  If it's a javascript (XHR)
        # request, give our own output which is less cool but safer
        # to use with Access-Control-Allow-Origin.
        if flask.request.headers.get('Origin'):
            return _error_response(traceback.format_exc())
        raise

    if file_changed or filename not in _LASTMOD_TIMES:
        mtime = os.path.getmtime(abspath)
        dtime = datetime.datetime.fromtimestamp(mtime)
        _LASTMOD_TIMES[filename] = dtime.strftime("%a, %d %b %Y %H:%M:%S GMT")   # @Nolint(API expected English date-names)

    # If the file hasn't changed, and the etag matches, return a 304.
    client_mtime = flask.request.headers.get("If-Modified-Since")
    if client_mtime == _LASTMOD_TIMES[filename]:
        response = flask.Response(status=304)
        _add_caching_headers(response, _LASTMOD_TIMES[filename])
        _maybe_add_sourcemap_header(response, filename, user_context)
        return response

    with open(abspath) as f:
        content = f.read()

    response = flask.Response(content,
                              mimetype=mimetypes.guess_type(filename)[0])
    _add_caching_headers(response, _LASTMOD_TIMES[filename])
    # If we have a sourcemap, tell the client.
    _maybe_add_sourcemap_header(response, filename, user_context)

    return response