-
-
Save mnacharov/44902e9eef53498f819a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding=utf8 | |
# 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 — обязательно | |
# * в случае, если не хватает каких-то данных, следует опираться на здравый смысл | |
# | |
# Если задача кажется слишом простой, можно добавить следующее: | |
# * параметры командной строки (порт, хост, сайт, отличный от хабра и т.п.) | |
# * после старта локального сервера автоматически запускается браузер с открытой | |
# обработанной™ главной страницей | |
from HTMLParser import HTMLParser | |
from StringIO import StringIO | |
import argparse | |
import mimetypes | |
import re | |
from urlparse import urljoin | |
from flask import Flask, request, Response | |
import requests | |
mimetypes.init() | |
app = Flask(__name__) | |
class TrademarkHTMLParser(HTMLParser): | |
def __init__(self, length, symbol): | |
self.result = StringIO() | |
self._length = length | |
self._symbol = symbol | |
# чтобы не менять контент скриптов и стилей | |
self._replace = True | |
HTMLParser.__init__(self) | |
def handle_starttag(self, tag, attrs): | |
if tag in ('script', 'style'): | |
self._replace = False | |
self.result.write(u'<{0} {1}>'.format(tag, u' '.join((u'{0}="{1}"'.format(key, val) if val else key for key, val in attrs)) if attrs else '')) | |
def handle_endtag(self, tag): | |
if tag in ('script', 'style'): | |
self._replace = True | |
self.result.write('</{0}>'.format(tag)) | |
def handle_data(self, data): | |
if self._replace: | |
data = re.sub(ur'(?<=[\s>«(,.])([a-zA-Zа-яА-Я]{%d})(?=[<»),.\s])' % self._length, | |
ur'\1' + self._symbol, data) | |
self.result.write(data) | |
def handle_decl(self, data): | |
self.result.write('<!{}>'.format(data)) | |
class ContentChanger(object): | |
length = 6 | |
reverse = False | |
site = 'http://habrahabr.ru/' | |
symbol = '™' | |
def __init__(self, reverse_url=None): | |
self._url = reverse_url | |
def get_content(self, path): | |
return requests.get(urljoin(self.site, path)).content | |
def change_content(self, content): | |
if content.strip().startswith('<!DOCTYPE'): | |
content = content.decode('utf8') | |
if self.reverse: | |
# пускаем всё через нас | |
content = content.replace(self.site, self._url) | |
# добавляем ™ | |
parser = TrademarkHTMLParser(self.length, self.symbol) | |
parser.feed(content) | |
return parser.result.getvalue() | |
return content | |
def serve(self, path): | |
content_type = mimetypes.types_map.get('.' + path.rsplit('.', 1)[-1], 'text/html') | |
return Response(self.change_content(self.get_content(path)), content_type=content_type) | |
@app.route("/", defaults={"path": ""}) | |
@app.route("/<path:path>") | |
def hello(path): | |
return ContentChanger(request.host_url).serve(path) | |
def main(): | |
parser = argparse.ArgumentParser(description=u'Запускает трейдмарк прокси-сервер для сайта') | |
parser.add_argument('host', metavar='host', nargs='?', type=str, default='127.0.0.1', | |
help=u'Хост на котором будет запущен прокси', ) | |
parser.add_argument('port', metavar='port', nargs='?', type=int, default=8232, | |
help=u'Номер порта на котором будет запущен прокси') | |
parser.add_argument('--site', '-S', metavar='site', type=str, default='http://habrahabr.ru/', | |
help=u'Сайт который будет показан') | |
parser.add_argument('--length', '-L', metavar='length', type=int, default=6, | |
help=u'Длина слова для которого добавлить symbol') | |
parser.add_argument('--symbol', '-Y', metavar='symbol', type=unicode, default=u'™', | |
help=u'Симвод который будет добавлен') | |
parser.add_argument('-D', '--deep', dest='deep', action='store_const', const=True, default=False, | |
help=u'Оставаться в пределах прокси при переходе по ссылкам') | |
parser.add_argument('-R', '--run', dest='browser', action='store_const', const=True, default=False, | |
help=u'Открыть браузер') | |
args = parser.parse_args() | |
ContentChanger.length = args.length | |
ContentChanger.reverse = args.deep | |
ContentChanger.site = args.site | |
ContentChanger.symbol = args.symbol | |
if args.browser: | |
import webbrowser | |
webbrowser.open_new_tab('http://{}:{}'.format(args.host, args.port)) | |
app.run(args.host, args.port) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment