Created
September 21, 2015 09:25
-
-
Save Xifax/66a243029bfd66d7aed7 to your computer and use it in GitHub Desktop.
Habraproxy, решение задачки.
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
#!/usr/bin/env python | |
# coding: utf-8 | |
# Author: Artiom Basenko | |
# Email: demi.log@gmail.com | |
# Python Version: 2.7.10 | |
# 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 webbrowser | |
import urlparse | |
import sys | |
from threading import Timer | |
import click | |
import requests | |
from bs4 import BeautifulSoup | |
from bottle import route, run | |
TM_POSTFIX_HTML = u'™' | |
WORD_LENGTH = 6 | |
class ProxyApp: | |
"""Simple configurable proxy bottle server.""" | |
def __init__(self, url, port): | |
"""Set url, port and routes""" | |
self.url = url | |
self.port = port | |
# Setup routes | |
route('/')(self.root) | |
route('/<path:path>')(self.sub) | |
def trademark(self, response): | |
"""Trademark all the 6 letter words.""" | |
if response.status_code == requests.codes.ok: | |
# Update hrefs to point to localhost:port | |
soup = BeautifulSoup(response.content, 'html.parser') | |
for a in soup.find_all('a'): | |
try: | |
domain = urlparse.urlparse(self.url).netloc | |
if domain in a['href']: | |
a['href'] = a['href'].replace( | |
domain, u'localhost:{0:d}'.format(self.port)) | |
except KeyError: | |
pass | |
# Urgh... | |
encoding = response.encoding if response.encoding else 'utf-8' | |
contents = unicode(str(soup), encoding) | |
# Find all 6 letter words (try to ignore scripts and styles) | |
words = [] | |
for div in soup.find_all('div'): | |
for word in div.text.split(u' '): | |
if len(word) == 6: | |
words.append(word) | |
# Trademark EVERYTHING | |
for word in set(words): | |
contents = contents.replace(word, word + TM_POSTFIX_HTML) | |
return contents | |
# On 404 and others | |
else: | |
return 'Cannot proxy that!' | |
def root(self): | |
"""Process base route.""" | |
return self.trademark(requests.get(self.url)) | |
def sub(self, path): | |
"""Process all the sub-routes.""" | |
return self.trademark( | |
requests.get(urlparse.urljoin(self.url, path))) | |
def run(self): | |
"""Run bottle server.""" | |
run(host='localhost', port=self.port) | |
@click.command() | |
@click.option('--url', default='http://habrahabr.ru', | |
prompt='Url to proxy', help='Url to process.') | |
@click.option('--port', default=8232, | |
prompt='Port to serve on', help='Port to listen on.') | |
@click.option('--browse', is_flag=True, default=False, | |
prompt='Launch default browser?', help='Should open browser.') | |
def serve(url, port, browse): | |
""" | |
Reverse-proxy provided url and modify page contents in an amusing manner.""" | |
# Check if provided url is valid | |
if not urlparse.urlparse(url).netloc: | |
sys.exit('Invalid url. Please specify something like http://yada.yada') | |
# Launch browser? | |
if browse: | |
t = Timer(1.0, lambda: webbrowser.open_new_tab( | |
'http://localhost:{0:d}'.format(port))) | |
t.start() | |
# Run proxy server | |
ProxyApp(url, port).run() | |
if __name__ == '__main__': | |
serve() |
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
bottle==0.12.8 | |
click==5.1 | |
requests==2.7.0 | |
beautifulsoup4==4.4.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment