151
151
req.status = req.HTTP_FORBIDDEN
152
152
req.headers_out['X-IVLE-Return-Error'] = 'Forbidden'
153
153
req.write("Forbidden")
154
elif not os.access(path, os.R_OK):
155
req.status = req.HTTP_NOT_FOUND
156
req.headers_out['X-IVLE-Return-Error'] = 'File not found'
157
req.write("File not found")
158
elif os.path.isdir(path):
156
# If this is a repository-revision request, it needs to be treated
157
# differently than if it were a regular file request.
158
# Note: If there IS a revision requested but the file doesn't exist in
159
# that revision, this will terminate.
160
revision = _get_revision_or_die(req, svnclient, path)
163
if not os.access(path, os.R_OK):
164
req.status = req.HTTP_NOT_FOUND
165
req.headers_out['X-IVLE-Return-Error'] = 'File not found'
166
req.write("File not found")
168
is_dir = os.path.isdir(path)
170
is_dir = ivle.svn.revision_is_dir(svnclient, path, revision)
159
173
# It's a directory. Return the directory listing.
160
174
req.content_type = mime_dirlisting
161
175
req.headers_out['X-IVLE-Return'] = 'Dir'
162
176
# TODO: Fix this dirty, dirty hack
163
newjson = get_dirlisting(req, svnclient, path)
177
newjson = get_dirlisting(req, svnclient, path, revision)
164
178
if ("X-IVLE-Action-Error" in req.headers_out):
165
179
newjson["Error"] = req.headers_out["X-IVLE-Action-Error"]
166
180
req.write(cjson.encode(newjson))
167
181
elif return_contents:
168
182
# It's a file. Return the file contents.
169
183
# First get the mime type of this file
170
# (Note that importing ivle.util has already initialised mime types)
171
184
(type, _) = mimetypes.guess_type(path)
173
type = ivle.conf.mimetypes.default_mimetype
186
type = ivle.mimetypes.DEFAULT_MIMETYPE
174
187
req.content_type = type
175
188
req.headers_out['X-IVLE-Return'] = 'File'
177
send_file(req, svnclient, path)
190
send_file(req, svnclient, path, revision)
179
192
# It's a file. Return a "fake directory listing" with just this file.
180
193
req.content_type = mime_dirlisting
181
194
req.headers_out['X-IVLE-Return'] = 'File'
182
req.write(cjson.encode(get_dirlisting(req, svnclient, path)))
195
req.write(cjson.encode(get_dirlisting(req, svnclient, path,
184
198
def _get_revision_or_die(req, svnclient, path):
185
'''Looks for a revision specification in req's URL, returning the revision
186
specified. Returns None if there was no revision specified. Errors and
187
terminates the request if the specification was bad, or it doesn't exist
199
"""Looks for a revision specification in req's URL.
200
Errors and terminates the request if the specification was bad, or it
201
doesn't exist for the given path.
202
@param req: Request object.
203
@param svnclient: pysvn Client object.
204
@param path: Path to the file whose revision is to be retrieved.
205
@returns: pysvn Revision object, for the file+revision specified, or None
206
if there was no revision specified.
190
208
# Work out the revisions from query
191
209
r_str = req.get_fieldstorage().getfirst("r")
192
210
revision = ivle.svn.revision_from_string(r_str)
195
213
if r_str and not (revision and
196
214
ivle.svn.revision_exists(svnclient, path, revision)):
197
215
req.status = req.HTTP_NOT_FOUND
198
req.headers_out['X-IVLE-Return-Error'] = 'Revision not found'
216
message = ('Revision not found or file not found in revision %d' %
218
req.headers_out['X-IVLE-Return-Error'] = message
199
219
req.ensure_headers_written()
200
req.write('Revision not found')
205
def send_file(req, svnclient, path):
206
revision = _get_revision_or_die(req, svnclient, path)
225
def send_file(req, svnclient, path, revision):
226
"""Given a local absolute path to a file, sends the contents of the file
229
@param req: Request object. Will not be mutated; just reads the session.
230
@param svnclient: Svn client object.
231
@param path: String. Absolute path on the local file system. Not checked,
232
must already be guaranteed safe. May be a file or a directory.
233
@param revision: pysvn Revision object for the given path, or None.
208
236
req.write(svnclient.cat(path, revision=revision))
210
238
req.sendfile(path)
212
def get_dirlisting(req, svnclient, path):
240
def get_dirlisting(req, svnclient, path, revision):
213
241
"""Given a local absolute path, creates a directory listing object
214
242
ready to be JSONized and sent to the client.
216
req: Request object. Will not be mutated; just reads the session.
217
svnclient: Svn client object.
218
path: String. Absolute path on the local file system. Not checked,
244
@param req: Request object. Will not be mutated; just reads the session.
245
@param svnclient: Svn client object.
246
@param path: String. Absolute path on the local file system. Not checked,
219
247
must already be guaranteed safe. May be a file or a directory.
248
@param revision: pysvn Revision object for the given path, or None.
222
revision = _get_revision_or_die(req, svnclient, path)
224
251
# Start by trying to do an SVN status, so we can report file version