hgext/lfs/wireprotolfsserver.py
changeset 41425 6d7f18cd81d9
parent 41424 7a11e4e55d5f
child 43076 2372284d9457
equal deleted inserted replaced
41424:7a11e4e55d5f 41425:6d7f18cd81d9
   131 
   131 
   132     # XXX: specify an encoding?
   132     # XXX: specify an encoding?
   133     lfsreq = json.loads(req.bodyfh.read())
   133     lfsreq = json.loads(req.bodyfh.read())
   134 
   134 
   135     # If no transfer handlers are explicitly requested, 'basic' is assumed.
   135     # If no transfer handlers are explicitly requested, 'basic' is assumed.
   136     if 'basic' not in lfsreq.get('transfers', ['basic']):
   136     if r'basic' not in lfsreq.get(r'transfers', [r'basic']):
   137         _sethttperror(res, HTTP_BAD_REQUEST,
   137         _sethttperror(res, HTTP_BAD_REQUEST,
   138                       b'Only the basic LFS transfer handler is supported')
   138                       b'Only the basic LFS transfer handler is supported')
   139         return True
   139         return True
   140 
   140 
   141     operation = lfsreq.get('operation')
   141     operation = lfsreq.get(r'operation')
   142     if operation not in ('upload', 'download'):
   142     operation = pycompat.bytestr(operation)
       
   143 
       
   144     if operation not in (b'upload', b'download'):
   143         _sethttperror(res, HTTP_BAD_REQUEST,
   145         _sethttperror(res, HTTP_BAD_REQUEST,
   144                       b'Unsupported LFS transfer operation: %s' % operation)
   146                       b'Unsupported LFS transfer operation: %s' % operation)
   145         return True
   147         return True
   146 
   148 
   147     localstore = repo.svfs.lfslocalblobstore
   149     localstore = repo.svfs.lfslocalblobstore
   148 
   150 
   149     objects = [p for p in _batchresponseobjects(req, lfsreq.get('objects', []),
   151     objects = [p for p in _batchresponseobjects(req, lfsreq.get(r'objects', []),
   150                                                 operation, localstore)]
   152                                                 operation, localstore)]
   151 
   153 
   152     rsp = {
   154     rsp = {
   153         'transfer': 'basic',
   155         r'transfer': r'basic',
   154         'objects': objects,
   156         r'objects': objects,
   155     }
   157     }
   156 
   158 
   157     res.status = hgwebcommon.statusmessage(HTTP_OK)
   159     res.status = hgwebcommon.statusmessage(HTTP_OK)
   158     res.headers[b'Content-Type'] = b'application/vnd.git-lfs+json'
   160     res.headers[b'Content-Type'] = b'application/vnd.git-lfs+json'
   159     res.setbodybytes(pycompat.bytestr(json.dumps(rsp)))
   161     res.setbodybytes(pycompat.bytestr(json.dumps(rsp)))
   188 
   190 
   189     # TODO: Sort out the expires_at/expires_in/authenticated keys.
   191     # TODO: Sort out the expires_at/expires_in/authenticated keys.
   190 
   192 
   191     for obj in objects:
   193     for obj in objects:
   192         # Convert unicode to ASCII to create a filesystem path
   194         # Convert unicode to ASCII to create a filesystem path
   193         oid = obj.get('oid').encode('ascii')
   195         soid = obj.get(r'oid')
       
   196         oid = soid.encode(r'ascii')
   194         rsp = {
   197         rsp = {
   195             'oid': oid,
   198             r'oid': soid,
   196             'size': obj.get('size'),  # XXX: should this check the local size?
   199             r'size': obj.get(r'size'),  # XXX: should this check the local size?
   197             #'authenticated': True,
   200             #r'authenticated': True,
   198         }
   201         }
   199 
   202 
   200         exists = True
   203         exists = True
   201         verifies = False
   204         verifies = False
   202 
   205 
   215                 store.linkfromusercache(oid)
   218                 store.linkfromusercache(oid)
   216         except IOError as inst:
   219         except IOError as inst:
   217             if inst.errno != errno.ENOENT:
   220             if inst.errno != errno.ENOENT:
   218                 _logexception(req)
   221                 _logexception(req)
   219 
   222 
   220                 rsp['error'] = {
   223                 rsp[r'error'] = {
   221                     'code': 500,
   224                     r'code': 500,
   222                     'message': inst.strerror or 'Internal Server Server'
   225                     r'message': inst.strerror or r'Internal Server Server'
   223                 }
   226                 }
   224                 yield rsp
   227                 yield rsp
   225                 continue
   228                 continue
   226 
   229 
   227             exists = False
   230             exists = False
   228 
   231 
   229         # Items are always listed for downloads.  They are dropped for uploads
   232         # Items are always listed for downloads.  They are dropped for uploads
   230         # IFF they already exist locally.
   233         # IFF they already exist locally.
   231         if action == b'download':
   234         if action == b'download':
   232             if not exists:
   235             if not exists:
   233                 rsp['error'] = {
   236                 rsp[r'error'] = {
   234                     'code': 404,
   237                     r'code': 404,
   235                     'message': "The object does not exist"
   238                     r'message': r"The object does not exist"
   236                 }
   239                 }
   237                 yield rsp
   240                 yield rsp
   238                 continue
   241                 continue
   239 
   242 
   240             elif not verifies:
   243             elif not verifies:
   241                 rsp['error'] = {
   244                 rsp[r'error'] = {
   242                     'code': 422,   # XXX: is this the right code?
   245                     r'code': 422,   # XXX: is this the right code?
   243                     'message': "The object is corrupt"
   246                     r'message': r"The object is corrupt"
   244                 }
   247                 }
   245                 yield rsp
   248                 yield rsp
   246                 continue
   249                 continue
   247 
   250 
   248         elif verifies:
   251         elif verifies:
   254         def _buildheader():
   257         def _buildheader():
   255             # The spec doesn't mention the Accept header here, but avoid
   258             # The spec doesn't mention the Accept header here, but avoid
   256             # a gratuitous deviation from lfs-test-server in the test
   259             # a gratuitous deviation from lfs-test-server in the test
   257             # output.
   260             # output.
   258             hdr = {
   261             hdr = {
   259                 'Accept': 'application/vnd.git-lfs'
   262                 r'Accept': r'application/vnd.git-lfs'
   260             }
   263             }
   261 
   264 
   262             auth = req.headers.get(b'Authorization', b'')
   265             auth = req.headers.get(b'Authorization', b'')
   263             if auth.startswith(b'Basic '):
   266             if auth.startswith(b'Basic '):
   264                 hdr['Authorization'] = auth
   267                 hdr[r'Authorization'] = pycompat.strurl(auth)
   265 
   268 
   266             return hdr
   269             return hdr
   267 
   270 
   268         rsp['actions'] = {
   271         rsp[r'actions'] = {
   269             '%s' % action: {
   272             r'%s' % pycompat.strurl(action): {
   270                 'href': '%s%s/.hg/lfs/objects/%s'
   273                 r'href': pycompat.strurl(b'%s%s/.hg/lfs/objects/%s'
   271                     % (req.baseurl, req.apppath, oid),
   274                     % (req.baseurl, req.apppath, oid)),
   272                 # datetime.isoformat() doesn't include the 'Z' suffix
   275                 # datetime.isoformat() doesn't include the 'Z' suffix
   273                 "expires_at": expiresat.strftime('%Y-%m-%dT%H:%M:%SZ'),
   276                 r"expires_at": expiresat.strftime(r'%Y-%m-%dT%H:%M:%SZ'),
   274                 'header': _buildheader(),
   277                 r'header': _buildheader(),
   275             }
   278             }
   276         }
   279         }
   277 
   280 
   278         yield rsp
   281         yield rsp
   279 
   282