Skip to content

Instantly share code, notes, and snippets.

@truetug
Last active March 21, 2016 21:08
Show Gist options
  • Save truetug/aa1fa38253e9d10c4839 to your computer and use it in GitHub Desktop.
Save truetug/aa1fa38253e9d10c4839 to your computer and use it in GitHub Desktop.
Тестовая задачка от ivelum.com
#!/usr/bin/env python
# encoding: utf-8
# habraproxy.py — это простейший http-прокси-сервер, запускаемый локально (порт на ваше
# усмотрение), который показывает содержимое страниц Хабра. С одним исключением: после
# каждого слова из шести букв должен стоять значок «™». Примерно так:
#
# http://habrahabr.ru/company/yandex/blog/258673/
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Сейчас на фоне уязвимости Logjam все в индустрии в очередной раз обсуждают проблемы и
# особенности TLS. Я хочу воспользоваться этой возможностью, чтобы поговорить об одной из
# них, а именно — о настройке ciphersiutes.
#
# http://127.0.0.1:8232/company/yandex/blog/258673/
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Сейчас™ на фоне уязвимости Logjam™ все в индустрии в очередной раз обсуждают проблемы и
# особенности TLS. Я хочу воспользоваться этой возможностью, чтобы поговорить об одной из
# них, а именно™ — о настройке ciphersiutes.
#
# Условия:
# * Python 2.x
# * можно использовать любые общедоступные библиотеки, которые сочтёте нужным
# * чем меньше кода, тем лучше. PEP8 — обязательно
# * в случае, если не хватает каких-то данных, следует опираться на здравый смысл
#
# Если задача кажется слишом простой, можно добавить следующее:
# * параметры командной строки (порт, хост, сайт, отличный от хабра и т.п.)
# * после старта локального сервера автоматически запускается браузер с открытой
# обработанной™ главной страницей
import re
import os
import imp
import signal
import logging
import webbrowser
try:
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.options import define, options, \
parse_command_line, parse_config_file
from tornado.web import Application, RequestHandler
from tornado.httpclient import AsyncHTTPClient
import bs4
imp.find_module('html5lib')
except ImportError:
requirements = (
'tornado==4.3',
'html5lib==0.9999999',
'beautifulsoup4==4.4.1'
)
msg = (
'Please install requirements:',
'virtualenv env && '
'. env/bin/activate && '
'pip install {0} && python {1}',
)
print '\n'.join(msg).format(' '.join(requirements), __file__)
exit(1)
NAME = 'xa6pokcug'
WORD_RE = re.compile(
r'(?:^|(?<=\s))(\w{6})(?:(?=\s)|$)',
flags=(re.MULTILINE | re.UNICODE)
)
IGNORE_TAGS = ('script', 'style', 'pre', 'code', 'iframe')
logger = logging.getLogger(NAME)
logger.setLevel(logging.INFO)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
logger.addHandler(ch)
define('scheme', default='http', help="")
define('address', default='127.0.0.1', help="address to listen on")
define('port', default=8888, help="port to listen on")
define('config_file', default='config.cfg',
help='filename for additional configuration')
define('debug', default=False, group='application',
help="run in debug mode (with automatic reloading)")
define('proxy_host', default='habrahabr.ru', group='application',
help="host proxy to")
def on_start():
"""
Opens browser after app start
"""
url = "{scheme}://{address}:{port}".format(
scheme=options.scheme,
address=options.address,
port=options.port
)
webbrowser.open(url, new=2)
def on_signal(signum, frame):
"""
Handles signals
"""
logger.info('%s shutdowned because of %s',
NAME,
'{0} signal was recieved'.format(on_signal.signals.get(signum, signum))
)
exit(0)
on_signal.signals = {2: 'INT', 15: 'TERM'}
class MainHandler(RequestHandler):
@gen.coroutine
def get(self):
url = '{protocol}://{host}{path}'.format(
protocol=self.request.protocol, host=options.proxy_host,
path=self.request.uri
)
try:
response = yield AsyncHTTPClient().fetch(url)
content = response.body
except Exception as error:
response = error.response
content = response.body
content = self.process(content)
self.set_status(response.code)
self.write(content)
def process(self, content):
soup = bs4.BeautifulSoup(content, 'html5lib')
domain_re = self.application.settings.get('domain_re')
for tag in domain_re and soup.find_all('a', href=domain_re) or ():
tag.attrs['href'] = domain_re.sub(u'', tag.attrs['href'])
for node in soup.find_all(text=True):
if node.string.strip() \
and not isinstance(node, bs4.element.PreformattedString) \
and node.parent.name not in IGNORE_TAGS:
node.string.replace_with(WORD_RE.sub(u'\\1™', node.string))
return u'{0}'.format(soup)
def main():
# Catch signals
signal.signal(signal.SIGINT, on_signal)
signal.signal(signal.SIGTERM, on_signal)
parse_command_line(final=False)
if os.path.isfile(options.config_file):
parse_config_file(options.config_file)
domain_re = re.compile(r'^https?://{0}'.format(options.proxy_host))
logger.info('Come along tornado %s:%s...', options.address, options.port)
if options.debug:
logger.info(
u'\nOptions\n===\n%s\n',
u'\n'.join([u'{0}: {1}'.format(k, v) for k, v in options.items()])
)
app = Application([
(r".+", MainHandler),
], domain_re=domain_re, **options.group_dict('application'))
app.listen(options.port, options.address)
ioloop = IOLoop.current()
if not options.debug:
ioloop.add_callback(on_start)
ioloop.start()
if __name__ == "__main__":
main()
else:
logger.info('Running %s', __name__)
#!/usr/bin/env python
# encoding: utf-8
import re
import os
import imp
import signal
import webbrowser
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.options import define, options, parse_command_line, \
parse_config_file
from tornado.web import Application, RequestHandler
from tornado.httpclient import AsyncHTTPClient
import bs4
NAME = 'xa6pokcug'
WORD_RE = re.compile(
r'(?:^|(?<=\s))(\w{6})(?:(?=\s)|$)', flags=(re.MULTILINE | re.UNICODE)
)
IGNORE_TAGS = ('script', 'style', 'pre', 'code', 'iframe')
define('scheme', default='http', help="")
define('address', default='127.0.0.1', help="address to listen on")
define('port', default=8888, help="port to listen on")
define('config_file', default='config.cfg',
help='filename for additional configuration')
define('debug', default=False, group='application',
help="run in debug mode (with automatic reloading)")
define('proxy_host', default='habrahabr.ru', group='application',
help="host proxy to")
def on_start():
url = "{scheme}://{address}:{port}".format(
scheme=options.scheme, address=options.address, port=options.port
)
webbrowser.open(url, new=2)
class MainHandler(RequestHandler):
@gen.coroutine
def get(self):
url = '{protocol}://{host}{path}'.format(
protocol=self.request.protocol, host=options.proxy_host,
path=self.request.uri
)
try:
response = yield AsyncHTTPClient().fetch(url)
content = response.body
except Exception as error:
response = error.response
content = response.body
content = self.process(content)
self.set_status(response.code)
self.write(content)
def process(self, content):
soup = bs4.BeautifulSoup(content, 'html5lib')
domain_re = self.application.settings.get('domain_re')
for tag in domain_re and soup.find_all('a', href=domain_re) or ():
tag.attrs['href'] = domain_re.sub(u'', tag.attrs['href'])
for node in soup.find_all(text=True):
if node.string.strip() \
and not isinstance(node, bs4.element.PreformattedString) \
and node.parent.name not in IGNORE_TAGS:
node.string.replace_with(WORD_RE.sub(u'\\1™', node.string))
return u'{0}'.format(soup)
def main():
parse_command_line(final=False)
if os.path.isfile(options.config_file):
parse_config_file(options.config_file)
domain_re = re.compile(r'^https?://{0}'.format(options.proxy_host))
app = Application([
(r".+", MainHandler),
], domain_re=domain_re, **options.group_dict('application'))
app.listen(options.port, options.address)
ioloop = IOLoop.current()
if not options.debug:
ioloop.add_callback(on_start)
ioloop.start()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment