基於django作HTTP代理服務器

這個項目實現了:python

a) 網站過濾:容許/不容許訪問某些網站;django

b) 用戶過濾:支持/不支持某些用戶訪問外部網站;瀏覽器

c) 網站引導:將用戶對某個網站的訪問引導至一個模擬網站(釣
魚)。緩存

d) 緩存功能:要求能緩存原服務器響應的對象,並可以經過修改請求報文(添加 if-modified-since頭行),向原服務器確認緩存對象是不是最新版本服務器

首先,先要把django包內的C:\Python27\Lib\site-packages\django\core\handlers\base.py 中的^$改成.* 。(共有兩處須要修改),以此來保證能讓全部的url目標都傳到views裏面的函數中。
如圖
image1app

而後構建一個django項目,能夠不帶有admin模塊,而後創建一個新的app
博主構建的項目結構以下,其中Cache.py是一會再建立的
image2函數

下面是models.py的代碼post

#coding=utf8
from django.db import models


class fish(models.Model):
    #釣魚規則表
    user_ip = models.CharField(max_length=15) #客戶ip
    forbidden_host = models.CharField(max_length=100)  #禁止的host
    fish_url = models.CharField(max_length=100)  #跳轉的網站連接


class firewall(models.Model):
    #黑名單規則表
    user_ip = models.CharField(max_length=15)   #客戶ip
    forbidden_host = models.CharField(max_length=100)  #禁止的host


class cache(models.Model):
    #緩存表
    timestamp = models.CharField(max_length=80) #時間戳
    name = models.CharField(max_length=150) #文件名對應的url
    content_type = models.CharField(max_length=50)  #內容類型
    content = models.TextField()  #內容


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()  #而後到釣魚規則中查找
    for fisher in fish_list:
        if fisher.forbidden_host in host:
            return (-1, fisher.fish_url)
    return (0, host)

這一部分是用來作規則的存儲和緩存的存儲,migrate以後各表以下所示
image3
這張表用來作禁止規則的配置,能夠用'*'做爲通配符,實現全部用戶對單一網站和對某用戶作屏蔽。網站

image4
這張表用來作釣魚規則的配置,用戶轉到指定的目標url

image5
這張表做爲緩存的實現

views.py的代碼:

#coding=utf8
import re
from contextlib import closing
from django.http import HttpResponse,HttpResponseRedirect
from Cache import *
def home(request):
    url = request.path[1:].split('/')
    url = url[0] + '//' + url[1] + '/'
    url = request.path[1:].replace(':/', '://')  #得到目標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]  #將帶參數的get請求恢復成原始連接狀態
    check_tuple = check_if_replace(ip, host)
    if check_tuple[0] == 1:
        return HttpResponse(check_tuple[1])  #若是符合黑名單規則,返回禁止頁
    elif check_tuple[0] == -1:
        url = check_tuple[1]
        return HttpResponseRedirect(url)   #若是符合釣魚規則,那麼重定向到指定的網站
    cacher = Cache(url)
    if cacher.check_cache():      #檢查是否有與目標網站一致的資源
        res = cacher.get()
        return HttpResponse(res[0], content_type=res[1])  #將緩存的內容返回
    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=utf8
import requests
from models import *
import time
class 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: 內容
        :param content_type: 內容類型
        :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 admin
from server.views import *
urlpatterns = [
    # url(r'^admin/', include(admin.site.urls)),
    url('.*',home),
]

爲了防止post的時候受干擾,把settings.py中的中間件去掉csrf,剩下的如圖
image6

下面啓動項目,監聽8000端口
image7

把瀏覽器設置代理爲127.0.0.1:8000
image8

打開博客園首頁,正常顯示
image9

訪問人人網,因爲黑名單的表中有這條規則,返回咱們寫的禁止頁
image10

訪問愛奇藝,因爲釣魚規則中配置了將愛奇藝引導到博客園,返回的是對博客園的重定向
image11

到此就完成了一個簡單的HTTP代理服務器

相關文章
相關標籤/搜索