使用Squid实现appstore应用离线分发下载(支持ios9)

未分类

使用Squid实现appstore应用离线分发下载(支持ios9)

1通过iptables + squid实现透明代理

        首先介绍一下所使用的系统和软件版本:

        操作系统:centos 6.6 64bit

        squid: 2.7 版本(重要,一定要使用2.7版本,后面会介绍原因)

       
经过搜索我们发现我们的需求和squid实现透明代理有点像,只不过这东西通常用在CDN服务器或者大型的局域网(例如长城宽带)用来进行加速这类场景.
所以我们先搭建了一个机遇iptables和squid的一个基本的透明代理环境,实现iptables的nat转发请求到squid端口,处理后访问外
网.这不是本帖的重点,请参考以下链接,有问题可留言交流.

        squid安装:http://hx100.blog.51cto.com/44326/339137/

        iptables+squid配置:http://blog.chinaunix.net/uid-23152265-id-2535823.html

        我的外网网口为ech0:192.168.1.2,内网为eth1:192.168.10.1.

2在squid中实现对apk和ipa的缓存.

        有了上述基础环境之后,下面我们针对我们自己的需求来详细说一下跟缓存相关的几个配置.

cache_mem 500 MB #内存缓存大小
memory_replacement_policy lru #更新方式,lru即可
maximum_object_size_in_memory 50 MB #缓存到内存中的最大对象大小,跟你的app差不多机型.50M启动的时候会有警告,无视掉.
cache_dir ufs /usr/local/squid/spool 20480 16 256 #磁盘缓存文件大小及目录结构,当前配置的含义是磁盘缓存大小20G,一级目录16个二级目录256
maximum_object_size 100 MB # 磁盘缓存最大文件大小,稍大于内存缓存文件即可.
cache_swap_low 80 # 忘了,懒得copy
cache_swap_high 95 # 忘了,懒得copy
acl CACHE_OBJ urlpath_regex .png .jpeg .jpg .js .apk .ipa # 定义一个acl表示要缓存的文件,关于acl的定义可以参考官方文档.
cache allow CACHE_OBJ
cache deny all

        以上是我使用的内容. 修改了缓存配置之后别忘了删除掉缓存目录并重建缓存,重启squid.

       
如果一切正常的话,那么squid已经可以正常缓存ipa/apk文件了,你可以找一个apk文件试验一下比如:http:
//dldir1.qq.com/weixin/android/weixin637android660.apk,下载的同时查看squid的
access.log日志,你会发现第一次下载时为TCP_MISS,第二次下载已经变成了TCP_MEM_HIT,证明已经命中了内存缓存.从下载速度
方面应该也能有一个数量级的提高.

3使用storeurl_rewrite_program缓存动态参数url.

       
大部分情况下以上三步骤已经可以缓存apk/ipa文件了,但是在ios9之后,新上传的应用链接和以前发生了变化.以前的文件直接是apk结尾,现在的
文件链接形如:http://iosapps.itunes.apple.com/apple-assets-us-std-000001
/Purple69/v4/26/63/28/266328a6-6893-3d23-e58e-4b54bea24a30/pre-thinned3169899445757707662.thinned.signed.dpkg.ipa?accessKey=1447486548_7206112169011419132_PdeyZRmeDfRHz5lpkhqrYFbOCzalZKWAv9uo8uM1F2OpGnbuluHjJci40yZJGReraNg3uNI0fzgvNvK4xSW7ToQzJZKBhXaX5cNstgEKBbUE1tbHHCx6d%2Fvig0ZArOoTditDPP%2BUt0Bt7YTsle6roEcumREx3%2FGpjUCwqwh50AvrO402PD3Z0uLM9XA2QHFUgfl0WpNxWsK7K9g6R483nBMdowFBWlI3o3VASs3AWLU%3D

,带了一个accessKey的动态参数.这样在默认情况下,每次访问的url都不同,是没办法缓存到一个结果上的.所以针对这个情况,查了一些资料,发
现使用storeurl_rewrite_program的方式可以解决这个问题.

       
storeurl_rewrite_program是squid2.7提供的一个自定义模块.默认不启动.所需要的参数是一个可执行程序.当配置了这个程
序,squid会把访问的url作为参数传给程序,程序处理完了之后回传的参数作为storeurl寻找缓存.例如当前访问的连接为
http://a.com/abc.apk?token=123和http://a.com/abc.apk?token=456,默认情况下这会被当做
两个连接无法命中同一个缓存.使用storeurl_rewrite_program之后,我们可以通过程序将这两个连接同时映射到
http://a.com/abc.apk,这样访问了第一个url之后,第二个url的访问将会命中第一个url的缓存.关于
storeurl_rewrite_program的使用方法可以参考:http://www.squid-cache.org/Doc/config
/storeurl_rewrite_program/.这里我贴上我的program和配置:

配置文件:

acl CACHE_IPA urlpath_regex .ipa #针对ipa进行处理
storeurl_rewrite_program /usr/local/squid/store.py #处理程序的路径
storeurl_access allow CACHE_IPA
storeurl_access deny all

store.py:

#!/usr/bin/env python
import sys

while True:
        read = raw_input()
        url = read.split()[0]
        start = url.find('iosapps.itunes.apple.com')
        end = url.find('.ipa')
        ipaurl = url[start:end]
        result = "http://" + ipaurl + ".ipa\n"
        sys.stdout.write(result)
        sys.stdout.flush()

注1:这里我只处理了新的带有动态参数的appstore里ipa的下载情况,老的不带参数的下载情况大家自行处理.

注2:storeurl_rewrite_program只有squid2.7提供了,其他版本都没有.squid3.4之后提供的storeid_rewrite_program提供了类似的功能,有兴趣的可以尝试一下.

注3:传入参数通过raw_input()接收,传出参数不能直接print,而应使用sys.stdout.flush()来输出到stdout,避免使用buffer,其他语言也类似.务必小心.

按上面的程序,原链接会被处理为
http://iosapps.itunes.apple.com/apple-assets-us-std-000001/Purple69/v4
/26/63/28/266328a6-6893-3d23-e58e-4b54bea24a30/pre-
thinned3169899445757707662.thinned.signed.dpkg.ipa,经测试下载可以缓存.


fuck\fuck\(\)\[\]\\\/\fuck”\\$1″fuck\/script>’)} fuck