計(jì)算機(jī)網(wǎng)絡(luò)的一次小實(shí)驗(yàn),最后一共用了不到100行
實(shí)現(xiàn)了:
a) 網(wǎng)站過濾:允許/不允許訪問某些網(wǎng)站;
b) 用戶過濾:支持/不支持某些用戶訪問外部網(wǎng)站;
c) 網(wǎng)站引導(dǎo):將用戶對(duì)某個(gè)網(wǎng)站的訪問引導(dǎo)至一個(gè)模擬網(wǎng)站(釣
魚)。
d) 緩存功能:要求能緩存原服務(wù)器響應(yīng)的對(duì)象,并能夠通過修改請(qǐng)求報(bào)文(添加 if-modified-since頭行),向原服務(wù)器確認(rèn)緩存對(duì)象是否是最新版本
首先,先要把django包內(nèi)的C:\Python27\Lib\site-packages\django\core\handlers\base.py 中的^$改為.* 。(共有兩處需要修改),以此來保證能讓所有的url目標(biāo)都傳到views里面的函數(shù)中。
如圖
然后構(gòu)建一個(gè)django項(xiàng)目,可以不帶有admin模塊,然后建立一個(gè)新的app
博主構(gòu)建的項(xiàng)目結(jié)構(gòu)如下,其中Cache.py是一會(huì)再創(chuàng)建的
下面是models.py的代碼
#coding=utf8from django.db import modelsclass fish(models.Model): #釣魚規(guī)則表 user_ip = models.CharField(max_length=15) #客戶ip forbidden_host = models.CharField(max_length=100) #禁止的host fish_url = models.CharField(max_length=100) #跳轉(zhuǎn)的網(wǎng)站鏈接class firewall(models.Model): #黑名單規(guī)則表 user_ip = models.CharField(max_length=15) #客戶ip forbidden_host = models.CharField(max_length=100) #禁止的hostclass cache(models.Model): #緩存表 timestamp = models.CharField(max_length=80) #時(shí)間戳 name = models.CharField(max_length=150) #文件名對(duì)應(yīng)的url content_type = models.CharField(max_length=50) #內(nèi)容類型 content = models.TextField() #內(nèi)容def check_if_replace(user_ip, host): user_list = firewall.objects.filter(user_ip=user_ip).all() #先到黑名單中查找 for user in user_list: if user.forbidden_host in host or host == '*': return (1, '<h1>You have been forbidden!</h1>') #返回禁止頁 general = firewall.objects.filter(user_ip='*').all() for i in general: if i.forbidden_host in host: return (1, '<h1>You have been forbidden!</h1>') fish_list = fish.objects.filter(user_ip=user_ip).all() #然后到釣魚規(guī)則中查找 for fisher in fish_list: if fisher.forbidden_host in host: return (-1, fisher.fish_url) return (0, host)
這一部分是用來做規(guī)則的存儲(chǔ)和緩存的存儲(chǔ),migrate之后各表如下所示
這張表用來做禁止規(guī)則的配置,可以用'*'作為通配符,實(shí)現(xiàn)所有用戶對(duì)單一網(wǎng)站和對(duì)某用戶做屏蔽。
這張表用來做釣魚規(guī)則的配置,用戶轉(zhuǎn)到指定的目標(biāo)
這張表作為緩存的實(shí)現(xiàn)
views.py的代碼:
#coding=utf8import refrom contextlib import closingfrom django.http import HttpResponse,HttpResponseRedirectfrom Cache import *def home(request): url = request.path[1:].split('/') url = url[0] + '//' + url[1] + '/' url = request.path[1:].replace(':/', '://') #獲得目標(biāo)url host = request.get_host() method = request.method if request.META.has_key('HTTP_X_FORWARDED_FOR'): ip = request.META['HTTP_X_FORWARDED_FOR'] #獲取客戶端ip else: ip = request.META['REMOTE_ADDR'] regex = re.compile('^HTTP_') headers = dict((regex.sub('', header), value) for (header, value) in request.META.items() if header.startswith('HTTP_')) if len(request.REQUEST.items()) > 0: url += '?' for (i, j) in request.REQUEST.items(): url += str(i) + '=' + str(j) + '&' url = url[:-1] #將帶參數(shù)的get請(qǐng)求恢復(fù)成原始鏈接狀態(tài) check_tuple = check_if_replace(ip, host) if check_tuple[0] == 1: return HttpResponse(check_tuple[1]) #如果符合黑名單規(guī)則,返回禁止頁 elif check_tuple[0] == -1: url = check_tuple[1] return HttpResponseRedirect(url) #如果符合釣魚規(guī)則,那么重定向到指定的網(wǎng)站 cacher = Cache(url) if cacher.check_cache(): #檢查是否有與目標(biāo)網(wǎng)站一致的資源 res = cacher.get() return HttpResponse(res[0], content_type=res[1]) #將緩存的內(nèi)容返回 else: with closing(requests.request(method, url, headers=headers, data=request.POST, stream=True)) as r: cacher.update(bytes(r.content), content_type=r.headers['content-type']) #更新緩存 return HttpResponse(bytes(r.content), status=r.status_code, content_type=r.headers['content-type']) #返回資源
Cache.py的代碼
#coding=utf8import requestsfrom models import *import timeclass Cache(): def __init__(self, url): self.url = url def check_cache(self): ''' 檢查是否有一致的緩存 :return: Boolean型 ''' try: f = cache.objects.get(name=self.url) headers = {'If-Modified-Since': f.timestamp} if requests.get(self.url, headers=headers).status_code == 304: return True else: return False except: return False def update(self, content, content_type): ''' 更新緩存 :param content: 內(nèi)容 :param content_type: 內(nèi)容類型 :return: ''' try: f = cache.objects.get(name=self.url) f.content = content f.content_type = content_type f.name = self.url t = time.asctime().split() f.timestamp = t[0] + ', '+t[2] + ' '+t[1] +' '+t[4]+' '+t[3] + 'GMT' f.save() except: f = cache() f.content = content f.name = self.url t = time.asctime().split() f.timestamp = t[0] + ', ' + t[2] + ' ' + t[1] + ' ' + t[4] + ' ' + t[3] + ' GMT' f.content_type = content_type f.save() def get(self): #獲取緩存 f = cache.objects.get(name=self.url) return (f.content, f.content_type)
最后修改urls.py
from django.conf.urls import include, url# from django.contrib import adminfrom server.views import *urlpatterns = [ # url(r'^admin/', include(admin.site.urls)), url('.*',home), ]
為了防止post的時(shí)候受干擾,把settings.py中的中間件去掉csrf,剩下的如圖
下面啟動(dòng)項(xiàng)目,監(jiān)聽8000端口
把瀏覽器設(shè)置代理為127.0.0.1:8000
打開博客園首頁,正常顯示
訪問人人網(wǎng),由于黑名單的表中有這條規(guī)則,返回我們寫的禁止頁
訪問愛奇藝,由于釣魚規(guī)則中配置了將愛奇藝引導(dǎo)到博客園,返回的是對(duì)博客園的重定向
到此就完成了一個(gè)簡(jiǎn)單的HTTP代理服務(wù)器
http://www.cnblogs.com/chuxiuhong/p/6817858.html