]>
Commit | Line | Data |
---|---|---|
818a4490 | 1 | #!/usr/bin/python |
2 | ############################################################################### | |
3 | # # | |
4 | # IPFire.org - A linux based firewall # | |
5 | # Copyright (C) 2007 Michael Tremer & Christian Schmidt # | |
6 | # # | |
7 | # This program is free software: you can redistribute it and/or modify # | |
8 | # it under the terms of the GNU General Public License as published by # | |
9 | # the Free Software Foundation, either version 3 of the License, or # | |
10 | # (at your option) any later version. # | |
11 | # # | |
12 | # This program is distributed in the hope that it will be useful, # | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
15 | # GNU General Public License for more details. # | |
16 | # # | |
17 | # You should have received a copy of the GNU General Public License # | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
19 | # # | |
20 | ############################################################################### | |
21 | ||
22 | import os | |
23 | import cgi | |
516a72ab MT |
24 | import sys |
25 | import sha | |
26 | from pysqlite2 import dbapi2 as sqlite | |
27 | ||
28 | sys.path.append(".") | |
29 | ||
818a4490 | 30 | from git import * |
31 | ||
141ef101 MT |
32 | SOURCE_BASE = "/srv/sources" |
33 | ||
6a170c4e MT |
34 | def give_403(): |
35 | print "Status: 403 Forbidden" | |
36 | print "Pragma: no-cache" | |
37 | print "Cache-control: no-cache" | |
38 | print "Connection: close" | |
39 | ||
40 | ||
516a72ab | 41 | sys.exit() |
6a170c4e | 42 | |
818a4490 | 43 | def give_404(): |
44 | print "Status: 404 Not found" | |
45 | print "Pragma: no-cache" | |
46 | print "Cache-control: no-cache" | |
47 | print "Connection: close" | |
48 | ||
6a170c4e | 49 | |
516a72ab | 50 | sys.exit() |
818a4490 | 51 | |
52 | def give_302(): | |
53 | print "Status: 302 Moved" | |
54 | print "Location: /" | |
55 | print "Pragma: no-cache" | |
56 | print "Cache-control: no-cache" | |
57 | print "Connection: close" | |
58 | ||
59 | ||
516a72ab | 60 | sys.exit() |
818a4490 | 61 | |
62 | class NotFoundError(Exception): | |
63 | pass | |
64 | ||
65 | class SourceObject: | |
516a72ab MT |
66 | def __init__(self, file): |
67 | self.file = file | |
68 | ||
69 | self.db = sqlite.connect("hashes.db") | |
70 | c = self.db.cursor() | |
71 | c.execute("CREATE TABLE IF NOT EXISTS hashes(file, sha1)") | |
72 | c.close() | |
73 | ||
74 | def getHash(self, type="sha1"): | |
75 | hash = None | |
76 | c = self.db.cursor() | |
77 | c.execute("SELECT %s FROM hashes WHERE file = '%s'" % (type, self.file,)) | |
78 | try: | |
79 | hash = c.fetchone()[0] | |
80 | except TypeError: | |
81 | pass | |
82 | c.close() | |
83 | ||
84 | if not hash: | |
85 | hash = sha.new(self.filedata).hexdigest() | |
86 | c = self.db.cursor() | |
87 | c.execute("INSERT INTO hashes(file, sha1) VALUES('%s', '%s')" % \ | |
88 | (self.file, hash,)) | |
89 | c.close() | |
90 | self.db.commit() | |
91 | return hash | |
92 | ||
93 | def __call__(self): | |
94 | print "Status: 200 - OK" | |
818a4490 | 95 | print "Pragma: no-cache" |
96 | print "Cache-control: no-cache" | |
97 | print "Connection: close" | |
516a72ab MT |
98 | print "Content-type: " + self.getMimetype() |
99 | print "Content-length: %s" % len(self.filedata) | |
100 | print "X-SHA1: " + self.getHash("sha1") | |
101 | print "X-Object: %s" % str(self.__class__).split(".")[1] | |
102 | print # An empty line ends the header | |
103 | print self.filedata | |
104 | ||
818a4490 | 105 | |
106 | class FileObject(SourceObject): | |
516a72ab MT |
107 | def __init__(self, path, file): |
108 | SourceObject.__init__(self, file) | |
109 | self.path = path | |
141ef101 | 110 | self.filepath = "/%s/%s/%s" % (SOURCE_BASE, path, file,) |
516a72ab | 111 | |
818a4490 | 112 | try: |
113 | f = open(self.filepath, "rb") | |
114 | except: | |
115 | raise NotFoundError | |
116 | ||
117 | self.filedata = f.read() | |
118 | f.close() | |
119 | ||
516a72ab | 120 | def getMimetype(self): |
818a4490 | 121 | default_mimetype = "text/plain" |
122 | from mimetypes import guess_type | |
123 | return guess_type(self.filepath)[0] or default_mimetype | |
124 | ||
818a4490 | 125 | |
516a72ab MT |
126 | class PatchObject(SourceObject): |
127 | def __init__(self, file, url="/srv/git/patches.git"): | |
128 | SourceObject.__init__(self, file) | |
818a4490 | 129 | self.url = url |
818a4490 | 130 | |
818a4490 | 131 | self.repo = Repository(self.url) |
516a72ab | 132 | tree = self.repo.head.tree |
818a4490 | 133 | blob = None |
516a72ab MT |
134 | |
135 | for directory in tree.keys(): | |
136 | if isinstance(tree[directory], Blob): | |
818a4490 | 137 | continue |
138 | try: | |
516a72ab | 139 | blob = tree[directory][self.file] |
818a4490 | 140 | if blob: |
141 | break | |
142 | except KeyError: | |
143 | pass | |
516a72ab | 144 | |
818a4490 | 145 | if not blob: |
146 | raise NotFoundError | |
147 | ||
148 | blob._load() | |
149 | self.filedata = blob._contents | |
520933d9 | 150 | self.filedata += '\n' |
818a4490 | 151 | |
516a72ab MT |
152 | def getMimetype(self): |
153 | return "text/plain" | |
818a4490 | 154 | |
728dfc54 | 155 | |
516a72ab MT |
156 | def main(): |
157 | os.environ["QUERY_STRING"] = \ | |
158 | os.environ["QUERY_STRING"].replace("+", "%2b") | |
818a4490 | 159 | |
516a72ab MT |
160 | file = cgi.FieldStorage().getfirst("file") |
161 | path = cgi.FieldStorage().getfirst("path") | |
6a170c4e | 162 | |
516a72ab MT |
163 | if not os.environ["HTTP_USER_AGENT"].startswith("IPFireSourceGrabber"): |
164 | give_403() | |
818a4490 | 165 | |
516a72ab MT |
166 | if not file: |
167 | give_302() | |
818a4490 | 168 | |
afbaaece | 169 | if not path or path == "download": |
516a72ab MT |
170 | path = "source-3.x" |
171 | ||
172 | # At first, we assume that the requested object is a plain file: | |
818a4490 | 173 | try: |
516a72ab | 174 | object = FileObject(path=path, file=file) |
818a4490 | 175 | except NotFoundError: |
516a72ab MT |
176 | # Second, we assume that the requestet object is in the patch repo: |
177 | try: | |
178 | object = PatchObject(file=file) | |
179 | except NotFoundError: | |
180 | give_404() | |
181 | else: | |
182 | object() | |
818a4490 | 183 | else: |
516a72ab MT |
184 | object() |
185 | ||
186 | try: | |
187 | main() | |
188 | except SystemExit: | |
189 | pass |