Move symbol static to /symbols

This commit is contained in:
Julien Duponchelle 2016-06-28 18:17:48 +02:00
parent c5fa699b9e
commit 5b4e668eb5
No known key found for this signature in database
GPG Key ID: CE8B29639E07F5E8
8 changed files with 67 additions and 106 deletions

View File

@ -40,9 +40,10 @@ class Symbols:
'symbol_id': symbol_id, 'symbol_id': symbol_id,
'filename': file, 'filename': file,
'builtin': True, 'builtin': True,
'url': '/static/builtin_symbols/' + file
}) })
self._symbols_path[symbol_id] = os.path.join(get_resource("symbols"), file) self._symbols_path[symbol_id] = os.path.join(get_resource("symbols"), file)
symbols.sort(key=lambda x: x["filename"])
#TODO: support ~/GNS3/symbols directory #TODO: support ~/GNS3/symbols directory
return symbols return symbols

View File

@ -16,7 +16,6 @@
from gns3server.handlers.index_handler import IndexHandler from gns3server.handlers.index_handler import IndexHandler
from gns3server.handlers.static_handler import StaticHandler
from gns3server.handlers.api.controller import * from gns3server.handlers.api.controller import *

View File

@ -36,3 +36,17 @@ class SymbolHandler:
controller = Controller.instance() controller = Controller.instance()
response.json(controller.symbols.list()) response.json(controller.symbols.list())
@Route.get(
r"/symbols/{symbol_id:.+}/raw",
description="Get the symbol file",
status_codes={
200: "Symbol returned"
})
def raw(request, response):
controller = Controller.instance()
try:
yield from response.file(controller.symbols.get_path(request.match_info["symbol_id"]))
except KeyError:
response.set_status(404)

View File

@ -1,66 +0,0 @@
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import asyncio
import mimetypes
from aiohttp import hdrs
from gns3server.web.route import Route
from gns3server.utils.get_resource import get_resource
class StaticHandler:
@Route.get(
r"/static/{type}/{path:.+}",
description="Serve static content from various locations"
)
def get(request, response):
type = request.match_info["type"]
# CLeanup the path for security
path = os.path.normpath(request.match_info["path"]).strip('/.')
if type == "builtin_symbols":
try:
yield from StaticHandler._serve_file(os.path.join(get_resource("symbols"), path), request, response)
except OSError:
response.set_status(404)
@asyncio.coroutine
def _serve_file(path, request, response):
ct, encoding = mimetypes.guess_type(path)
if not ct:
ct = 'application/octet-stream'
if encoding:
response.headers[hdrs.CONTENT_ENCODING] = encoding
response.content_type = ct
st = os.stat(path)
response.last_modified = st.st_mtime
response.content_length = st.st_size
with open(path, 'rb') as fobj:
response.start(request)
chunk_size = 4096
chunk = fobj.read(chunk_size)
while chunk:
response.write(chunk)
yield from response.drain()
chunk = fobj.read(chunk_size)
if chunk:
response.write(chunk[:count])
yield from response.drain()

View File

@ -17,11 +17,14 @@
import json import json
import jsonschema import jsonschema
import aiohttp
import aiohttp.web import aiohttp.web
import mimetypes
import asyncio import asyncio
import logging import logging
import sys
import jinja2 import jinja2
import sys
import os
from ..utils.get_resource import get_resource from ..utils.get_resource import get_resource
from ..version import __version__ from ..version import __version__
@ -102,6 +105,35 @@ class Response(aiohttp.web.Response):
raise aiohttp.web.HTTPBadRequest(text="{}".format(e)) raise aiohttp.web.HTTPBadRequest(text="{}".format(e))
self.body = json.dumps(answer, indent=4, sort_keys=True).encode('utf-8') self.body = json.dumps(answer, indent=4, sort_keys=True).encode('utf-8')
@asyncio.coroutine
def file(self, path):
"""
Return a file as a response
"""
ct, encoding = mimetypes.guess_type(path)
if not ct:
ct = 'application/octet-stream'
if encoding:
self.headers[aiohttp.hdrs.CONTENT_ENCODING] = encoding
self.content_type = ct
st = os.stat(path)
self.last_modified = st.st_mtime
self.content_length = st.st_size
with open(path, 'rb') as fobj:
self.start(self._request)
chunk_size = 4096
chunk = fobj.read(chunk_size)
while chunk:
self.write(chunk)
yield from self.drain()
chunk = fobj.read(chunk_size)
if chunk:
self.write(chunk[:count])
yield from self.drain()
def redirect(self, url): def redirect(self, url):
""" """
Redirect to url Redirect to url

View File

@ -26,8 +26,12 @@ def test_list():
symbols = Symbols() symbols = Symbols()
assert { assert {
'symbol_id': ':/symbols/firewall.svg', 'symbol_id': ':/symbols/firewall.svg',
'url': '/static/builtin_symbols/firewall.svg',
'filename': 'firewall.svg', 'filename': 'firewall.svg',
'builtin': True 'builtin': True
} in symbols.list() } in symbols.list()
assert symbols assert symbols
def test_get_path():
symbols = Symbols()
assert symbols.get_path(':/symbols/firewall.svg') == get_resource("symbols/firewall.svg")

View File

@ -15,6 +15,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import urllib.parse
from gns3server.config import Config from gns3server.config import Config
@ -23,7 +25,17 @@ def test_symbols(http_controller):
assert response.status == 200 assert response.status == 200
assert { assert {
'symbol_id': ':/symbols/firewall.svg', 'symbol_id': ':/symbols/firewall.svg',
'url': '/static/builtin_symbols/firewall.svg',
'filename': 'firewall.svg', 'filename': 'firewall.svg',
'builtin': True 'builtin': True
} in response.json } in response.json
def test_get(http_controller):
response = http_controller.get('/symbols/' + urllib.parse.quote(':/symbols/firewall.svg') + '/raw')
assert response.status == 200
assert response.headers['CONTENT-LENGTH'] == '9381'
assert response.headers['CONTENT-TYPE'] == 'image/svg+xml'
assert '</svg>' in response.html
response = http_controller.get('/symbols/404.png/raw')
assert response.status == 404

View File

@ -1,35 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import aiohttp
import os
from unittest.mock import patch
def test_get(http_root):
response = http_root.get('/static/builtin_symbols/firewall.svg')
assert response.status == 200
assert response.headers['CONTENT-LENGTH'] == '9381'
assert response.headers['CONTENT-TYPE'] == 'image/svg+xml'
assert '</svg>' in response.html
response = http_root.get('/static/builtin_symbols/../main.py')
assert response.status == 404
response = http_root.get('/static/builtin_symbols/404.png')
assert response.status == 404