0000: 23 21 2f 75 73 72 2f 62 69 6e 2f 65 6e 76 20 70 #!/usr/bin/env p
0010: 79 74 68 6f 6e 33 2e 33 0a 0a 69 6d 70 6f 72 74 ython3.3..import
0020: 20 61 72 67 70 61 72 73 65 2c 20 6f 73 0a 70 61 argparse, os.pa
0030: 72 73 65 72 20 3d 20 61 72 67 70 61 72 73 65 2e rser = argparse.
0040: 41 72 67 75 6d 65 6e 74 50 61 72 73 65 72 28 29 ArgumentParser()
0050: 0a 70 61 72 73 65 72 2e 61 64 64 5f 61 72 67 75 .parser.add_argu
0060: 6d 65 6e 74 28 27 2d 63 27 2c 20 27 2d 2d 63 6f ment('-c', '--co
0070: 6e 66 69 67 27 2c 20 64 65 73 74 20 3d 20 27 63 nfig', dest = 'c
0080: 6f 6e 66 69 67 27 2c 20 68 65 6c 70 20 3d 20 27 onfig', help = '
0090: 63 6f 6e 66 69 67 20 66 69 6c 65 20 6c 6f 63 61 config file loca
00a0: 74 69 6f 6e 27 2c 20 6d 65 74 61 76 61 72 20 3d tion', metavar =
00b0: 20 27 46 49 4c 45 27 2c 20 64 65 66 61 75 6c 74 'FILE', default
00c0: 20 3d 20 27 73 61 6d 65 73 69 74 65 2e 63 6f 6e = 'samesite.con
00d0: 66 27 29 0a 61 72 67 73 20 3d 20 70 61 72 73 65 f').args = parse
00e0: 72 2e 70 61 72 73 65 5f 61 72 67 73 28 29 0a 61 r.parse_args().a
00f0: 73 73 65 72 74 20 6f 73 2e 61 63 63 65 73 73 28 ssert os.access(
0100: 61 72 67 73 2e 63 6f 6e 66 69 67 2c 20 6f 73 2e args.config, os.
0110: 52 5f 4f 4b 29 2c 20 22 46 61 74 61 6c 20 65 72 R_OK), "Fatal er
0120: 72 6f 72 3a 20 63 61 6e 27 74 20 72 65 61 64 20 ror: can't read
0130: 7b 7d 22 2e 66 6f 72 6d 61 74 28 61 72 67 73 2e {}".format(args.
0140: 63 6f 6e 66 69 67 29 0a 0a 69 6d 70 6f 72 74 20 config)..import
0150: 63 6f 6e 66 69 67 70 61 72 73 65 72 0a 63 6f 6e configparser.con
0160: 66 69 67 20 3d 20 63 6f 6e 66 69 67 70 61 72 73 fig = configpars
0170: 65 72 2e 43 6f 6e 66 69 67 50 61 72 73 65 72 28 er.ConfigParser(
0180: 7b 0a 09 27 70 6f 72 74 27 3a 20 27 38 30 30 38 {..'port': '8008
0190: 27 2c 0a 09 27 76 65 72 62 6f 73 65 27 3a 20 27 ',..'verbose': '
01a0: 6e 6f 27 2c 0a 09 27 6e 6f 65 74 61 67 27 3a 20 no',..'noetag':
01b0: 27 6e 6f 27 2c 0a 09 27 6e 6f 70 61 72 74 73 27 'no',..'noparts'
01c0: 3a 20 27 6e 6f 27 2c 0a 09 27 73 74 72 69 70 27 : 'no',..'strip'
01d0: 3a 20 27 27 2c 0a 09 27 73 75 62 27 3a 20 27 27 : '',..'sub': ''
01e0: 2c 0a 09 27 70 72 6f 74 6f 27 3a 20 27 68 74 74 ,..'proto': 'htt
01f0: 70 27 2c 0a 7d 29 0a 63 6f 6e 66 69 67 2e 72 65 p',.}).config.re
0200: 61 64 28 61 72 67 73 2e 63 6f 6e 66 69 67 29 0a ad(args.config).
0210: 0a 63 61 63 68 65 5f 64 69 72 20 3d 20 6f 73 2e .cache_dir = os.
0220: 70 61 74 68 2e 72 65 61 6c 70 61 74 68 28 6f 73 path.realpath(os
0230: 2e 70 61 74 68 2e 64 69 72 6e 61 6d 65 28 61 72 .path.dirname(ar
0240: 67 73 2e 63 6f 6e 66 69 67 29 29 0a 0a 69 6d 70 gs.config))..imp
0250: 6f 72 74 20 72 65 0a 66 6f 72 20 73 65 63 74 69 ort re.for secti
0260: 6f 6e 20 69 6e 20 63 6f 6e 66 69 67 2e 73 65 63 on in config.sec
0270: 74 69 6f 6e 73 28 29 3a 0a 09 69 66 20 73 65 63 tions():..if sec
0280: 74 69 6f 6e 20 21 3d 20 27 44 45 46 41 55 4c 54 tion != 'DEFAULT
0290: 27 3a 0a 09 09 69 66 20 27 64 69 72 27 20 69 6e ':...if 'dir' in
02a0: 20 63 6f 6e 66 69 67 5b 73 65 63 74 69 6f 6e 5d config[section]
02b0: 3a 0a 09 09 09 69 66 20 6e 6f 74 20 72 65 2e 63 :....if not re.c
02c0: 6f 6d 70 69 6c 65 28 27 5e 2f 2e 2a 27 29 2e 6d ompile('^/.*').m
02d0: 61 74 63 68 28 63 6f 6e 66 69 67 5b 73 65 63 74 atch(config[sect
02e0: 69 6f 6e 5d 5b 27 64 69 72 27 5d 29 3a 0a 09 09 ion]['dir']):...
02f0: 09 09 63 6f 6e 66 69 67 5b 73 65 63 74 69 6f 6e ..config[section
0300: 5d 5b 27 64 69 72 27 5d 20 3d 20 63 61 63 68 65 ]['dir'] = cache
0310: 5f 64 69 72 20 2b 20 6f 73 2e 73 65 70 20 2b 20 _dir + os.sep +
0320: 73 65 63 74 69 6f 6e 0a 09 09 09 74 68 69 73 44 section....thisD
0330: 69 72 20 3d 20 72 65 2e 63 6f 6d 70 69 6c 65 28 ir = re.compile(
0340: 27 5e 28 2e 2a 29 2f 24 27 29 2e 6d 61 74 63 68 '^(.*)/$').match
0350: 28 63 6f 6e 66 69 67 5b 73 65 63 74 69 6f 6e 5d (config[section]
0360: 5b 27 64 69 72 27 5d 29 0a 09 09 09 69 66 20 74 ['dir'])....if t
0370: 68 69 73 44 69 72 3a 0a 09 09 09 09 63 6f 6e 66 hisDir:.....conf
0380: 69 67 5b 73 65 63 74 69 6f 6e 5d 5b 27 64 69 72 ig[section]['dir
0390: 27 5d 20 3d 20 74 68 69 73 44 69 72 2e 67 72 6f '] = thisDir.gro
03a0: 75 70 28 31 29 0a 09 09 09 69 66 20 6e 6f 74 20 up(1)....if not
03b0: 72 65 2e 63 6f 6d 70 69 6c 65 28 27 5e 2f 28 2e re.compile('^/(.
03c0: 2a 29 24 27 29 2e 6d 61 74 63 68 28 63 6f 6e 66 *)$').match(conf
03d0: 69 67 5b 73 65 63 74 69 6f 6e 5d 5b 27 64 69 72 ig[section]['dir
03e0: 27 5d 29 3a 0a 09 09 09 09 63 6f 6e 66 69 67 5b ']):.....config[
03f0: 73 65 63 74 69 6f 6e 5d 5b 27 64 69 72 27 5d 20 section]['dir']
0400: 3d 20 63 61 63 68 65 5f 64 69 72 20 2b 20 6f 73 = cache_dir + os
0410: 2e 73 65 70 20 2b 20 63 6f 6e 66 69 67 5b 73 65 .sep + config[se
0420: 63 74 69 6f 6e 5d 5b 27 64 69 72 27 5d 0a 09 09 ction]['dir']...
0430: 65 6c 73 65 3a 0a 09 09 09 63 6f 6e 66 69 67 5b else:....config[
0440: 73 65 63 74 69 6f 6e 5d 5b 27 64 69 72 27 5d 20 section]['dir']
0450: 3d 20 63 61 63 68 65 5f 64 69 72 20 2b 20 6f 73 = cache_dir + os
0460: 2e 73 65 70 20 2b 20 73 65 63 74 69 6f 6e 0a 09 .sep + section..
0470: 09 69 66 20 6e 6f 74 20 27 72 6f 6f 74 27 20 69 .if not 'root' i
0480: 6e 20 63 6f 6e 66 69 67 5b 73 65 63 74 69 6f 6e n config[section
0490: 5d 3a 0a 09 09 09 63 6f 6e 66 69 67 5b 73 65 63 ]:....config[sec
04a0: 74 69 6f 6e 5d 5b 27 72 6f 6f 74 27 5d 20 3d 20 tion]['root'] =
04b0: 73 65 63 74 69 6f 6e 0a 0a 23 61 73 73 65 72 74 section..#assert
04c0: 20 6f 70 74 69 6f 6e 73 2e 70 6f 72 74 20 6f 72 options.port or
04d0: 20 6f 73 2e 61 63 63 65 73 73 28 6f 70 74 69 6f os.access(optio
04e0: 6e 73 2e 6c 6f 67 2c 20 6f 73 2e 52 5f 4f 4b 29 ns.log, os.R_OK)
04f0: 2c 20 27 4c 6f 67 20 66 69 6c 65 20 75 6e 72 65 , 'Log file unre
0500: 61 64 61 62 6c 65 27 0a 0a 63 6f 6e 73 74 5f 64 adable'..const_d
0510: 65 73 63 5f 66 69 65 6c 64 73 20 3d 20 73 65 74 esc_fields = set
0520: 28 5b 27 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 (['Content-Lengt
0530: 68 27 2c 20 27 4c 61 73 74 2d 4d 6f 64 69 66 69 h', 'Last-Modifi
0540: 65 64 27 2c 20 27 50 72 61 67 6d 61 27 5d 29 0a ed', 'Pragma']).
0550: 63 6f 6e 73 74 5f 69 67 6e 6f 72 65 5f 66 69 65 const_ignore_fie
0560: 6c 64 73 20 3d 20 73 65 74 28 5b 0a 09 27 41 63 lds = set([..'Ac
0570: 63 65 70 74 2d 52 61 6e 67 65 73 27 2c 20 27 41 cept-Ranges', 'A
0580: 67 65 27 2c 0a 09 27 43 61 63 68 65 2d 43 6f 6e ge',..'Cache-Con
0590: 74 72 6f 6c 27 2c 20 27 43 6f 6e 6e 65 63 74 69 trol', 'Connecti
05a0: 6f 6e 27 2c 20 27 43 6f 6e 74 65 6e 74 2d 54 79 on', 'Content-Ty
05b0: 70 65 27 2c 0a 09 27 44 61 74 65 27 2c 0a 09 27 pe',..'Date',..'
05c0: 45 78 70 69 72 65 73 27 2c 0a 09 27 52 65 66 65 Expires',..'Refe
05d0: 72 65 72 27 2c 0a 09 27 53 65 72 76 65 72 27 2c rer',..'Server',
05e0: 0a 09 27 56 69 61 27 2c 0a 09 27 58 2d 43 43 43 ..'Via',..'X-CCC
05f0: 27 2c 20 27 58 2d 43 49 44 27 2c 20 27 58 2d 43 ', 'X-CID', 'X-C
0600: 61 63 68 65 27 2c 20 27 58 2d 43 61 63 68 65 2d ache', 'X-Cache-
0610: 4c 6f 6f 6b 75 70 27 2c 20 27 58 2d 4c 69 76 65 Lookup', 'X-Live
0620: 74 6f 6f 6c 27 2c 20 27 58 2d 50 6f 77 65 72 65 tool', 'X-Powere
0630: 64 2d 42 79 27 2c 0a 5d 29 0a 0a 62 6c 6f 63 6b d-By',.])..block
0640: 5f 73 69 7a 65 20 3d 20 38 31 39 32 0a 0a 69 6d _size = 8192..im
0650: 70 6f 72 74 20 62 73 64 64 62 33 2e 64 62 73 68 port bsddb3.dbsh
0660: 65 6c 76 65 2c 20 63 6f 70 79 2c 20 64 61 74 65 elve, copy, date
0670: 74 69 6d 65 2c 20 68 74 74 70 2e 73 65 72 76 65 time, http.serve
0680: 72 2c 20 73 70 61 63 65 6d 61 70 2c 20 75 72 6c r, spacemap, url
0690: 6c 69 62 2e 72 65 71 75 65 73 74 2c 20 75 72 6c lib.request, url
06a0: 6c 69 62 2e 65 72 72 6f 72 0a 0a 63 6c 61 73 73 lib.error..class
06b0: 20 4d 79 52 65 71 75 65 73 74 48 61 6e 64 6c 65 MyRequestHandle
06c0: 72 28 68 74 74 70 2e 73 65 72 76 65 72 2e 42 61 r(http.server.Ba
06d0: 73 65 48 54 54 50 52 65 71 75 65 73 74 48 61 6e seHTTPRequestHan
06e0: 64 6c 65 72 29 3a 0a 09 64 65 66 20 5f 5f 70 72 dler):..def __pr
06f0: 6f 63 65 73 73 28 73 65 6c 66 29 3a 0a 09 09 23 ocess(self):...#
0700: 20 72 65 6c 6f 61 64 20 6d 65 61 6e 73 20 66 69 reload means fi
0710: 6c 65 20 6e 65 65 64 73 20 74 6f 20 62 65 20 72 le needs to be r
0720: 65 6c 6f 61 64 65 64 20 74 6f 20 73 65 72 76 65 eloaded to serve
0730: 20 72 65 71 75 65 73 74 0a 09 09 72 65 6c 6f 61 request...reloa
0740: 64 20 3d 20 46 61 6c 73 65 0a 09 09 23 20 72 65 d = False...# re
0750: 63 68 65 63 6b 20 6d 65 61 6e 73 20 66 69 6c 65 check means file
0760: 20 6e 65 65 64 73 20 74 6f 20 62 65 20 63 68 65 needs to be che
0770: 63 6b 65 64 2c 20 74 68 69 73 20 61 6c 73 6f 20 cked, this also
0780: 6d 65 61 6e 73 20 74 68 61 74 20 69 66 20 66 69 means that if fi
0790: 6c 65 20 68 61 76 20 62 65 65 6e 20 6d 6f 64 69 le hav been modi
07a0: 66 69 65 64 20 77 65 20 63 61 6e 20 73 65 72 76 fied we can serv
07b0: 65 20 6f 6c 64 65 72 20 63 6f 70 79 0a 09 09 72 e older copy...r
07c0: 65 63 68 65 63 6b 20 3d 20 46 61 6c 73 65 0a 09 echeck = False..
07d0: 09 23 20 66 69 6c 65 5f 73 74 61 74 20 6d 65 61 .# file_stat mea
07e0: 6e 73 20 66 69 6c 65 20 64 65 66 69 6e 69 74 65 ns file definite
07f0: 6c 79 20 65 78 69 73 74 73 0a 09 09 66 69 6c 65 ly exists...file
0800: 5f 73 74 61 74 20 3d 20 4e 6f 6e 65 0a 09 09 23 _stat = None...#
0810: 20 72 65 71 75 65 73 74 65 64 5f 72 61 6e 67 65 requested_range
0820: 73 20 68 6f 6c 64 73 20 64 61 74 61 20 61 62 6f s holds data abo
0830: 75 74 20 61 6e 79 20 72 61 6e 67 65 20 72 65 71 ut any range req
0840: 75 65 73 74 65 64 0a 09 09 72 65 71 75 65 73 74 uested...request
0850: 65 64 5f 72 61 6e 67 65 73 20 3d 20 4e 6f 6e 65 ed_ranges = None
0860: 0a 09 09 23 20 72 65 63 6f 72 64 73 20 68 6f 6c ...# records hol
0870: 64 73 20 64 61 74 61 20 66 72 6f 6d 20 69 6e 64 ds data from ind
0880: 65 78 20 6c 6f 63 61 6c 6c 79 2c 20 73 68 6f 75 ex locally, shou
0890: 6c 64 20 62 65 20 77 72 69 74 74 65 6e 20 62 61 ld be written ba
08a0: 63 6b 20 75 70 6f 6e 20 73 75 63 63 65 73 73 66 ck upon successf
08b0: 75 6c 6c 20 63 6f 6d 70 6c 65 74 69 6f 6e 0a 09 ull completion..
08c0: 09 72 65 63 6f 72 64 20 3d 20 4e 6f 6e 65 0a 0a .record = None..
08d0: 09 09 6d 79 50 61 74 68 20 3d 20 72 65 2e 63 6f ..myPath = re.co
08e0: 6d 70 69 6c 65 28 27 5e 28 2e 2a 3f 29 28 5c 3f mpile('^(.*?)(\?
08f0: 2e 2a 29 24 27 29 2e 6d 61 74 63 68 28 73 65 6c .*)$').match(sel
0900: 66 2e 70 61 74 68 29 0a 09 09 69 66 20 6d 79 50 f.path)...if myP
0910: 61 74 68 3a 0a 09 09 09 6d 79 5f 70 61 74 68 20 ath:....my_path
0920: 3d 20 6d 79 50 61 74 68 2e 67 72 6f 75 70 28 31 = myPath.group(1
0930: 29 0a 09 09 65 6c 73 65 3a 0a 09 09 09 6d 79 5f )...else:....my_
0940: 70 61 74 68 20 3d 20 73 65 6c 66 2e 70 61 74 68 path = self.path
0950: 0a 0a 09 09 69 66 20 6e 6f 74 20 63 6f 6e 66 69 ....if not confi
0960: 67 2e 68 61 73 5f 73 65 63 74 69 6f 6e 28 73 65 g.has_section(se
0970: 6c 66 2e 68 65 61 64 65 72 73 5b 27 48 6f 73 74 lf.headers['Host
0980: 27 5d 29 3a 0a 09 09 09 63 6f 6e 66 69 67 2e 61 ']):....config.a
0990: 64 64 5f 73 65 63 74 69 6f 6e 28 73 65 6c 66 2e dd_section(self.
09a0: 68 65 61 64 65 72 73 5b 27 48 6f 73 74 27 5d 29 headers['Host'])
09b0: 0a 09 09 09 63 6f 6e 66 69 67 5b 73 65 6c 66 2e ....config[self.
09c0: 68 65 61 64 65 72 73 5b 27 48 6f 73 74 27 5d 5d headers['Host']]
09d0: 5b 27 72 6f 6f 74 27 5d 20 3d 20 73 65 6c 66 2e ['root'] = self.
09e0: 68 65 61 64 65 72 73 5b 27 48 6f 73 74 27 5d 0a headers['Host'].
09f0: 09 09 09 63 6f 6e 66 69 67 5b 73 65 6c 66 2e 68 ...config[self.h
0a00: 65 61 64 65 72 73 5b 27 48 6f 73 74 27 5d 5d 5b eaders['Host']][
0a10: 27 64 69 72 27 5d 20 3d 20 63 61 63 68 65 5f 64 'dir'] = cache_d
0a20: 69 72 20 2b 20 6f 73 2e 73 65 70 20 2b 20 73 65 ir + os.sep + se
0a30: 6c 66 2e 68 65 61 64 65 72 73 5b 27 48 6f 73 74 lf.headers['Host
0a40: 27 5d 0a 09 09 63 6f 6e 66 69 67 5f 68 6f 73 74 ']...config_host
0a50: 20 3d 20 63 6f 6e 66 69 67 5b 73 65 6c 66 2e 68 = config[self.h
0a60: 65 61 64 65 72 73 5b 27 48 6f 73 74 27 5d 5d 0a eaders['Host']].
0a70: 0a 09 09 69 66 20 63 6f 6e 66 69 67 5f 68 6f 73 ...if config_hos
0a80: 74 5b 27 73 75 62 27 5d 20 21 3d 20 4e 6f 6e 65 t['sub'] != None
0a90: 20 61 6e 64 20 63 6f 6e 66 69 67 5f 68 6f 73 74 and config_host
0aa0: 5b 27 73 74 72 69 70 27 5d 20 21 3d 20 4e 6f 6e ['strip'] != Non
0ab0: 65 20 61 6e 64 20 6c 65 6e 28 63 6f 6e 66 69 67 e and len(config
0ac0: 5f 68 6f 73 74 5b 27 73 74 72 69 70 27 5d 29 20 _host['strip'])
0ad0: 3e 20 30 3a 0a 09 09 09 73 74 72 69 6e 67 20 3d > 0:....string =
0ae0: 20 72 65 2e 63 6f 6d 70 69 6c 65 28 63 6f 6e 66 re.compile(conf
0af0: 69 67 5f 68 6f 73 74 5b 27 73 74 72 69 70 27 5d ig_host['strip']
0b00: 29 2e 73 75 62 28 63 6f 6e 66 69 67 5f 68 6f 73 ).sub(config_hos
0b10: 74 5b 27 73 75 62 27 5d 2c 20 6d 79 5f 70 61 74 t['sub'], my_pat
0b20: 68 29 0a 09 09 09 6d 79 5f 70 61 74 68 20 3d 20 h)....my_path =
0b30: 73 74 72 69 6e 67 0a 0a 09 09 6d 79 5f 70 61 74 string....my_pat
0b40: 68 5f 62 20 3d 20 6d 79 5f 70 61 74 68 2e 65 6e h_b = my_path.en
0b50: 63 6f 64 65 28 27 75 74 66 2d 38 27 29 0a 09 09 code('utf-8')...
0b60: 69 6e 66 6f 20 3d 20 27 43 68 65 63 6b 69 6e 67 info = 'Checking
0b70: 20 66 69 6c 65 3a 20 27 20 2b 20 6d 79 5f 70 61 file: ' + my_pa
0b80: 74 68 0a 0a 09 09 69 66 20 6e 6f 74 20 6f 73 2e th....if not os.
0b90: 61 63 63 65 73 73 28 63 6f 6e 66 69 67 5f 68 6f access(config_ho
0ba0: 73 74 5b 27 64 69 72 27 5d 2c 20 6f 73 2e 58 5f st['dir'], os.X_
0bb0: 4f 4b 29 3a 0a 09 09 09 6f 73 2e 6d 6b 64 69 72 OK):....os.mkdir
0bc0: 28 63 6f 6e 66 69 67 5f 68 6f 73 74 5b 27 64 69 (config_host['di
0bd0: 72 27 5d 29 0a 09 09 23 20 74 68 69 73 20 69 73 r'])...# this is
0be0: 20 66 69 6c 65 20 69 6e 64 65 78 20 2d 20 65 76 file index - ev
0bf0: 65 72 79 74 68 69 6e 67 20 69 73 20 73 74 6f 72 erything is stor
0c00: 65 64 20 69 6e 20 74 68 69 73 20 66 69 6c 65 0a ed in this file.
0c10: 09 09 23 20 5f 70 61 72 74 73 20 2d 20 6c 69 73 ..# _parts - lis
0c20: 74 20 6f 66 20 73 74 6f 72 65 64 20 70 61 72 74 t of stored part
0c30: 73 20 6f 66 20 66 69 6c 65 0a 09 09 23 20 5f 74 s of file...# _t
0c40: 69 6d 65 20 2d 20 6c 61 73 74 20 74 69 6d 65 20 ime - last time
0c50: 74 68 65 20 66 69 6c 65 20 77 61 73 20 63 68 65 the file was che
0c60: 63 6b 65 64 0a 09 09 23 20 65 76 65 72 79 74 68 cked...# everyth
0c70: 69 6e 67 20 65 6c 73 65 20 69 73 20 6a 75 73 74 ing else is just
0c80: 20 74 68 65 20 68 65 61 64 65 72 73 0a 09 09 69 the headers...i
0c90: 6e 64 65 78 20 3d 20 62 73 64 64 62 33 2e 64 62 ndex = bsddb3.db
0ca0: 73 68 65 6c 76 65 2e 6f 70 65 6e 28 63 6f 6e 66 shelve.open(conf
0cb0: 69 67 5f 68 6f 73 74 5b 27 64 69 72 27 5d 20 2b ig_host['dir'] +
0cc0: 20 6f 73 2e 73 65 70 20 2b 20 27 2e 69 6e 64 65 os.sep + '.inde
0cd0: 78 27 29 0a 0a 09 09 64 65 73 63 5f 66 69 65 6c x')....desc_fiel
0ce0: 64 73 20 3d 20 63 6f 6e 73 74 5f 64 65 73 63 5f ds = const_desc_
0cf0: 66 69 65 6c 64 73 2e 63 6f 70 79 28 29 0a 09 09 fields.copy()...
0d00: 69 67 6e 6f 72 65 5f 66 69 65 6c 64 73 20 3d 20 ignore_fields =
0d10: 63 6f 6e 73 74 5f 69 67 6e 6f 72 65 5f 66 69 65 const_ignore_fie
0d20: 6c 64 73 2e 63 6f 70 79 28 29 0a 09 09 69 66 20 lds.copy()...if
0d30: 63 6f 6e 66 69 67 5f 68 6f 73 74 5b 27 6e 6f 65 config_host['noe
0d40: 74 61 67 27 5d 20 3d 3d 20 27 6e 6f 27 3a 0a 09 tag'] == 'no':..
0d50: 09 09 64 65 73 63 5f 66 69 65 6c 64 73 2e 61 64 ..desc_fields.ad
0d60: 64 28 27 45 54 61 67 27 29 0a 09 09 65 6c 73 65 d('ETag')...else
0d70: 3a 0a 09 09 09 69 67 6e 6f 72 65 5f 66 69 65 6c :....ignore_fiel
0d80: 64 73 2e 61 64 64 28 27 45 54 61 67 27 29 0a 0a ds.add('ETag')..
0d90: 09 09 70 72 6f 78 79 5f 69 67 6e 6f 72 65 64 20 ..proxy_ignored
0da0: 3d 20 73 65 74 28 5b 0a 09 09 09 27 41 63 63 65 = set([....'Acce
0db0: 70 74 27 2c 20 27 41 63 63 65 70 74 2d 43 68 61 pt', 'Accept-Cha
0dc0: 72 73 65 74 27 2c 20 27 41 63 63 65 70 74 2d 45 rset', 'Accept-E
0dd0: 6e 63 6f 64 69 6e 67 27 2c 20 27 41 63 63 65 70 ncoding', 'Accep
0de0: 74 2d 4c 61 6e 67 75 61 67 65 27 2c 0a 09 09 09 t-Language',....
0df0: 27 43 61 63 68 65 2d 43 6f 6e 74 72 6f 6c 27 2c 'Cache-Control',
0e00: 20 27 43 6f 6e 6e 65 63 74 69 6f 6e 27 2c 20 27 'Connection', '
0e10: 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 27 2c Content-Length',
0e20: 20 27 43 6f 6f 6b 69 65 27 2c 0a 09 09 09 27 48 'Cookie',....'H
0e30: 6f 73 74 27 2c 0a 09 09 09 27 49 66 2d 4d 6f 64 ost',....'If-Mod
0e40: 69 66 69 65 64 2d 53 69 6e 63 65 27 2c 20 27 49 ified-Since', 'I
0e50: 66 2d 4e 6f 6e 65 2d 4d 61 74 63 68 27 2c 20 27 f-None-Match', '
0e60: 49 66 2d 55 6e 6d 6f 64 69 66 69 65 64 2d 53 69 If-Unmodified-Si
0e70: 6e 63 65 27 2c 0a 09 09 09 27 52 65 66 65 72 65 nce',....'Refere
0e80: 72 27 2c 0a 09 09 09 27 55 41 2d 43 50 55 27 2c r',....'UA-CPU',
0e90: 20 27 55 73 65 72 2d 41 67 65 6e 74 27 2c 0a 09 'User-Agent',..
0ea0: 09 09 27 56 69 61 27 2c 0a 09 09 09 27 58 2d 46 ..'Via',....'X-F
0eb0: 6f 72 77 61 72 64 65 64 2d 46 6f 72 27 2c 20 27 orwarded-For', '
0ec0: 58 2d 4c 61 73 74 2d 48 52 27 2c 20 27 58 2d 4c X-Last-HR', 'X-L
0ed0: 61 73 74 2d 48 54 54 50 2d 53 74 61 74 75 73 2d ast-HTTP-Status-
0ee0: 43 6f 64 65 27 2c 20 27 58 2d 4f 6c 64 2d 55 49 Code', 'X-Old-UI
0ef0: 44 27 2c 20 27 58 2d 52 65 6d 6f 76 65 64 27 2c D', 'X-Removed',
0f00: 20 27 58 2d 52 65 61 6c 2d 49 50 27 2c 20 27 58 'X-Real-IP', 'X
0f10: 2d 52 65 74 72 79 2d 43 6f 75 6e 74 27 2c 0a 09 -Retry-Count',..
0f20: 09 5d 29 0a 0a 09 09 70 72 69 6e 74 28 27 3d 3d .])....print('==
0f30: 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 5b 20 7b =============[ {
0f40: 7d 20 72 65 71 75 65 73 74 20 5d 3d 3d 3d 27 2e } request ]==='.
0f50: 66 6f 72 6d 61 74 28 73 65 6c 66 2e 63 6f 6d 6d format(self.comm
0f60: 61 6e 64 29 29 0a 0a 09 09 66 6f 72 20 68 65 61 and))....for hea
0f70: 64 65 72 20 69 6e 20 73 65 6c 66 2e 68 65 61 64 der in self.head
0f80: 65 72 73 3a 0a 09 09 09 69 66 20 68 65 61 64 65 ers:....if heade
0f90: 72 20 69 6e 20 70 72 6f 78 79 5f 69 67 6e 6f 72 r in proxy_ignor
0fa0: 65 64 3a 0a 09 09 09 09 70 61 73 73 0a 09 09 09 ed:.....pass....
0fb0: 65 6c 69 66 20 68 65 61 64 65 72 20 69 6e 20 28 elif header in (
0fc0: 27 52 61 6e 67 65 27 29 3a 0a 09 09 09 09 69 73 'Range'):.....is
0fd0: 52 61 6e 67 65 20 3d 20 72 65 2e 63 6f 6d 70 69 Range = re.compi
0fe0: 6c 65 28 27 62 79 74 65 73 3d 28 5c 64 2b 29 2d le('bytes=(\d+)-
0ff0: 28 5c 64 2b 29 27 29 2e 6d 61 74 63 68 28 73 65 (\d+)').match(se
1000: 6c 66 2e 68 65 61 64 65 72 73 5b 68 65 61 64 65 lf.headers[heade
1010: 72 5d 29 0a 09 09 09 09 69 66 20 69 73 52 61 6e r]).....if isRan
1020: 67 65 3a 0a 09 09 09 09 09 72 65 71 75 65 73 74 ge:......request
1030: 65 64 5f 72 61 6e 67 65 73 20 3d 20 73 70 61 63 ed_ranges = spac
1040: 65 6d 61 70 2e 53 70 61 63 65 4d 61 70 28 7b 69 emap.SpaceMap({i
1050: 6e 74 28 69 73 52 61 6e 67 65 2e 67 72 6f 75 70 nt(isRange.group
1060: 28 31 29 29 3a 20 69 6e 74 28 69 73 52 61 6e 67 (1)): int(isRang
1070: 65 2e 67 72 6f 75 70 28 32 29 29 20 2b 20 31 7d e.group(2)) + 1}
1080: 29 0a 09 09 09 09 65 6c 73 65 3a 0a 09 09 09 09 ).....else:.....
1090: 09 72 65 74 75 72 6e 28 29 0a 09 09 09 65 6c 69 .return()....eli
10a0: 66 20 68 65 61 64 65 72 20 69 6e 20 28 27 50 72 f header in ('Pr
10b0: 61 67 6d 61 27 29 3a 0a 09 09 09 09 69 66 20 6d agma'):.....if m
10c0: 79 5f 70 61 74 68 5f 62 20 69 6e 20 69 6e 64 65 y_path_b in inde
10d0: 78 3a 0a 09 09 09 09 09 69 6e 64 65 78 5b 6d 79 x:......index[my
10e0: 5f 70 61 74 68 5f 62 5d 5b 68 65 61 64 65 72 5d _path_b][header]
10f0: 20 3d 20 73 65 6c 66 2e 68 65 61 64 65 72 73 5b = self.headers[
1100: 68 65 61 64 65 72 5d 0a 09 09 09 65 6c 73 65 3a header]....else:
1110: 0a 09 09 09 09 70 72 69 6e 74 28 27 55 6e 6b 6e .....print('Unkn
1120: 6f 77 6e 20 68 65 61 64 65 72 20 2d 20 27 2c 20 own header - ',
1130: 68 65 61 64 65 72 2c 20 27 3a 20 27 2c 20 73 65 header, ': ', se
1140: 6c 66 2e 68 65 61 64 65 72 73 5b 68 65 61 64 65 lf.headers[heade
1150: 72 5d 2c 20 73 65 70 3d 27 27 29 0a 09 09 09 09 r], sep='').....
1160: 72 65 74 75 72 6e 28 29 0a 09 09 09 70 72 69 6e return()....prin
1170: 74 28 68 65 61 64 65 72 2c 20 73 65 6c 66 2e 68 t(header, self.h
1180: 65 61 64 65 72 73 5b 68 65 61 64 65 72 5d 29 0a eaders[header]).
1190: 0a 09 09 23 20 63 72 65 61 74 69 6e 67 20 66 69 ...# creating fi
11a0: 6c 65 20 6e 61 6d 65 20 66 72 6f 6d 20 6d 79 5f le name from my_
11b0: 70 61 74 68 0a 09 09 66 69 6c 65 5f 6e 61 6d 65 path...file_name
11c0: 20 3d 20 63 6f 6e 66 69 67 5f 68 6f 73 74 5b 27 = config_host['
11d0: 64 69 72 27 5d 20 2b 20 6f 73 2e 73 65 70 20 2b dir'] + os.sep +
11e0: 20 72 65 2e 63 6f 6d 70 69 6c 65 28 27 25 32 30 re.compile('%20
11f0: 27 29 2e 73 75 62 28 27 20 27 2c 20 6d 79 5f 70 ').sub(' ', my_p
1200: 61 74 68 29 0a 09 09 23 20 70 61 72 74 69 61 6c ath)...# partial
1210: 20 66 69 6c 65 20 6f 72 20 75 6e 66 69 6e 69 73 file or unfinis
1220: 68 65 64 20 64 6f 77 6e 6c 6f 61 64 0a 09 09 74 hed download...t
1230: 65 6d 70 5f 6e 61 6d 65 20 3d 20 63 6f 6e 66 69 emp_name = confi
1240: 67 5f 68 6f 73 74 5b 27 64 69 72 27 5d 20 2b 20 g_host['dir'] +
1250: 6f 73 2e 73 65 70 20 2b 20 27 2e 70 61 72 74 73 os.sep + '.parts
1260: 27 20 2b 20 72 65 2e 63 6f 6d 70 69 6c 65 28 27 ' + re.compile('
1270: 25 32 30 27 29 2e 73 75 62 28 27 20 27 2c 20 6d %20').sub(' ', m
1280: 79 5f 70 61 74 68 29 0a 0a 09 09 23 20 63 72 65 y_path)....# cre
1290: 61 74 69 6e 67 20 65 6d 70 74 79 20 70 6c 61 63 ating empty plac
12a0: 65 68 6f 6c 64 65 72 20 69 6e 20 69 6e 64 65 78 eholder in index
12b0: 0a 09 09 23 20 69 66 20 74 68 65 72 65 27 73 20 ...# if there's
12c0: 6e 6f 20 73 70 61 63 65 20 6d 61 70 20 61 6e 64 no space map and
12d0: 20 74 68 65 72 65 27 73 20 6e 6f 20 66 69 6c 65 there's no file
12e0: 20 69 6e 20 72 65 61 6c 20 64 69 72 65 63 74 6f in real directo
12f0: 72 79 20 2d 20 77 65 20 68 61 76 65 20 6e 6f 20 ry - we have no
1300: 66 69 6c 65 0a 09 09 23 20 69 66 20 74 68 65 72 file...# if ther
1310: 65 27 73 20 61 6e 20 65 6d 70 74 79 20 73 70 61 e's an empty spa
1320: 63 65 20 6d 61 70 20 2d 20 66 69 6c 65 20 69 73 ce map - file is
1330: 20 66 75 6c 6c 0a 09 09 23 20 73 70 61 63 65 20 full...# space
1340: 6d 61 70 20 67 65 6e 65 72 61 6c 6c 79 20 63 6f map generally co
1350: 76 65 72 73 20 65 76 65 72 79 20 62 69 74 20 6f vers every bit o
1360: 66 20 66 69 6c 65 20 77 65 20 64 6f 6e 27 74 20 f file we don't
1370: 70 6f 73 65 73 73 20 63 75 72 72 65 6e 74 6c 79 posess currently
1380: 0a 09 09 69 66 20 6e 6f 74 20 6d 79 5f 70 61 74 ...if not my_pat
1390: 68 5f 62 20 69 6e 20 69 6e 64 65 78 3a 0a 09 09 h_b in index:...
13a0: 09 69 6e 66 6f 20 2b 3d 20 27 5c 6e 54 68 69 73 .info += '\nThis
13b0: 20 6f 6e 65 20 69 73 20 6e 65 77 2e 27 0a 09 09 one is new.'...
13c0: 09 72 65 6c 6f 61 64 20 3d 20 54 72 75 65 0a 09 .reload = True..
13d0: 09 09 72 65 63 6f 72 64 20 3d 20 7b 7d 0a 09 09 ..record = {}...
13e0: 65 6c 73 65 3a 0a 09 09 09 23 20 66 6f 72 63 69 else:....# forci
13f0: 62 6c 79 20 63 68 65 63 6b 69 6e 67 20 66 69 6c bly checking fil
1400: 65 20 69 66 20 6e 6f 20 66 69 6c 65 20 70 72 65 e if no file pre
1410: 73 65 6e 74 0a 09 09 09 72 65 63 6f 72 64 20 3d sent....record =
1420: 20 69 6e 64 65 78 5b 6d 79 5f 70 61 74 68 5f 62 index[my_path_b
1430: 5d 0a 09 09 09 69 66 20 6f 73 2e 61 63 63 65 73 ]....if os.acces
1440: 73 28 66 69 6c 65 5f 6e 61 6d 65 2c 20 6f 73 2e s(file_name, os.
1450: 52 5f 4f 4b 29 3a 0a 09 09 09 09 69 6e 66 6f 20 R_OK):.....info
1460: 2b 3d 20 27 5c 6e 46 75 6c 6c 20 66 69 6c 65 20 += '\nFull file
1470: 66 6f 75 6e 64 2e 27 0a 09 09 09 09 66 69 6c 65 found.'.....file
1480: 5f 73 74 61 74 20 3d 20 6f 73 2e 73 74 61 74 28 _stat = os.stat(
1490: 66 69 6c 65 5f 6e 61 6d 65 29 0a 09 09 09 65 6c file_name)....el
14a0: 69 66 20 27 5f 70 61 72 74 73 27 20 69 6e 20 69 if '_parts' in i
14b0: 6e 64 65 78 5b 6d 79 5f 70 61 74 68 5f 62 5d 20 ndex[my_path_b]
14c0: 61 6e 64 20 6f 73 2e 61 63 63 65 73 73 28 74 65 and os.access(te
14d0: 6d 70 5f 6e 61 6d 65 2c 20 6f 73 2e 52 5f 4f 4b mp_name, os.R_OK
14e0: 29 3a 0a 09 09 09 09 69 6e 66 6f 20 2b 3d 20 27 ):.....info += '
14f0: 5c 6e 50 61 72 74 69 61 6c 20 66 69 6c 65 20 66 \nPartial file f
1500: 6f 75 6e 64 2e 27 0a 09 09 09 09 66 69 6c 65 5f ound.'.....file_
1510: 73 74 61 74 20 3d 20 6f 73 2e 73 74 61 74 28 74 stat = os.stat(t
1520: 65 6d 70 5f 6e 61 6d 65 29 0a 09 09 09 09 72 65 emp_name).....re
1530: 63 68 65 63 6b 20 3d 20 54 72 75 65 0a 09 09 09 check = True....
1540: 65 6c 73 65 3a 0a 09 09 09 09 69 6e 66 6f 20 2b else:.....info +
1550: 3d 20 27 5c 6e 46 69 6c 65 20 6e 6f 74 20 66 6f = '\nFile not fo
1560: 75 6e 64 20 6f 72 20 69 6e 61 63 63 65 73 73 69 und or inaccessi
1570: 62 6c 65 2e 27 0a 09 09 09 09 72 65 63 6f 72 64 ble.'.....record
1580: 5b 27 5f 70 61 72 74 73 27 5d 20 3d 20 4e 6f 6e ['_parts'] = Non
1590: 65 0a 09 09 09 09 72 65 6c 6f 61 64 20 3d 20 54 e.....reload = T
15a0: 72 75 65 0a 0a 09 09 69 66 20 6e 6f 74 20 27 5f rue....if not '_
15b0: 70 61 72 74 73 27 20 69 6e 20 72 65 63 6f 72 64 parts' in record
15c0: 3a 0a 09 09 09 72 65 63 6f 72 64 5b 27 5f 70 61 :....record['_pa
15d0: 72 74 73 27 5d 20 3d 20 4e 6f 6e 65 0a 0a 09 09 rts'] = None....
15e0: 69 66 20 72 65 63 6f 72 64 5b 27 5f 70 61 72 74 if record['_part
15f0: 73 27 5d 20 3d 3d 20 4e 6f 6e 65 3a 0a 09 09 09 s'] == None:....
1600: 72 65 63 68 65 63 6b 20 3d 20 54 72 75 65 0a 0a recheck = True..
1610: 09 09 23 20 66 6f 72 63 69 62 6c 79 20 63 68 65 ..# forcibly che
1620: 63 6b 69 6e 67 20 66 69 6c 65 20 69 66 20 66 69 cking file if fi
1630: 6c 65 20 73 69 7a 65 20 64 6f 65 73 6e 27 74 20 le size doesn't
1640: 6d 61 74 63 68 20 77 69 74 68 20 69 6e 64 65 78 match with index
1650: 20 64 61 74 61 0a 09 09 69 66 20 6e 6f 74 20 72 data...if not r
1660: 65 6c 6f 61 64 3a 0a 09 09 09 69 66 20 27 5f 70 eload:....if '_p
1670: 61 72 74 73 27 20 69 6e 20 72 65 63 6f 72 64 20 arts' in record
1680: 61 6e 64 20 72 65 63 6f 72 64 5b 27 5f 70 61 72 and record['_par
1690: 74 73 27 5d 20 3d 3d 20 73 70 61 63 65 6d 61 70 ts'] == spacemap
16a0: 2e 53 70 61 63 65 4d 61 70 28 29 3a 0a 09 09 09 .SpaceMap():....
16b0: 09 69 66 20 27 63 6f 6e 74 65 6e 74 2d 6c 65 6e .if 'content-len
16c0: 67 74 68 27 20 69 6e 20 72 65 63 6f 72 64 20 61 gth' in record a
16d0: 6e 64 20 66 69 6c 65 5f 73 74 61 74 20 61 6e 64 nd file_stat and
16e0: 20 66 69 6c 65 5f 73 74 61 74 2e 73 74 5f 73 69 file_stat.st_si
16f0: 7a 65 20 21 3d 20 69 6e 74 28 72 65 63 6f 72 64 ze != int(record
1700: 5b 27 63 6f 6e 74 65 6e 74 2d 6c 65 6e 67 74 68 ['content-length
1710: 27 5d 29 3a 0a 09 09 09 09 09 69 6e 66 6f 20 2b ']):......info +
1720: 3d 20 27 5c 6e 46 69 6c 65 20 73 69 7a 65 20 69 = '\nFile size i
1730: 73 20 7b 7d 20 61 6e 64 20 73 74 6f 72 65 64 20 s {} and stored
1740: 66 69 6c 65 20 73 69 7a 65 20 69 73 20 7b 7d 2e file size is {}.
1750: 27 2e 66 6f 72 6d 61 74 28 66 69 6c 65 5f 73 74 '.format(file_st
1760: 61 74 2e 73 74 5f 73 69 7a 65 2c 20 72 65 63 6f at.st_size, reco
1770: 72 64 5b 27 63 6f 6e 74 65 6e 74 2d 6c 65 6e 67 rd['content-leng
1780: 74 68 27 5d 29 0a 09 09 09 09 09 72 65 63 6f 72 th'])......recor
1790: 64 5b 27 5f 70 61 72 74 73 27 5d 20 3d 20 4e 6f d['_parts'] = No
17a0: 6e 65 0a 09 09 09 09 09 72 65 6c 6f 61 64 20 3d ne......reload =
17b0: 20 54 72 75 65 0a 0a 09 09 23 20 66 6f 72 63 69 True....# forci
17c0: 62 6c 79 20 63 68 65 63 6b 69 6e 67 20 66 69 6c bly checking fil
17d0: 65 20 69 66 20 69 6e 64 65 78 20 68 6f 6c 64 73 e if index holds
17e0: 20 50 72 61 67 6d 61 20 68 65 61 64 65 72 0a 09 Pragma header..
17f0: 09 69 66 20 6e 6f 74 20 72 65 6c 6f 61 64 20 61 .if not reload a
1800: 6e 64 20 27 70 72 61 67 6d 61 27 20 69 6e 20 72 nd 'pragma' in r
1810: 65 63 6f 72 64 20 61 6e 64 20 72 65 63 6f 72 64 ecord and record
1820: 5b 27 70 72 61 67 6d 61 27 5d 20 3d 3d 20 27 6e ['pragma'] == 'n
1830: 6f 2d 63 61 63 68 65 27 3a 0a 09 09 09 69 6e 66 o-cache':....inf
1840: 6f 20 2b 3d 27 5c 6e 50 72 61 67 6d 61 20 6f 6e o +='\nPragma on
1850: 3a 20 72 65 63 68 65 63 6b 20 69 6d 6d 69 6e 65 : recheck immine
1860: 6e 74 2e 27 0a 09 09 09 72 65 63 68 65 63 6b 20 nt.'....recheck
1870: 3d 20 54 72 75 65 0a 0a 09 09 23 20 73 6b 69 70 = True....# skip
1880: 70 69 6e 67 20 66 69 6c 65 20 70 72 6f 63 65 73 ping file proces
1890: 73 69 6e 67 20 69 66 20 74 68 65 72 65 27 73 20 sing if there's
18a0: 6e 6f 20 6e 65 65 64 20 74 6f 20 72 65 63 68 65 no need to reche
18b0: 63 6b 20 69 74 20 61 6e 64 20 77 65 20 68 61 76 ck it and we hav
18c0: 65 20 63 68 65 63 6b 65 64 20 69 74 20 61 74 20 e checked it at
18d0: 6c 65 61 73 74 20 34 20 68 6f 75 72 73 20 61 67 least 4 hours ag
18e0: 6f 0a 09 09 69 66 20 6e 6f 74 20 72 65 63 68 65 o...if not reche
18f0: 63 6b 20 61 6e 64 20 6e 6f 74 20 72 65 6c 6f 61 ck and not reloa
1900: 64 20 61 6e 64 20 27 5f 74 69 6d 65 27 20 69 6e d and '_time' in
1910: 20 72 65 63 6f 72 64 20 61 6e 64 20 28 72 65 63 record and (rec
1920: 6f 72 64 5b 27 5f 74 69 6d 65 27 5d 20 2d 20 64 ord['_time'] - d
1930: 61 74 65 74 69 6d 65 2e 64 61 74 65 74 69 6d 65 atetime.datetime
1940: 2e 6e 6f 77 28 29 20 2b 20 64 61 74 65 74 69 6d .now() + datetim
1950: 65 2e 74 69 6d 65 64 65 6c 74 61 28 68 6f 75 72 e.timedelta(hour
1960: 73 20 3d 20 34 29 29 2e 64 61 79 73 20 3c 20 30 s = 4)).days < 0
1970: 3a 0a 09 09 09 69 6e 66 6f 20 2b 3d 20 27 5c 6e :....info += '\n
1980: 46 69 6c 65 20 69 73 20 6f 6c 64 20 2d 20 72 65 File is old - re
1990: 63 68 65 63 6b 69 6e 67 2e 27 0a 09 09 09 72 65 checking.'....re
19a0: 63 68 65 63 6b 20 3d 20 54 72 75 65 0a 0a 09 09 check = True....
19b0: 70 72 69 6e 74 28 69 6e 66 6f 29 0a 09 09 69 66 print(info)...if
19c0: 20 72 65 6c 6f 61 64 20 6f 72 20 72 65 63 68 65 reload or reche
19d0: 63 6b 3a 0a 0a 09 09 09 74 72 79 3a 0a 09 09 09 ck:.....try:....
19e0: 09 72 65 71 75 65 73 74 20 3d 20 63 6f 6e 66 69 .request = confi
19f0: 67 5f 68 6f 73 74 5b 27 70 72 6f 74 6f 27 5d 20 g_host['proto']
1a00: 2b 20 27 3a 2f 2f 27 20 2b 20 63 6f 6e 66 69 67 + '://' + config
1a10: 5f 68 6f 73 74 5b 27 72 6f 6f 74 27 5d 20 2b 20 _host['root'] +
1a20: 73 65 6c 66 2e 70 61 74 68 0a 09 09 09 09 6d 79 self.path.....my
1a30: 5f 68 65 61 64 65 72 73 20 3d 20 7b 7d 0a 09 09 _headers = {}...
1a40: 09 09 66 6f 72 20 68 65 61 64 65 72 20 69 6e 20 ..for header in
1a50: 28 27 41 63 63 65 70 74 27 2c 20 27 43 61 63 68 ('Accept', 'Cach
1a60: 65 2d 43 6f 6e 74 72 6f 6c 27 2c 20 27 43 6f 6f e-Control', 'Coo
1a70: 6b 69 65 27 2c 20 27 52 65 66 65 72 65 72 27 2c kie', 'Referer',
1a80: 20 27 55 73 65 72 2d 41 67 65 6e 74 27 29 3a 0a 'User-Agent'):.
1a90: 09 09 09 09 09 69 66 20 68 65 61 64 65 72 20 69 .....if header i
1aa0: 6e 20 73 65 6c 66 2e 68 65 61 64 65 72 73 3a 0a n self.headers:.
1ab0: 09 09 09 09 09 09 6d 79 5f 68 65 61 64 65 72 73 ......my_headers
1ac0: 5b 68 65 61 64 65 72 5d 20 3d 20 73 65 6c 66 2e [header] = self.
1ad0: 68 65 61 64 65 72 73 5b 68 65 61 64 65 72 5d 0a headers[header].
1ae0: 0a 09 09 09 09 6e 65 65 64 65 64 20 3d 20 4e 6f .....needed = No
1af0: 6e 65 0a 09 09 09 09 69 66 20 73 65 6c 66 2e 63 ne.....if self.c
1b00: 6f 6d 6d 61 6e 64 20 6e 6f 74 20 69 6e 20 28 27 ommand not in ('
1b10: 48 45 41 44 27 29 3a 0a 09 09 09 09 09 69 66 20 HEAD'):......if
1b20: 27 5f 70 61 72 74 73 27 20 69 6e 20 72 65 63 6f '_parts' in reco
1b30: 72 64 20 61 6e 64 20 72 65 63 6f 72 64 5b 27 5f rd and record['_
1b40: 70 61 72 74 73 27 5d 20 21 3d 20 4e 6f 6e 65 3a parts'] != None:
1b50: 0a 09 09 09 09 09 09 69 66 20 63 6f 6e 66 69 67 .......if config
1b60: 5f 68 6f 73 74 5b 27 6e 6f 70 61 72 74 73 27 5d _host['noparts']
1b70: 20 21 3d 20 27 6e 6f 27 20 6f 72 20 72 65 71 75 != 'no' or requ
1b80: 65 73 74 65 64 5f 72 61 6e 67 65 73 20 3d 3d 20 ested_ranges ==
1b90: 4e 6f 6e 65 20 6f 72 20 72 65 71 75 65 73 74 65 None or requeste
1ba0: 64 5f 72 61 6e 67 65 73 20 3d 3d 20 73 70 61 63 d_ranges == spac
1bb0: 65 6d 61 70 2e 53 70 61 63 65 4d 61 70 28 29 3a emap.SpaceMap():
1bc0: 0a 09 09 09 09 09 09 09 6e 65 65 64 65 64 20 3d ........needed =
1bd0: 20 72 65 63 6f 72 64 5b 27 5f 70 61 72 74 73 27 record['_parts'
1be0: 5d 0a 09 09 09 09 09 09 65 6c 73 65 3a 0a 09 09 ].......else:...
1bf0: 09 09 09 09 09 6e 65 65 64 65 64 20 3d 20 72 65 .....needed = re
1c00: 63 6f 72 64 5b 27 5f 70 61 72 74 73 27 5d 20 26 cord['_parts'] &
1c10: 20 72 65 71 75 65 73 74 65 64 5f 72 61 6e 67 65 requested_range
1c20: 73 0a 09 09 09 09 09 65 6c 69 66 20 63 6f 6e 66 s......elif conf
1c30: 69 67 5f 68 6f 73 74 5b 27 6e 6f 70 61 72 74 73 ig_host['noparts
1c40: 27 5d 20 3d 3d 27 6e 6f 27 20 61 6e 64 20 72 65 '] =='no' and re
1c50: 71 75 65 73 74 65 64 5f 72 61 6e 67 65 73 20 21 quested_ranges !
1c60: 3d 20 4e 6f 6e 65 20 61 6e 64 20 72 65 71 75 65 = None and reque
1c70: 73 74 65 64 5f 72 61 6e 67 65 73 20 21 3d 20 73 sted_ranges != s
1c80: 70 61 63 65 6d 61 70 2e 53 70 61 63 65 4d 61 70 pacemap.SpaceMap
1c90: 28 29 3a 0a 09 09 09 09 09 09 6e 65 65 64 65 64 ():.......needed
1ca0: 20 3d 20 72 65 71 75 65 73 74 65 64 5f 72 61 6e = requested_ran
1cb0: 67 65 73 0a 09 09 09 09 09 72 61 6e 67 65 73 20 ges......ranges
1cc0: 3d 20 28 29 0a 09 09 09 09 09 70 72 69 6e 74 28 = ()......print(
1cd0: 27 4d 69 73 73 69 6e 67 20 72 61 6e 67 65 73 3a 'Missing ranges:
1ce0: 20 7b 7d 2c 20 72 65 71 75 65 73 74 65 64 20 72 {}, requested r
1cf0: 61 6e 67 65 73 3a 20 7b 7d 2c 20 6e 65 65 64 65 anges: {}, neede
1d00: 64 20 72 61 6e 67 65 73 3a 20 7b 7d 2e 27 2e 66 d ranges: {}.'.f
1d10: 6f 72 6d 61 74 28 72 65 63 6f 72 64 5b 27 5f 70 ormat(record['_p
1d20: 61 72 74 73 27 5d 2c 20 72 65 71 75 65 73 74 65 arts'], requeste
1d30: 64 5f 72 61 6e 67 65 73 2c 20 6e 65 65 64 65 64 d_ranges, needed
1d40: 29 29 0a 09 09 09 09 09 69 66 20 6e 65 65 64 65 ))......if neede
1d50: 64 20 21 3d 20 4e 6f 6e 65 20 61 6e 64 20 6c 65 d != None and le
1d60: 6e 28 6e 65 65 64 65 64 29 20 3e 20 30 3a 0a 09 n(needed) > 0:..
1d70: 09 09 09 09 09 6e 65 65 64 65 64 2e 72 65 77 69 .....needed.rewi
1d80: 6e 64 28 29 0a 09 09 09 09 09 09 77 68 69 6c 65 nd().......while
1d90: 20 54 72 75 65 3a 0a 09 09 09 09 09 09 09 72 61 True:........ra
1da0: 6e 67 65 20 3d 20 6e 65 65 64 65 64 2e 70 6f 70 nge = needed.pop
1db0: 28 29 0a 09 09 09 09 09 09 09 69 66 20 72 61 6e ()........if ran
1dc0: 67 65 5b 30 5d 20 3d 3d 20 4e 6f 6e 65 3a 0a 09 ge[0] == None:..
1dd0: 09 09 09 09 09 09 09 62 72 65 61 6b 0a 09 09 09 .......break....
1de0: 09 09 09 09 72 61 6e 67 65 73 20 2b 3d 20 27 7b ....ranges += '{
1df0: 7d 2d 7b 7d 27 2e 66 6f 72 6d 61 74 28 72 61 6e }-{}'.format(ran
1e00: 67 65 5b 30 5d 2c 20 72 61 6e 67 65 5b 31 5d 20 ge[0], range[1]
1e10: 2d 20 31 29 2c 0a 09 09 09 09 09 09 6d 79 5f 68 - 1),.......my_h
1e20: 65 61 64 65 72 73 5b 27 52 61 6e 67 65 27 5d 20 eaders['Range']
1e30: 3d 20 27 62 79 74 65 73 3d 27 20 2b 20 27 2c 27 = 'bytes=' + ','
1e40: 2e 6a 6f 69 6e 28 72 61 6e 67 65 73 29 0a 0a 09 .join(ranges)...
1e50: 09 09 09 23 6d 79 5f 68 65 61 64 65 72 73 5b 27 ...#my_headers['
1e60: 41 63 63 65 70 74 2d 45 6e 63 6f 64 69 6e 67 27 Accept-Encoding'
1e70: 5d 20 3d 20 27 67 7a 69 70 2c 20 63 6f 6d 70 72 ] = 'gzip, compr
1e80: 65 73 73 2c 20 64 65 66 6c 61 74 65 2c 20 69 64 ess, deflate, id
1e90: 65 6e 74 69 74 79 3b 20 71 3d 30 27 0a 09 09 09 entity; q=0'....
1ea0: 09 72 65 71 75 65 73 74 20 3d 20 75 72 6c 6c 69 .request = urlli
1eb0: 62 2e 72 65 71 75 65 73 74 2e 52 65 71 75 65 73 b.request.Reques
1ec0: 74 28 72 65 71 75 65 73 74 2c 20 68 65 61 64 65 t(request, heade
1ed0: 72 73 20 3d 20 6d 79 5f 68 65 61 64 65 72 73 29 rs = my_headers)
1ee0: 0a 0a 09 09 09 09 73 6f 75 72 63 65 20 3d 20 75 ......source = u
1ef0: 72 6c 6c 69 62 2e 72 65 71 75 65 73 74 2e 75 72 rllib.request.ur
1f00: 6c 6f 70 65 6e 28 72 65 71 75 65 73 74 2c 20 74 lopen(request, t
1f10: 69 6d 65 6f 75 74 20 3d 20 36 30 29 0a 09 09 09 imeout = 60)....
1f20: 09 6e 65 77 5f 72 65 63 6f 72 64 20 3d 20 7b 7d .new_record = {}
1f30: 0a 09 09 09 09 6e 65 77 5f 72 65 63 6f 72 64 5b .....new_record[
1f40: 27 5f 70 61 72 74 73 27 5d 20 3d 20 72 65 63 6f '_parts'] = reco
1f50: 72 64 5b 27 5f 70 61 72 74 73 27 5d 0a 09 09 09 rd['_parts']....
1f60: 09 68 65 61 64 65 72 73 20 3d 20 73 6f 75 72 63 .headers = sourc
1f70: 65 2e 69 6e 66 6f 28 29 0a 0a 09 09 09 09 69 66 e.info()......if
1f80: 20 27 43 6f 6e 74 65 6e 74 2d 45 6e 63 6f 64 69 'Content-Encodi
1f90: 6e 67 27 20 69 6e 20 68 65 61 64 65 72 73 20 61 ng' in headers a
1fa0: 6e 64 20 68 65 61 64 65 72 73 5b 27 43 6f 6e 74 nd headers['Cont
1fb0: 65 6e 74 2d 45 6e 63 6f 64 69 6e 67 27 5d 20 3d ent-Encoding'] =
1fc0: 3d 20 27 67 7a 69 70 27 3a 0a 09 09 09 09 09 69 = 'gzip':......i
1fd0: 6d 70 6f 72 74 20 67 7a 69 70 0a 09 09 09 09 09 mport gzip......
1fe0: 73 6f 75 72 63 65 20 3d 20 67 7a 69 70 2e 47 7a source = gzip.Gz
1ff0: 69 70 46 69 6c 65 28 66 69 6c 65 6f 62 6a 3d 73 ipFile(fileobj=s
2000: 6f 75 72 63 65 29 0a 0a 09 09 09 09 23 20 73 74 ource)......# st
2010: 72 69 70 70 69 6e 67 20 75 6e 6e 65 65 64 65 64 ripping unneeded
2020: 20 68 65 61 64 65 72 73 20 28 58 58 58 20 6d 61 headers (XXX ma
2030: 6b 65 20 74 68 69 73 20 69 6e 70 6c 61 63 65 3f ke this inplace?
2040: 29 0a 09 09 09 09 66 6f 72 20 68 65 61 64 65 72 ).....for header
2050: 20 69 6e 20 68 65 61 64 65 72 73 3a 0a 09 09 09 in headers:....
2060: 09 09 69 66 20 68 65 61 64 65 72 20 69 6e 20 64 ..if header in d
2070: 65 73 63 5f 66 69 65 6c 64 73 3a 0a 09 09 09 09 esc_fields:.....
2080: 09 09 23 69 66 20 68 65 61 64 65 72 20 3d 3d 20 ..#if header ==
2090: 27 50 72 61 67 6d 61 27 20 61 6e 64 20 68 65 61 'Pragma' and hea
20a0: 64 65 72 73 5b 68 65 61 64 65 72 5d 20 21 3d 20 ders[header] !=
20b0: 27 6e 6f 2d 63 61 63 68 65 27 3a 0a 09 09 09 09 'no-cache':.....
20c0: 09 09 69 66 20 68 65 61 64 65 72 20 3d 3d 20 27 ..if header == '
20d0: 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 27 3a Content-Length':
20e0: 0a 09 09 09 09 09 09 09 69 66 20 27 43 6f 6e 74 ........if 'Cont
20f0: 65 6e 74 2d 52 61 6e 67 65 27 20 6e 6f 74 20 69 ent-Range' not i
2100: 6e 20 68 65 61 64 65 72 73 3a 0a 09 09 09 09 09 n headers:......
2110: 09 09 09 6e 65 77 5f 72 65 63 6f 72 64 5b 68 65 ...new_record[he
2120: 61 64 65 72 5d 20 3d 20 69 6e 74 28 68 65 61 64 ader] = int(head
2130: 65 72 73 5b 68 65 61 64 65 72 5d 29 0a 09 09 09 ers[header])....
2140: 09 09 09 65 6c 73 65 3a 0a 09 09 09 09 09 09 09 ...else:........
2150: 6e 65 77 5f 72 65 63 6f 72 64 5b 68 65 61 64 65 new_record[heade
2160: 72 5d 20 3d 20 68 65 61 64 65 72 73 5b 68 65 61 r] = headers[hea
2170: 64 65 72 5d 0a 09 09 09 09 09 65 6c 69 66 20 68 der]......elif h
2180: 65 61 64 65 72 20 3d 3d 20 27 43 6f 6e 74 65 6e eader == 'Conten
2190: 74 2d 52 61 6e 67 65 27 3a 0a 09 09 09 09 09 09 t-Range':.......
21a0: 72 61 6e 67 65 20 3d 20 72 65 2e 63 6f 6d 70 69 range = re.compi
21b0: 6c 65 28 27 5e 62 79 74 65 73 20 28 5c 64 2b 29 le('^bytes (\d+)
21c0: 2d 28 5c 64 2b 29 2f 28 5c 64 2b 29 24 27 29 2e -(\d+)/(\d+)$').
21d0: 6d 61 74 63 68 28 68 65 61 64 65 72 73 5b 68 65 match(headers[he
21e0: 61 64 65 72 5d 29 0a 09 09 09 09 09 09 69 66 20 ader]).......if
21f0: 72 61 6e 67 65 3a 0a 09 09 09 09 09 09 09 6e 65 range:........ne
2200: 77 5f 72 65 63 6f 72 64 5b 27 43 6f 6e 74 65 6e w_record['Conten
2210: 74 2d 4c 65 6e 67 74 68 27 5d 20 3d 20 69 6e 74 t-Length'] = int
2220: 28 72 61 6e 67 65 2e 67 72 6f 75 70 28 33 29 29 (range.group(3))
2230: 0a 09 09 09 09 09 09 65 6c 73 65 3a 09 0a 09 09 .......else:....
2240: 09 09 09 09 09 61 73 73 65 72 74 20 46 61 6c 73 .....assert Fals
2250: 65 2c 20 27 43 6f 6e 74 65 6e 74 2d 52 61 6e 67 e, 'Content-Rang
2260: 65 20 75 6e 72 65 63 6f 67 6e 69 7a 65 64 2e 27 e unrecognized.'
2270: 0a 09 09 09 09 09 65 6c 69 66 20 6e 6f 74 20 68 ......elif not h
2280: 65 61 64 65 72 20 69 6e 20 69 67 6e 6f 72 65 5f eader in ignore_
2290: 66 69 65 6c 64 73 3a 0a 09 09 09 09 09 09 70 72 fields:.......pr
22a0: 69 6e 74 28 27 55 6e 64 65 66 69 6e 65 64 20 68 int('Undefined h
22b0: 65 61 64 65 72 20 22 27 2c 20 68 65 61 64 65 72 eader "', header
22c0: 2c 20 27 22 3a 20 27 2c 20 68 65 61 64 65 72 73 , '": ', headers
22d0: 5b 68 65 61 64 65 72 5d 2c 20 73 65 70 3d 27 27 [header], sep=''
22e0: 29 0a 0a 09 09 09 09 23 20 63 6f 6d 70 61 72 69 )......# compari
22f0: 6e 67 20 68 65 61 64 65 72 73 20 77 69 74 68 20 ng headers with
2300: 64 61 74 61 20 66 6f 75 6e 64 20 69 6e 20 69 6e data found in in
2310: 64 65 78 0a 09 09 09 09 23 20 69 66 20 61 6e 79 dex.....# if any
2320: 20 68 65 61 64 65 72 20 68 61 73 20 63 68 61 6e header has chan
2330: 67 65 64 20 28 65 78 63 65 70 74 20 50 72 61 67 ged (except Prag
2340: 6d 61 29 20 66 69 6c 65 20 69 73 20 66 75 6c 6c ma) file is full
2350: 79 20 64 6f 77 6e 6c 6f 61 64 65 64 0a 09 09 09 y downloaded....
2360: 09 23 20 73 61 6d 65 20 69 66 20 77 65 20 67 65 .# same if we ge
2370: 74 20 6d 6f 72 65 20 6f 72 20 6c 65 73 73 20 68 t more or less h
2380: 65 61 64 65 72 73 0a 09 09 09 09 6f 6c 64 5f 6b eaders.....old_k
2390: 65 79 73 20 3d 20 73 65 74 28 72 65 63 6f 72 64 eys = set(record
23a0: 2e 6b 65 79 73 28 29 29 0a 09 09 09 09 6f 6c 64 .keys()).....old
23b0: 5f 6b 65 79 73 2e 64 69 73 63 61 72 64 28 27 5f _keys.discard('_
23c0: 74 69 6d 65 27 29 0a 09 09 09 09 6f 6c 64 5f 6b time').....old_k
23d0: 65 79 73 2e 64 69 73 63 61 72 64 28 27 50 72 61 eys.discard('Pra
23e0: 67 6d 61 27 29 0a 09 09 09 09 6d 6f 72 65 5f 6b gma').....more_k
23f0: 65 79 73 20 3d 20 73 65 74 28 6e 65 77 5f 72 65 eys = set(new_re
2400: 63 6f 72 64 2e 6b 65 79 73 28 29 29 20 2d 20 6f cord.keys()) - o
2410: 6c 64 5f 6b 65 79 73 0a 09 09 09 09 6d 6f 72 65 ld_keys.....more
2420: 5f 6b 65 79 73 2e 64 69 73 63 61 72 64 28 27 50 _keys.discard('P
2430: 72 61 67 6d 61 27 29 0a 09 09 09 09 6c 65 73 73 ragma').....less
2440: 5f 6b 65 79 73 20 3d 20 6f 6c 64 5f 6b 65 79 73 _keys = old_keys
2450: 20 2d 20 73 65 74 28 6e 65 77 5f 72 65 63 6f 72 - set(new_recor
2460: 64 2e 6b 65 79 73 28 29 29 0a 09 09 09 09 69 66 d.keys()).....if
2470: 20 6c 65 6e 28 6d 6f 72 65 5f 6b 65 79 73 29 20 len(more_keys)
2480: 3e 20 30 3a 0a 09 09 09 09 09 69 66 20 6c 65 6e > 0:......if len
2490: 28 6f 6c 64 5f 6b 65 79 73 29 20 21 3d 20 30 3a (old_keys) != 0:
24a0: 0a 09 09 09 09 09 09 70 72 69 6e 74 28 27 4d 6f .......print('Mo
24b0: 72 65 20 68 65 61 64 65 72 73 20 61 70 70 65 61 re headers appea
24c0: 72 3a 27 2c 20 6d 6f 72 65 5f 6b 65 79 73 29 0a r:', more_keys).
24d0: 09 09 09 09 09 72 65 6c 6f 61 64 20 3d 20 54 72 .....reload = Tr
24e0: 75 65 0a 09 09 09 09 65 6c 69 66 20 6c 65 6e 28 ue.....elif len(
24f0: 6c 65 73 73 5f 6b 65 79 73 29 20 3e 20 30 3a 0a less_keys) > 0:.
2500: 09 09 09 09 09 70 72 69 6e 74 28 27 4c 65 73 73 .....print('Less
2510: 20 68 65 61 64 65 72 73 20 61 70 70 65 61 72 3a headers appear:
2520: 27 2c 20 6c 65 73 73 5f 6b 65 79 73 29 0a 09 09 ', less_keys)...
2530: 09 09 65 6c 73 65 3a 0a 09 09 09 09 09 66 6f 72 ..else:......for
2540: 20 6b 65 79 20 69 6e 20 72 65 63 6f 72 64 2e 6b key in record.k
2550: 65 79 73 28 29 3a 0a 09 09 09 09 09 09 69 66 20 eys():.......if
2560: 6b 65 79 5b 30 5d 20 21 3d 20 27 5f 27 20 61 6e key[0] != '_' an
2570: 64 20 6b 65 79 20 21 3d 20 27 50 72 61 67 6d 61 d key != 'Pragma
2580: 27 20 61 6e 64 20 72 65 63 6f 72 64 5b 6b 65 79 ' and record[key
2590: 5d 20 21 3d 20 6e 65 77 5f 72 65 63 6f 72 64 5b ] != new_record[
25a0: 6b 65 79 5d 3a 0a 09 09 09 09 09 09 09 70 72 69 key]:........pri
25b0: 6e 74 28 27 48 65 61 64 65 72 20 22 27 2c 20 6b nt('Header "', k
25c0: 65 79 2c 20 27 22 20 63 68 61 6e 67 65 64 20 66 ey, '" changed f
25d0: 72 6f 6d 20 5b 27 2c 20 72 65 63 6f 72 64 5b 6b rom [', record[k
25e0: 65 79 5d 2c 20 27 5d 20 74 6f 20 5b 27 2c 20 6e ey], '] to [', n
25f0: 65 77 5f 72 65 63 6f 72 64 5b 6b 65 79 5d 2c 20 ew_record[key],
2600: 27 5d 27 2c 20 73 65 70 3d 27 27 29 0a 09 09 09 ']', sep='')....
2610: 09 09 09 09 70 72 69 6e 74 28 74 79 70 65 28 72 ....print(type(r
2620: 65 63 6f 72 64 5b 6b 65 79 5d 29 2c 20 74 79 70 ecord[key]), typ
2630: 65 28 6e 65 77 5f 72 65 63 6f 72 64 5b 6b 65 79 e(new_record[key
2640: 5d 29 29 0a 09 09 09 09 09 09 09 72 65 6c 6f 61 ]))........reloa
2650: 64 20 3d 20 54 72 75 65 0a 0a 09 09 09 09 69 66 d = True......if
2660: 20 72 65 6c 6f 61 64 3a 0a 09 09 09 09 09 70 72 reload:......pr
2670: 69 6e 74 28 27 52 65 6c 6f 61 64 69 6e 67 2e 27 int('Reloading.'
2680: 29 0a 09 09 09 09 09 69 66 20 6f 73 2e 61 63 63 )......if os.acc
2690: 65 73 73 28 74 65 6d 70 5f 6e 61 6d 65 2c 20 6f ess(temp_name, o
26a0: 73 2e 52 5f 4f 4b 29 3a 0a 09 09 09 09 09 09 6f s.R_OK):.......o
26b0: 73 2e 75 6e 6c 69 6e 6b 28 74 65 6d 70 5f 6e 61 s.unlink(temp_na
26c0: 6d 65 29 0a 09 09 09 09 09 69 66 20 6f 73 2e 61 me)......if os.a
26d0: 63 63 65 73 73 28 66 69 6c 65 5f 6e 61 6d 65 2c ccess(file_name,
26e0: 20 6f 73 2e 52 5f 4f 4b 29 3a 0a 09 09 09 09 09 os.R_OK):......
26f0: 09 6f 73 2e 75 6e 6c 69 6e 6b 28 66 69 6c 65 5f .os.unlink(file_
2700: 6e 61 6d 65 29 0a 09 09 09 09 09 69 66 20 27 43 name)......if 'C
2710: 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 27 20 69 ontent-Length' i
2720: 6e 20 6e 65 77 5f 72 65 63 6f 72 64 3a 0a 09 09 n new_record:...
2730: 09 09 09 09 6e 65 77 5f 72 65 63 6f 72 64 5b 27 ....new_record['
2740: 5f 70 61 72 74 73 27 5d 20 3d 20 73 70 61 63 65 _parts'] = space
2750: 6d 61 70 2e 53 70 61 63 65 4d 61 70 28 7b 30 3a map.SpaceMap({0:
2760: 20 69 6e 74 28 6e 65 77 5f 72 65 63 6f 72 64 5b int(new_record[
2770: 27 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 27 'Content-Length'
2780: 5d 29 7d 29 0a 09 09 09 09 69 66 20 6e 6f 74 20 ])}).....if not
2790: 6e 65 77 5f 72 65 63 6f 72 64 5b 27 5f 70 61 72 new_record['_par
27a0: 74 73 27 5d 3a 0a 09 09 09 09 09 6e 65 77 5f 72 ts']:......new_r
27b0: 65 63 6f 72 64 5b 27 5f 70 61 72 74 73 27 5d 20 ecord['_parts']
27c0: 3d 20 73 70 61 63 65 6d 61 70 2e 53 70 61 63 65 = spacemap.Space
27d0: 4d 61 70 28 29 0a 09 09 09 09 70 72 69 6e 74 28 Map().....print(
27e0: 6e 65 77 5f 72 65 63 6f 72 64 29 0a 0a 09 09 09 new_record).....
27f0: 09 23 20 64 6f 77 6e 6c 6f 61 64 69 6e 67 20 66 .# downloading f
2800: 69 6c 65 20 6f 72 20 73 65 67 6d 65 6e 74 0a 09 ile or segment..
2810: 09 09 09 69 66 20 27 43 6f 6e 74 65 6e 74 2d 4c ...if 'Content-L
2820: 65 6e 67 74 68 27 20 69 6e 20 6e 65 77 5f 72 65 ength' in new_re
2830: 63 6f 72 64 3a 0a 09 09 09 09 09 69 66 20 6e 65 cord:......if ne
2840: 65 64 65 64 20 3d 3d 20 4e 6f 6e 65 3a 0a 09 09 eded == None:...
2850: 09 09 09 09 6e 65 65 64 65 64 20 3d 20 6e 65 77 ....needed = new
2860: 5f 72 65 63 6f 72 64 5b 27 5f 70 61 72 74 73 27 _record['_parts'
2870: 5d 0a 09 09 09 09 09 65 6c 73 65 3a 0a 09 09 09 ]......else:....
2880: 09 09 09 69 66 20 6c 65 6e 28 6e 65 65 64 65 64 ...if len(needed
2890: 29 20 3e 20 31 3a 0a 09 09 09 09 09 09 09 70 72 ) > 1:........pr
28a0: 69 6e 74 28 22 4d 75 6c 74 69 70 61 72 74 20 72 int("Multipart r
28b0: 65 71 75 65 73 74 73 20 63 75 72 72 65 6e 74 6c equests currentl
28c0: 79 20 6e 6f 74 20 73 75 70 70 6f 72 74 65 64 2e y not supported.
28d0: 22 29 0a 09 09 09 09 09 09 09 61 73 73 65 72 74 ")........assert
28e0: 20 46 61 6c 73 65 2c 20 27 53 6b 69 70 20 74 68 False, 'Skip th
28f0: 69 73 20 6f 6e 65 20 66 6f 72 20 6e 6f 77 2e 27 is one for now.'
2900: 0a 09 09 09 09 23 65 6c 73 65 3a 0a 09 09 09 09 .....#else:.....
2910: 09 23 61 73 73 65 72 74 20 46 61 6c 73 65 2c 20 .#assert False,
2920: 27 4e 6f 20 63 6f 6e 74 65 6e 74 2d 6c 65 6e 67 'No content-leng
2930: 74 68 20 6f 72 20 43 6f 6e 74 65 6e 74 2d 52 61 th or Content-Ra
2940: 6e 67 65 20 68 65 61 64 65 72 2e 27 0a 0a 09 09 nge header.'....
2950: 09 09 6e 65 77 5f 72 65 63 6f 72 64 5b 27 5f 74 ..new_record['_t
2960: 69 6d 65 27 5d 20 3d 20 64 61 74 65 74 69 6d 65 ime'] = datetime
2970: 2e 64 61 74 65 74 69 6d 65 2e 6e 6f 77 28 29 0a .datetime.now().
2980: 09 09 09 09 69 66 20 73 65 6c 66 2e 63 6f 6d 6d ....if self.comm
2990: 61 6e 64 20 6e 6f 74 20 69 6e 20 28 27 48 45 41 and not in ('HEA
29a0: 44 27 29 3a 0a 09 09 09 09 09 23 20 66 69 6c 65 D'):......# file
29b0: 20 69 73 20 63 72 65 61 74 65 64 20 61 74 20 74 is created at t
29c0: 65 6d 70 6f 72 61 72 79 20 6c 6f 63 61 74 69 6f emporary locatio
29d0: 6e 20 61 6e 64 20 6d 6f 76 65 64 20 69 6e 20 70 n and moved in p
29e0: 6c 61 63 65 20 6f 6e 6c 79 20 77 68 65 6e 20 64 lace only when d
29f0: 6f 77 6e 6c 6f 61 64 20 63 6f 6d 70 6c 65 74 65 ownload complete
2a00: 73 0a 09 09 09 09 09 69 66 20 6e 6f 74 20 6f 73 s......if not os
2a10: 2e 61 63 63 65 73 73 28 74 65 6d 70 5f 6e 61 6d .access(temp_nam
2a20: 65 2c 20 6f 73 2e 52 5f 4f 4b 29 3a 0a 09 09 09 e, os.R_OK):....
2a30: 09 09 09 65 6d 70 74 79 5f 6e 61 6d 65 20 3d 20 ...empty_name =
2a40: 63 6f 6e 66 69 67 5f 68 6f 73 74 5b 27 64 69 72 config_host['dir
2a50: 27 5d 20 2b 20 6f 73 2e 73 65 70 20 2b 20 27 2e '] + os.sep + '.
2a60: 74 6d 70 27 0a 09 09 09 09 09 09 77 69 74 68 20 tmp'.......with
2a70: 6f 70 65 6e 28 65 6d 70 74 79 5f 6e 61 6d 65 2c open(empty_name,
2a80: 20 27 77 2b 62 27 29 20 61 73 20 73 6f 6d 65 5f 'w+b') as some_
2a90: 66 69 6c 65 3a 0a 09 09 09 09 09 09 09 70 61 73 file:........pas
2aa0: 73 0a 09 09 09 09 09 09 6f 73 2e 72 65 6e 61 6d s.......os.renam
2ab0: 65 73 28 65 6d 70 74 79 5f 6e 61 6d 65 2c 20 74 es(empty_name, t
2ac0: 65 6d 70 5f 6e 61 6d 65 29 0a 09 09 09 09 09 74 emp_name)......t
2ad0: 65 6d 70 5f 66 69 6c 65 20 3d 20 6f 70 65 6e 28 emp_file = open(
2ae0: 74 65 6d 70 5f 6e 61 6d 65 2c 20 27 72 2b 62 27 temp_name, 'r+b'
2af0: 29 0a 09 09 09 09 09 69 66 20 72 65 71 75 65 73 )......if reques
2b00: 74 65 64 5f 72 61 6e 67 65 73 20 3d 3d 20 4e 6f ted_ranges == No
2b10: 6e 65 20 61 6e 64 20 6e 65 65 64 65 64 20 3d 3d ne and needed ==
2b20: 20 4e 6f 6e 65 3a 0a 09 09 09 09 09 09 6e 65 65 None:.......nee
2b30: 64 65 64 20 3d 20 6e 65 77 5f 72 65 63 6f 72 64 ded = new_record
2b40: 5b 27 5f 70 61 72 74 73 27 5d 0a 09 09 09 09 09 ['_parts']......
2b50: 6e 65 65 64 65 64 2e 72 65 77 69 6e 64 28 29 0a needed.rewind().
2b60: 09 09 09 09 09 63 6f 75 6e 74 64 6f 77 6e 20 3d .....countdown =
2b70: 20 31 36 0a 09 09 09 09 09 77 68 69 6c 65 20 54 16......while T
2b80: 72 75 65 3a 0a 09 09 09 09 09 09 23 20 58 58 58 rue:.......# XXX
2b90: 20 63 61 6e 20 6d 61 6b 65 20 74 68 69 73 20 69 can make this i
2ba0: 6d 70 6c 69 63 69 74 20 2d 20 6f 6e 65 20 72 65 mplicit - one re
2bb0: 71 75 65 73 74 20 70 65 72 20 72 61 6e 67 65 0a quest per range.
2bc0: 09 09 09 09 09 09 28 73 74 61 72 74 2c 20 65 6e ......(start, en
2bd0: 64 29 20 3d 20 6e 65 65 64 65 64 2e 70 6f 70 28 d) = needed.pop(
2be0: 29 0a 09 09 09 09 09 09 69 66 20 73 74 61 72 74 ).......if start
2bf0: 20 3d 3d 20 4e 6f 6e 65 3a 0a 09 09 09 09 09 09 == None:.......
2c00: 09 62 72 65 61 6b 0a 09 09 09 09 09 09 73 74 72 .break.......str
2c10: 65 61 6d 5f 6c 61 73 74 20 3d 20 73 74 61 72 74 eam_last = start
2c20: 0a 09 09 09 09 09 09 6f 6c 64 5f 72 65 63 6f 72 .......old_recor
2c30: 64 20 3d 20 63 6f 70 79 2e 63 6f 70 79 28 6e 65 d = copy.copy(ne
2c40: 77 5f 72 65 63 6f 72 64 29 0a 09 09 09 09 09 09 w_record).......
2c50: 69 66 20 65 6e 64 20 2d 20 73 74 61 72 74 20 3c if end - start <
2c60: 20 62 6c 6f 63 6b 5f 73 69 7a 65 3a 0a 09 09 09 block_size:....
2c70: 09 09 09 09 72 65 71 5f 62 6c 6f 63 6b 5f 73 69 ....req_block_si
2c80: 7a 65 20 3d 20 65 6e 64 20 2d 20 73 74 61 72 74 ze = end - start
2c90: 0a 09 09 09 09 09 09 65 6c 73 65 3a 0a 09 09 09 .......else:....
2ca0: 09 09 09 09 72 65 71 5f 62 6c 6f 63 6b 5f 73 69 ....req_block_si
2cb0: 7a 65 20 3d 20 62 6c 6f 63 6b 5f 73 69 7a 65 0a ze = block_size.
2cc0: 09 09 09 09 09 09 62 75 66 66 65 72 20 3d 20 73 ......buffer = s
2cd0: 6f 75 72 63 65 2e 72 65 61 64 28 72 65 71 5f 62 ource.read(req_b
2ce0: 6c 6f 63 6b 5f 73 69 7a 65 29 0a 09 09 09 09 09 lock_size)......
2cf0: 09 6c 65 6e 67 74 68 20 3d 20 6c 65 6e 28 62 75 .length = len(bu
2d00: 66 66 65 72 29 0a 09 09 09 09 09 09 77 68 69 6c ffer).......whil
2d10: 65 20 6c 65 6e 67 74 68 20 3e 20 30 20 61 6e 64 e length > 0 and
2d20: 20 73 74 72 65 61 6d 5f 6c 61 73 74 20 3c 20 65 stream_last < e
2d30: 6e 64 3a 0a 09 09 09 09 09 09 09 73 74 72 65 61 nd:........strea
2d40: 6d 5f 70 6f 73 20 3d 20 73 74 72 65 61 6d 5f 6c m_pos = stream_l
2d50: 61 73 74 20 2b 20 6c 65 6e 67 74 68 0a 09 09 09 ast + length....
2d60: 09 09 09 09 61 73 73 65 72 74 20 73 74 72 65 61 ....assert strea
2d70: 6d 5f 70 6f 73 20 3c 3d 20 65 6e 64 2c 20 27 52 m_pos <= end, 'R
2d80: 65 63 65 69 76 65 64 20 6d 6f 72 65 20 64 61 74 eceived more dat
2d90: 61 20 74 68 65 6e 20 72 65 71 75 65 73 74 65 64 a then requested
2da0: 3a 20 70 6f 73 3a 7b 7d 20 73 74 61 72 74 3a 7b : pos:{} start:{
2db0: 7d 20 65 6e 64 3a 7b 7d 2e 27 2e 66 6f 72 6d 61 } end:{}.'.forma
2dc0: 74 28 73 74 72 65 61 6d 5f 70 6f 73 2c 20 73 74 t(stream_pos, st
2dd0: 61 72 74 2c 20 65 6e 64 29 0a 09 09 09 09 09 09 art, end).......
2de0: 09 74 65 6d 70 5f 66 69 6c 65 2e 73 65 65 6b 28 .temp_file.seek(
2df0: 73 74 72 65 61 6d 5f 6c 61 73 74 29 0a 09 09 09 stream_last)....
2e00: 09 09 09 09 74 65 6d 70 5f 66 69 6c 65 2e 77 72 ....temp_file.wr
2e10: 69 74 65 28 62 75 66 66 65 72 29 0a 09 09 09 09 ite(buffer).....
2e20: 09 09 09 78 20 3d 20 6e 65 77 5f 72 65 63 6f 72 ...x = new_recor
2e30: 64 5b 27 5f 70 61 72 74 73 27 5d 20 2d 20 73 70 d['_parts'] - sp
2e40: 61 63 65 6d 61 70 2e 53 70 61 63 65 4d 61 70 28 acemap.SpaceMap(
2e50: 7b 73 74 72 65 61 6d 5f 6c 61 73 74 3a 20 73 74 {stream_last: st
2e60: 72 65 61 6d 5f 70 6f 73 7d 29 0a 09 09 09 09 09 ream_pos})......
2e70: 09 09 6e 65 77 5f 72 65 63 6f 72 64 5b 27 5f 70 ..new_record['_p
2e80: 61 72 74 73 27 5d 20 3d 20 6e 65 77 5f 72 65 63 arts'] = new_rec
2e90: 6f 72 64 5b 27 5f 70 61 72 74 73 27 5d 20 2d 20 ord['_parts'] -
2ea0: 73 70 61 63 65 6d 61 70 2e 53 70 61 63 65 4d 61 spacemap.SpaceMa
2eb0: 70 28 7b 73 74 72 65 61 6d 5f 6c 61 73 74 3a 20 p({stream_last:
2ec0: 73 74 72 65 61 6d 5f 70 6f 73 7d 29 0a 09 09 09 stream_pos})....
2ed0: 09 09 09 09 63 6f 75 6e 74 64 6f 77 6e 20 2d 3d ....countdown -=
2ee0: 20 31 0a 09 09 09 09 09 09 09 69 66 20 63 6f 75 1........if cou
2ef0: 6e 74 64 6f 77 6e 20 3d 3d 20 30 3a 0a 09 09 09 ntdown == 0:....
2f00: 09 09 09 09 09 69 6e 64 65 78 5b 6d 79 5f 70 61 .....index[my_pa
2f10: 74 68 5f 62 5d 20 3d 20 6f 6c 64 5f 72 65 63 6f th_b] = old_reco
2f20: 72 64 0a 09 09 09 09 09 09 09 09 69 6e 64 65 78 rd.........index
2f30: 2e 73 79 6e 63 28 29 0a 09 09 09 09 09 09 09 09 .sync().........
2f40: 63 6f 75 6e 74 64 6f 77 6e 20 3d 20 31 36 0a 09 countdown = 16..
2f50: 09 09 09 09 09 09 6f 6c 64 5f 72 65 63 6f 72 64 ......old_record
2f60: 20 3d 20 63 6f 70 79 2e 63 6f 70 79 28 6e 65 77 = copy.copy(new
2f70: 5f 72 65 63 6f 72 64 29 0a 09 09 09 09 09 09 09 _record)........
2f80: 73 74 72 65 61 6d 5f 6c 61 73 74 20 3d 20 73 74 stream_last = st
2f90: 72 65 61 6d 5f 70 6f 73 0a 09 09 09 09 09 09 09 ream_pos........
2fa0: 69 66 20 65 6e 64 20 2d 20 73 74 72 65 61 6d 5f if end - stream_
2fb0: 6c 61 73 74 20 3c 20 62 6c 6f 63 6b 5f 73 69 7a last < block_siz
2fc0: 65 3a 0a 09 09 09 09 09 09 09 09 72 65 71 5f 62 e:.........req_b
2fd0: 6c 6f 63 6b 5f 73 69 7a 65 20 3d 20 65 6e 64 20 lock_size = end
2fe0: 2d 20 73 74 72 65 61 6d 5f 6c 61 73 74 0a 09 09 - stream_last...
2ff0: 09 09 09 09 09 62 75 66 66 65 72 20 3d 20 73 6f .....buffer = so
3000: 75 72 63 65 2e 72 65 61 64 28 72 65 71 5f 62 6c urce.read(req_bl
3010: 6f 63 6b 5f 73 69 7a 65 29 0a 09 09 09 09 09 09 ock_size).......
3020: 09 6c 65 6e 67 74 68 20 3d 20 6c 65 6e 28 62 75 .length = len(bu
3030: 66 66 65 72 29 0a 09 09 09 09 09 23 20 6d 6f 76 ffer)......# mov
3040: 69 6e 67 20 64 6f 77 6e 6c 6f 61 64 65 64 20 64 ing downloaded d
3050: 61 74 61 20 74 6f 20 72 65 61 6c 20 66 69 6c 65 ata to real file
3060: 0a 09 09 09 09 09 74 65 6d 70 5f 66 69 6c 65 2e ......temp_file.
3070: 63 6c 6f 73 65 28 29 0a 0a 09 09 09 09 69 6e 64 close()......ind
3080: 65 78 5b 6d 79 5f 70 61 74 68 5f 62 5d 20 3d 20 ex[my_path_b] =
3090: 6e 65 77 5f 72 65 63 6f 72 64 0a 09 09 09 09 69 new_record.....i
30a0: 6e 64 65 78 2e 73 79 6e 63 28 29 0a 0a 09 09 09 ndex.sync().....
30b0: 65 78 63 65 70 74 20 75 72 6c 6c 69 62 2e 65 72 except urllib.er
30c0: 72 6f 72 2e 48 54 54 50 45 72 72 6f 72 20 61 73 ror.HTTPError as
30d0: 20 65 72 72 6f 72 3a 0a 09 09 09 09 23 20 69 6e error:.....# in
30e0: 20 63 61 73 65 20 6f 66 20 65 72 72 6f 72 20 77 case of error w
30f0: 65 20 64 6f 6e 27 74 20 6e 65 65 64 20 74 6f 20 e don't need to
3100: 64 6f 20 61 6e 79 74 68 69 6e 67 20 61 63 74 75 do anything actu
3110: 61 6c 6c 79 2c 0a 09 09 09 09 23 20 69 66 20 66 ally,.....# if f
3120: 69 6c 65 20 64 6f 77 6e 6c 6f 61 64 20 73 74 61 ile download sta
3130: 6c 6c 73 20 6f 72 20 66 61 69 6c 73 20 74 68 65 lls or fails the
3140: 20 66 69 6c 65 20 77 6f 75 6c 64 20 6e 6f 74 20 file would not
3150: 62 65 20 6d 6f 76 65 64 20 74 6f 20 69 74 27 73 be moved to it's
3160: 20 6c 6f 63 61 74 69 6f 6e 0a 09 09 09 09 73 65 location.....se
3170: 6c 66 2e 73 65 6e 64 5f 72 65 73 70 6f 6e 73 65 lf.send_response
3180: 28 65 72 72 6f 72 2e 63 6f 64 65 29 0a 09 09 09 (error.code)....
3190: 09 73 65 6c 66 2e 65 6e 64 5f 68 65 61 64 65 72 .self.end_header
31a0: 73 28 29 0a 09 09 09 09 70 72 69 6e 74 28 65 72 s().....print(er
31b0: 72 6f 72 2c 20 72 65 70 72 28 6d 79 5f 68 65 61 ror, repr(my_hea
31c0: 64 65 72 73 29 29 0a 09 09 09 09 72 65 74 75 72 ders)).....retur
31d0: 6e 0a 0a 09 09 23 70 72 69 6e 74 28 69 6e 64 65 n....#print(inde
31e0: 78 5b 6d 79 5f 70 61 74 68 5f 62 5d 29 0a 0a 09 x[my_path_b])...
31f0: 09 69 66 20 6e 6f 74 20 6f 73 2e 61 63 63 65 73 .if not os.acces
3200: 73 28 66 69 6c 65 5f 6e 61 6d 65 2c 20 6f 73 2e s(file_name, os.
3210: 52 5f 4f 4b 29 20 61 6e 64 20 6f 73 2e 61 63 63 R_OK) and os.acc
3220: 65 73 73 28 74 65 6d 70 5f 6e 61 6d 65 2c 20 6f ess(temp_name, o
3230: 73 2e 52 5f 4f 4b 29 20 61 6e 64 20 27 5f 70 61 s.R_OK) and '_pa
3240: 72 74 73 27 20 69 6e 20 69 6e 64 65 78 5b 6d 79 rts' in index[my
3250: 5f 70 61 74 68 5f 62 5d 20 61 6e 64 20 69 6e 64 _path_b] and ind
3260: 65 78 5b 6d 79 5f 70 61 74 68 5f 62 5d 5b 27 5f ex[my_path_b]['_
3270: 70 61 72 74 73 27 5d 20 3d 3d 20 73 70 61 63 65 parts'] == space
3280: 6d 61 70 2e 53 70 61 63 65 4d 61 70 28 29 3a 0a map.SpaceMap():.
3290: 09 09 09 23 20 6a 75 73 74 20 6d 6f 76 69 6e 67 ...# just moving
32a0: 0a 09 09 09 23 20 64 72 6f 70 20 6f 6c 64 20 64 ....# drop old d
32b0: 69 72 73 20 58 58 58 0a 09 09 09 70 72 69 6e 74 irs XXX....print
32c0: 28 27 4d 6f 76 69 6e 67 20 74 65 6d 70 6f 72 61 ('Moving tempora
32d0: 72 79 20 66 69 6c 65 20 74 6f 20 6e 65 77 20 64 ry file to new d
32e0: 65 73 74 69 6e 61 74 69 6f 6e 2e 27 29 0a 09 09 estination.')...
32f0: 09 6f 73 2e 72 65 6e 61 6d 65 73 28 74 65 6d 70 .os.renames(temp
3300: 5f 6e 61 6d 65 2c 20 66 69 6c 65 5f 6e 61 6d 65 _name, file_name
3310: 29 0a 0a 09 09 69 66 20 6e 6f 74 20 6d 79 5f 70 )....if not my_p
3320: 61 74 68 5f 62 20 69 6e 20 69 6e 64 65 78 3a 0a ath_b in index:.
3330: 09 09 09 73 65 6c 66 2e 73 65 6e 64 5f 72 65 73 ...self.send_res
3340: 70 6f 6e 73 65 28 35 30 32 29 0a 09 09 09 73 65 ponse(502)....se
3350: 6c 66 2e 65 6e 64 5f 68 65 61 64 65 72 73 28 29 lf.end_headers()
3360: 0a 09 09 09 72 65 74 75 72 6e 0a 0a 09 09 69 66 ....return....if
3370: 20 73 65 6c 66 2e 63 6f 6d 6d 61 6e 64 20 3d 3d self.command ==
3380: 20 27 48 45 41 44 27 3a 0a 09 09 09 73 65 6c 66 'HEAD':....self
3390: 2e 73 65 6e 64 5f 72 65 73 70 6f 6e 73 65 28 32 .send_response(2
33a0: 30 30 29 0a 09 09 09 69 66 20 27 43 6f 6e 74 65 00)....if 'Conte
33b0: 6e 74 2d 4c 65 6e 67 74 68 27 20 69 6e 20 69 6e nt-Length' in in
33c0: 64 65 78 5b 6d 79 5f 70 61 74 68 5f 62 5d 3a 0a dex[my_path_b]:.
33d0: 09 09 09 09 73 65 6c 66 2e 73 65 6e 64 5f 68 65 ....self.send_he
33e0: 61 64 65 72 28 27 43 6f 6e 74 65 6e 74 2d 4c 65 ader('Content-Le
33f0: 6e 67 74 68 27 2c 20 69 6e 64 65 78 5b 6d 79 5f ngth', index[my_
3400: 70 61 74 68 5f 62 5d 5b 27 43 6f 6e 74 65 6e 74 path_b]['Content
3410: 2d 4c 65 6e 67 74 68 27 5d 29 0a 09 09 09 73 65 -Length'])....se
3420: 6c 66 2e 73 65 6e 64 5f 68 65 61 64 65 72 28 27 lf.send_header('
3430: 41 63 63 65 70 74 2d 52 61 6e 67 65 73 27 2c 20 Accept-Ranges',
3440: 27 62 79 74 65 73 27 29 0a 09 09 09 73 65 6c 66 'bytes')....self
3450: 2e 73 65 6e 64 5f 68 65 61 64 65 72 28 27 43 6f .send_header('Co
3460: 6e 74 65 6e 74 2d 54 79 70 65 27 2c 20 27 61 70 ntent-Type', 'ap
3470: 70 6c 69 63 61 74 69 6f 6e 2f 6f 63 74 65 74 2d plication/octet-
3480: 73 74 72 65 61 6d 27 29 0a 09 09 09 69 66 20 27 stream')....if '
3490: 4c 61 73 74 2d 4d 6f 64 69 66 69 65 64 27 20 69 Last-Modified' i
34a0: 6e 20 69 6e 64 65 78 5b 6d 79 5f 70 61 74 68 5f n index[my_path_
34b0: 62 5d 3a 0a 09 09 09 09 73 65 6c 66 2e 73 65 6e b]:.....self.sen
34c0: 64 5f 68 65 61 64 65 72 28 27 4c 61 73 74 2d 4d d_header('Last-M
34d0: 6f 64 69 66 69 65 64 27 2c 20 69 6e 64 65 78 5b odified', index[
34e0: 6d 79 5f 70 61 74 68 5f 62 5d 5b 27 4c 61 73 74 my_path_b]['Last
34f0: 2d 4d 6f 64 69 66 69 65 64 27 5d 29 0a 09 09 09 -Modified'])....
3500: 73 65 6c 66 2e 65 6e 64 5f 68 65 61 64 65 72 73 self.end_headers
3510: 28 29 0a 09 09 65 6c 73 65 3a 0a 09 09 09 69 66 ()...else:....if
3520: 20 28 27 5f 70 61 72 74 73 27 20 69 6e 20 69 6e ('_parts' in in
3530: 64 65 78 5b 6d 79 5f 70 61 74 68 5f 62 5d 20 61 dex[my_path_b] a
3540: 6e 64 20 69 6e 64 65 78 5b 6d 79 5f 70 61 74 68 nd index[my_path
3550: 5f 62 5d 5b 27 5f 70 61 72 74 73 27 5d 20 21 3d _b]['_parts'] !=
3560: 20 73 70 61 63 65 6d 61 70 2e 53 70 61 63 65 4d spacemap.SpaceM
3570: 61 70 28 29 29 20 6f 72 20 6e 6f 74 20 6f 73 2e ap()) or not os.
3580: 61 63 63 65 73 73 28 66 69 6c 65 5f 6e 61 6d 65 access(file_name
3590: 2c 20 6f 73 2e 52 5f 4f 4b 29 3a 0a 09 09 09 09 , os.R_OK):.....
35a0: 66 69 6c 65 5f 6e 61 6d 65 20 3d 20 74 65 6d 70 file_name = temp
35b0: 5f 6e 61 6d 65 0a 0a 09 09 09 77 69 74 68 20 6f _name.....with o
35c0: 70 65 6e 28 66 69 6c 65 5f 6e 61 6d 65 2c 20 27 pen(file_name, '
35d0: 72 62 27 29 20 61 73 20 72 65 61 6c 5f 66 69 6c rb') as real_fil
35e0: 65 3a 0a 09 09 09 09 66 69 6c 65 5f 73 74 61 74 e:.....file_stat
35f0: 20 3d 20 6f 73 2e 73 74 61 74 28 66 69 6c 65 5f = os.stat(file_
3600: 6e 61 6d 65 29 0a 09 09 09 09 69 66 20 27 52 61 name).....if 'Ra
3610: 6e 67 65 27 20 69 6e 20 73 65 6c 66 2e 68 65 61 nge' in self.hea
3620: 64 65 72 73 3a 0a 09 09 09 09 09 73 65 6c 66 2e ders:......self.
3630: 73 65 6e 64 5f 72 65 73 70 6f 6e 73 65 28 32 30 send_response(20
3640: 36 29 0a 09 09 09 09 09 72 61 6e 67 65 73 20 3d 6)......ranges =
3650: 20 28 29 0a 09 09 09 09 09 72 65 71 75 65 73 74 ()......request
3660: 65 64 5f 72 61 6e 67 65 73 2e 72 65 77 69 6e 64 ed_ranges.rewind
3670: 28 29 0a 09 09 09 09 09 77 68 69 6c 65 20 54 72 ()......while Tr
3680: 75 65 3a 0a 09 09 09 09 09 09 70 61 69 72 20 3d ue:.......pair =
3690: 20 72 65 71 75 65 73 74 65 64 5f 72 61 6e 67 65 requested_range
36a0: 73 2e 70 6f 70 28 29 0a 09 09 09 09 09 09 69 66 s.pop().......if
36b0: 20 70 61 69 72 5b 30 5d 20 3d 3d 20 4e 6f 6e 65 pair[0] == None
36c0: 3a 0a 09 09 09 09 09 09 09 62 72 65 61 6b 0a 09 :........break..
36d0: 09 09 09 09 09 72 61 6e 67 65 73 20 2b 3d 20 27 .....ranges += '
36e0: 7b 7d 2d 7b 7d 27 2e 66 6f 72 6d 61 74 28 70 61 {}-{}'.format(pa
36f0: 69 72 5b 30 5d 2c 20 73 74 72 28 70 61 69 72 5b ir[0], str(pair[
3700: 31 5d 20 2d 20 31 29 29 2c 0a 09 09 09 09 09 73 1] - 1)),......s
3710: 65 6c 66 2e 73 65 6e 64 5f 68 65 61 64 65 72 28 elf.send_header(
3720: 27 43 6f 6e 74 65 6e 74 2d 52 61 6e 67 65 27 2c 'Content-Range',
3730: 20 27 62 79 74 65 73 20 7b 7d 2f 7b 7d 27 2e 66 'bytes {}/{}'.f
3740: 6f 72 6d 61 74 28 27 2c 27 2e 6a 6f 69 6e 28 72 ormat(','.join(r
3750: 61 6e 67 65 73 29 2c 20 69 6e 64 65 78 5b 6d 79 anges), index[my
3760: 5f 70 61 74 68 5f 62 5d 5b 27 43 6f 6e 74 65 6e _path_b]['Conten
3770: 74 2d 4c 65 6e 67 74 68 27 5d 29 29 0a 09 09 09 t-Length']))....
3780: 09 65 6c 73 65 3a 0a 09 09 09 09 09 73 65 6c 66 .else:......self
3790: 2e 73 65 6e 64 5f 72 65 73 70 6f 6e 73 65 28 32 .send_response(2
37a0: 30 30 29 0a 09 09 09 09 09 73 65 6c 66 2e 73 65 00)......self.se
37b0: 6e 64 5f 68 65 61 64 65 72 28 27 43 6f 6e 74 65 nd_header('Conte
37c0: 6e 74 2d 4c 65 6e 67 74 68 27 2c 20 73 74 72 28 nt-Length', str(
37d0: 66 69 6c 65 5f 73 74 61 74 2e 73 74 5f 73 69 7a file_stat.st_siz
37e0: 65 29 29 0a 09 09 09 09 09 72 65 71 75 65 73 74 e))......request
37f0: 65 64 5f 72 61 6e 67 65 73 20 3d 20 73 70 61 63 ed_ranges = spac
3800: 65 6d 61 70 2e 53 70 61 63 65 4d 61 70 28 7b 30 emap.SpaceMap({0
3810: 3a 20 66 69 6c 65 5f 73 74 61 74 2e 73 74 5f 73 : file_stat.st_s
3820: 69 7a 65 7d 29 0a 09 09 09 09 69 66 20 27 4c 61 ize}).....if 'La
3830: 73 74 2d 4d 6f 64 69 66 69 65 64 27 20 69 6e 20 st-Modified' in
3840: 69 6e 64 65 78 5b 6d 79 5f 70 61 74 68 5f 62 5d index[my_path_b]
3850: 3a 0a 09 09 09 09 09 73 65 6c 66 2e 73 65 6e 64 :......self.send
3860: 5f 68 65 61 64 65 72 28 27 4c 61 73 74 2d 4d 6f _header('Last-Mo
3870: 64 69 66 69 65 64 27 2c 20 69 6e 64 65 78 5b 6d dified', index[m
3880: 79 5f 70 61 74 68 5f 62 5d 5b 27 4c 61 73 74 2d y_path_b]['Last-
3890: 4d 6f 64 69 66 69 65 64 27 5d 29 0a 09 09 09 09 Modified']).....
38a0: 73 65 6c 66 2e 73 65 6e 64 5f 68 65 61 64 65 72 self.send_header
38b0: 28 27 43 6f 6e 74 65 6e 74 2d 54 79 70 65 27 2c ('Content-Type',
38c0: 20 27 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6f 63 'application/oc
38d0: 74 65 74 2d 73 74 72 65 61 6d 27 29 0a 09 09 09 tet-stream')....
38e0: 09 73 65 6c 66 2e 65 6e 64 5f 68 65 61 64 65 72 .self.end_header
38f0: 73 28 29 0a 09 09 09 09 69 66 20 73 65 6c 66 2e s().....if self.
3900: 63 6f 6d 6d 61 6e 64 20 69 6e 20 28 27 47 45 54 command in ('GET
3910: 27 29 3a 0a 09 09 09 09 09 69 66 20 6c 65 6e 28 '):......if len(
3920: 72 65 71 75 65 73 74 65 64 5f 72 61 6e 67 65 73 requested_ranges
3930: 29 20 3e 20 30 3a 0a 09 09 09 09 09 09 72 65 71 ) > 0:.......req
3940: 75 65 73 74 65 64 5f 72 61 6e 67 65 73 2e 72 65 uested_ranges.re
3950: 77 69 6e 64 28 29 0a 09 09 09 09 09 09 28 73 74 wind().......(st
3960: 61 72 74 2c 20 65 6e 64 29 20 3d 20 72 65 71 75 art, end) = requ
3970: 65 73 74 65 64 5f 72 61 6e 67 65 73 2e 70 6f 70 ested_ranges.pop
3980: 28 29 0a 09 09 09 09 09 65 6c 73 65 3a 0a 09 09 ()......else:...
3990: 09 09 09 09 73 74 61 72 74 20 3d 20 30 0a 09 09 ....start = 0...
39a0: 09 09 09 09 23 20 58 58 58 20 75 67 6c 79 20 68 ....# XXX ugly h
39b0: 61 63 6b 0a 09 09 09 09 09 09 69 66 20 27 43 6f ack.......if 'Co
39c0: 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 27 20 69 6e ntent-Length' in
39d0: 20 69 6e 64 65 78 5b 6d 79 5f 70 61 74 68 5f 62 index[my_path_b
39e0: 5d 3a 0a 09 09 09 09 09 09 09 65 6e 64 20 3d 20 ]:........end =
39f0: 69 6e 64 65 78 5b 6d 79 5f 70 61 74 68 5f 62 5d index[my_path_b]
3a00: 5b 27 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 ['Content-Length
3a10: 27 5d 0a 09 09 09 09 09 09 65 6c 73 65 3a 0a 09 '].......else:..
3a20: 09 09 09 09 09 09 65 6e 64 20 3d 20 30 0a 09 09 ......end = 0...
3a30: 09 09 09 72 65 61 6c 5f 66 69 6c 65 2e 73 65 65 ...real_file.see
3a40: 6b 28 73 74 61 72 74 29 0a 09 09 09 09 09 69 66 k(start)......if
3a50: 20 62 6c 6f 63 6b 5f 73 69 7a 65 20 3e 20 65 6e block_size > en
3a60: 64 20 2d 20 73 74 61 72 74 3a 0a 09 09 09 09 09 d - start:......
3a70: 09 72 65 71 5f 62 6c 6f 63 6b 5f 73 69 7a 65 20 .req_block_size
3a80: 3d 20 65 6e 64 20 2d 20 73 74 61 72 74 0a 09 09 = end - start...
3a90: 09 09 09 65 6c 73 65 3a 0a 09 09 09 09 09 09 72 ...else:.......r
3aa0: 65 71 5f 62 6c 6f 63 6b 5f 73 69 7a 65 20 3d 20 eq_block_size =
3ab0: 62 6c 6f 63 6b 5f 73 69 7a 65 0a 09 09 09 09 09 block_size......
3ac0: 62 75 66 66 65 72 20 3d 20 72 65 61 6c 5f 66 69 buffer = real_fi
3ad0: 6c 65 2e 72 65 61 64 28 72 65 71 5f 62 6c 6f 63 le.read(req_bloc
3ae0: 6b 5f 73 69 7a 65 29 0a 09 09 09 09 09 6c 65 6e k_size)......len
3af0: 67 74 68 20 3d 20 6c 65 6e 28 62 75 66 66 65 72 gth = len(buffer
3b00: 29 0a 09 09 09 09 09 77 68 69 6c 65 20 6c 65 6e )......while len
3b10: 67 74 68 20 3e 20 30 3a 0a 09 09 09 09 09 09 73 gth > 0:.......s
3b20: 65 6c 66 2e 77 66 69 6c 65 2e 77 72 69 74 65 28 elf.wfile.write(
3b30: 62 75 66 66 65 72 29 0a 09 09 09 09 09 09 73 74 buffer).......st
3b40: 61 72 74 20 2b 3d 20 6c 65 6e 28 62 75 66 66 65 art += len(buffe
3b50: 72 29 0a 09 09 09 09 09 09 69 66 20 72 65 71 5f r).......if req_
3b60: 62 6c 6f 63 6b 5f 73 69 7a 65 20 3e 20 65 6e 64 block_size > end
3b70: 20 2d 20 73 74 61 72 74 3a 0a 09 09 09 09 09 09 - start:.......
3b80: 09 72 65 71 5f 62 6c 6f 63 6b 5f 73 69 7a 65 20 .req_block_size
3b90: 3d 20 65 6e 64 20 2d 20 73 74 61 72 74 0a 09 09 = end - start...
3ba0: 09 09 09 09 69 66 20 72 65 71 5f 62 6c 6f 63 6b ....if req_block
3bb0: 5f 73 69 7a 65 20 3d 3d 20 30 3a 0a 09 09 09 09 _size == 0:.....
3bc0: 09 09 09 62 72 65 61 6b 0a 09 09 09 09 09 09 62 ...break.......b
3bd0: 75 66 66 65 72 20 3d 20 72 65 61 6c 5f 66 69 6c uffer = real_fil
3be0: 65 2e 72 65 61 64 28 72 65 71 5f 62 6c 6f 63 6b e.read(req_block
3bf0: 5f 73 69 7a 65 29 0a 09 09 09 09 09 09 6c 65 6e _size).......len
3c00: 67 74 68 20 3d 20 6c 65 6e 28 62 75 66 66 65 72 gth = len(buffer
3c10: 29 0a 09 09 09 09 0a 09 64 65 66 20 64 6f 5f 48 ).......def do_H
3c20: 45 41 44 28 73 65 6c 66 29 3a 0a 09 09 72 65 74 EAD(self):...ret
3c30: 75 72 6e 20 73 65 6c 66 2e 5f 5f 70 72 6f 63 65 urn self.__proce
3c40: 73 73 28 29 0a 09 64 65 66 20 64 6f 5f 47 45 54 ss()..def do_GET
3c50: 28 73 65 6c 66 29 3a 0a 09 09 72 65 74 75 72 6e (self):...return
3c60: 20 73 65 6c 66 2e 5f 5f 70 72 6f 63 65 73 73 28 self.__process(
3c70: 29 0a 0a 73 65 72 76 65 72 20 3d 20 68 74 74 70 )..server = http
3c80: 2e 73 65 72 76 65 72 2e 48 54 54 50 53 65 72 76 .server.HTTPServ
3c90: 65 72 28 28 27 31 32 37 2e 30 2e 30 2e 31 27 2c er(('127.0.0.1',
3ca0: 20 69 6e 74 28 63 6f 6e 66 69 67 5b 27 44 45 46 int(config['DEF
3cb0: 41 55 4c 54 27 5d 5b 27 70 6f 72 74 27 5d 29 29 AULT']['port']))
3cc0: 2c 20 4d 79 52 65 71 75 65 73 74 48 61 6e 64 6c , MyRequestHandl
3cd0: 65 72 29 0a 73 65 72 76 65 72 2e 73 65 72 76 65 er).server.serve
3ce0: 5f 66 6f 72 65 76 65 72 28 29 0a 0a 23 67 65 76 _forever()..#gev
3cf0: 65 6e 74 2e 6a 6f 69 6e 61 6c 6c 28 29 0a ent.joinall().