webページをproxyしてくれるwebアプリのソース
悪用されそうで、自重してサービスを止めていたのですが、同じようなツール
を作ってすでに公開(Google App Engineを使って無料で自宅用プロキシを運用)
されているので、私もサービスを再開し、ソースを公開することにしました。
下記で公開中です。
google code webappproxy
メインのプログラム1本とHTML1本の小さなプログラムなので全部掲載します。
guess_charsetに関しては、たばさの:urlfetchとmemcacheを使ってみるテスト
のソースを流用させていただきました。
Python歴3ヶ月程度なのでPythonのほうは滅茶苦茶。
hello.py
import re
import urllib
import logging
import urlparse
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.api import urlfetch
from google.appengine.ext.webapp import template
def guess_charset(data):
f = lambda d, enc: d.decode(enc) and enc
try: return f(data, 'utf-8')
except: pass
try: return f(data, 'shift-jis')
except: pass
try: return f(data, 'euc-jp')
except: pass
try: return f(data, 'iso2022-jp')
except: pass
return None
class MainPage(webapp.RequestHandler):
def get(self):
path = os.path.join(os.path.dirname(__file__), 'main.html')
self.response.out.write(template.render(path, {}))
class NotePage(webapp.RequestHandler):
def get(self):
url=""
if(self.request.get("url")):
if re.compile("^\s*http://").match(self.request.get("url")):
url = self.request.get("url").strip()
else:
url = "http://"+self.request.get("url").strip()
else:
if 'host' in self.request.cookies:
url = self.request.cookies['host'] + self.request.path
if url!="" :
result = urlfetch.fetch(url)
enc=guess_charset(result.content)
if enc == None or enc == "shift_jis":
enc="cp932"
dec_content = result.content.decode(enc)
enc_content = dec_content.encode("utf_8")
result.content = re.sub("charset=([a-zA-Z0-9_]*)","charset=UTF-8",enc_content,1)
if result.status_code == 200:
for k,v in result.headers.iteritems():
self.response.headers.add_header(k, v)
parseString=urlparse.urlparse(url)
cookie_val = 'host' + '=' + parseString[0]+"://"+parseString[1]
self.response.headers.add_header('Set-Cookie',cookie_val)
cookie_val = 'path' + '=' + re.sub("/[^/]*$","",parseString[2])
self.response.headers.add_header('Set-Cookie',cookie_val)
self.response.out.write(result.content)
else:
self.response.out.write("")
application = webapp.WSGIApplication(
[('/main', MainPage),(r'/[^?]*',NotePage)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
/mainでアクセスされたら、MainPageのgetを呼び出し、main.htmlを返して
います。
それ以外のアドレスはすべてNotePageのgetを呼び出します。
こうすることには
訳があり、後ほど説明します。
main.html画面にurlを入力し、displayボタンを押下すると、/?url=指定したurl
の形式でアクセスされます。
指定されたurlからurl_fetchで内容をごっそり持ってきて、utf-8に変換します。
また、クッキーに指定されたURLのHostをセットしておきます。
こうすることで、表示した画面のパスのみで記述されたリンクをクリックされた
際に、
クッキーに保存しているHost名にそのパスをくっつけることで、再び
コンテンツを
取得することができるようになります。
/main以外のアドレスをすべてNotePageのgetを呼び出すようにしたのもそういう
訳です。
main.html
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>title</title>
<link rel="shortcut icon" href="favicon.ico">
<script type="text/javascript">
function parseCooke(){
cookies = document.cookie.split(";");
obj = {};
for(var i=0;i<cookies.length;i++){
pair = cookies[i].split("=");
obj[pair[0].replace(/^\s+/,"")] = pair[1];
}
return obj;
}
function loadData()
{
document.getElementById('ifm').src = "/?url="+escape(document.getElementById('url').value);
}
function modLink()
{
var doc;
var ifm = document.getElementById("ifm");
if (document.all) {
// IE
doc = ifm.contentWindow.document;
} else {
// Mozilla
doc = ifm.contentDocument;
}
var aElems=doc.getElementsByTagName("a");
var cookie_info = parseCooke();
var nHost = cookie_info.host;
var path = cookie_info.path;
var reg = RegExp(nHost);
var reg2 = RegExp("http://"+location.host);
for(var i=0;i<aElems.length;i++)
{
var aElem = aElems[i];
if (document.all) {
if(aElem.target!=null){
aElem.target=null;
}
}
else if(aElem.target){
delete(aElem.target);
}
if(aElem.href.match(reg)){
aElem.href= aElem.href.replace(nHost,"http://"+location.host);
}
else if(!aElem.href.match(reg2)){
aElem.href="http://"+location.host+"?url="+escape(aElem.href);
}else{
if(!aElem.getAttributeNode("href").nodeValue.match(/^[\/#]/)){
aElem.href = path + "/" + aElem.getAttributeNode("href").nodeValue;
}
}
aElem.onclick=function(ev){
var elem = null;
if(ifm.contentWindow.event){
elem=ifm.contentWindow.event.srcElement;
}else
{
elem=ev.target;
}
ifm.src = elem.href;return false;
};
}
var imgElems=doc.getElementsByTagName("img");
for(var i=0;i<imgElems.length;i++)
{
var imgElem = imgElems[i];
if(!imgElem.getAttributeNode("src").nodeValue.match(/^http:/)){
if(imgElem.getAttributeNode("src").nodeValue.match(/^\//)){
imgElem.src = nHost + imgElem.getAttributeNode("src").nodeValue;
}else{
imgElem.src = nHost + "/" + path + "/" + imgElem.getAttributeNode("src").nodeValue;
}
}
}
}
</script>
</head>
<body>
<form id="note_form" target="#" onsubmit="loadData(); return false;">
URL:<input type="text" name="url" id="url" size="150"/>
<input type="submit" value="display"/>
</form>
<iframe id="ifm" frameborder='0' style="width:100%;height:100%;border:none;" onload="modLink();" >
</iframe>
</body>
</html>
main.htmlでは、displayボタンが押された時に/?url="URLのテキストボックスに
書かれた値" の形式でwebappproxyのURLを呼び出し、応答をiframeに書き出し
ています。
その際、iframeに書き出されたaタグのリンクをすべて抽出し、srcが同一ホストの
場合は、ホスト名を削除し(クッキーにホストが保存されているため),パスだけに
します。
違うホスト名の場合は/?url=違うホストのURLにします。
上記のようにすることで、proxyして表示されたリンクをたどっていっても、
proxyされ続けるようにしています。
| 固定リンク
| コメント (0)
| トラックバック (0)
最近のコメント