예제 #1
0
 def do_GET(self, serv):
   qs = get_qs(serv.path)
   
   if "accessToken" not in qs or ("path" not in qs and "id" not in qs):
     serv.send_error(400)
     return
   
   tok = qs["accessToken"][0]
   userid = do_auth(tok)
   
   if userid == None:
     serv.send_error(401)
     return
   
   if "path" in qs:
     fileid = resolve_path(qs["path"][0])
   else:
     fileid = publicid_to_fileid(qs["id"][0])[1]
   
   if fileid == None:
     serv.send_error(400)
   
   if fileid == None:
     serv.send_error(400)
   
   f = fetch_file(fileid)
   if f == None:
     serv.send_error(400)
     return
   
   if f["userid"] != userid:
     serv.send_error(401)
     return
   
   f2 = {}
   for k in f:
     if k in file_restricted_fields: continue
     
     if k == "fileid":
       f2["id"] = fileid_to_publicid(fileid, userid)
       continue
     if k == "other_meta" and f[k] != "" and f[k] != None:
       try:
         meta = json.loads(f[k])
       except ValueError:
         meta = {}
       
       for k2 in meta:
         f2[k2] = estr(meta[k2])
       continue
     
     f2[k] = estr(f[k])
       
   f2["is_dir"] = f2["mimeType"] == FOLDER_MIME
   
   body = json.dumps(f2)
   body = bstr(body)
   
   serv.gen_headers("GET", len(body), json_mimetype)
   serv.wfile.write(body)
예제 #2
0
 def do_GET(self, serv):
   qs = get_qs(serv.path)
   if "accessToken" not in qs or ("path" not in qs and "id" not in qs):
     serv.send_error(400)
     return
   
   tok = qs["accessToken"][0]
   userid = do_auth(tok)
   
   if userid == None:
     serv.send_error(401)
     return
   
   if "path" in qs:
     fileid = resolve_path(qs["path"][0])
   else:
     fileid = publicid_to_fileid(qs["id"][0])[1]
   
   if fileid == None:
     serv.send_error(404)
     return
     
   alog("fetching file %s" % fileid);
   f = fetch_file(fileid)
   if f == None:
     serv.send_error(400)
     return
   
   if is_folder(f):
     serv.send_error(401)
     return
     
   if f["userid"] != userid:
     serv.send_error(401)
     return
   
   try:
     file = open(f["diskpath"], "rb")    
   except OSError:
     serv.send_error(404)
     return
   
   body = file.read()
   file.close()
   
   serv.gen_headers("GET", len(body), "application/octet-stream")
   serv.send_header("Content-Disposition", "attachment; filename=\"%s\"" % f["name"])
   #Content-Disposition: attachment; filename=FILENAME
   
   serv.wfile.write(body)
예제 #3
0
    def do_GET(self, serv):
        qs = get_qs(serv.path)
        if "refreshToken" not in qs:
            serv.send_error(400)
            return

        token = qs["refreshToken"][0]

        cur, con = mysql_connect()
        cur.execute("SELECT * FROM authtokens WHERE tokenid=" + estr(token))

        ret = cur.fetchone()
        if ret == None:
            serv.send_error(401)
            return

        exprtime1 = ensure_datetime(ret["expiration"])

        if exprtime1 < datetime.datetime.now():
            alog("Expired token %s" % (token))
            serv.send_error(408)
            return

        userid = ret["userid"]
        tok = gen_token("A", userid)
        exprtime = datetime.datetime.now() + datetime.timedelta(hours=2)

        alog("Generated session token %s for user %s" % (tok, str(userid)))

        cols = ["tokenid", "userid", "type", "permissions", "expiration"]
        values = [tok, userid, toktypes["A"], default_permission, exprtime]
        types = [sq.token, sq.int, sq.int, sq.int, sq.datetime]

        try:
            qstr = sql_insertinto("authtokens", cols, values, types)
        except SQLParamError:
            do_param_error("cols: " + str(cols) + ", values:" + str(values))
            serv.send_error(401)
            return

        cur.execute(qstr)
        con.commit()

        body = json.dumps({"access_token": str(tok)})
        body = bstr(body)

        serv.gen_headers("GET", len(body), json_mimetype)
        serv.wfile.write(body)
예제 #4
0
  def do_GET(self, serv):
    qs = get_qs(serv.path)
    if "accessToken" not in qs or ("path" not in qs and "id" not in qs):
      serv.send_error(400)
      return
    
    tok = qs["accessToken"][0]
    userid = do_auth(tok)
    
    if userid == None:
      serv.send_error(401)
      return
    
    if "path" in qs:
      path = qs["path"][0]
    else:
      path = publicid_to_fileid(qs["id"][0])
    
    if path == None:
      serv.send_error(404)
      return
      
    alog("fetching file %s" % path);
    f = File(path, userid)
    
    if f == None:
      serv.send_error(400)
      return
    
    if is_folder(f):
      serv.send_error(401)
      return

    print("diskpath:", f.diskpath)
    try:
      file = open(f.diskpath, "rb")    
    except OSError:
      serv.send_error(404)
      return
    
    body = file.read()
    file.close()
    
    serv.gen_headers("GET", len(body), "application/octet-stream")
    serv.send_header("Content-Disposition", "attachment; filename=\"%s\"" % f.name)
    #Content-Disposition: attachment; filename=FILENAME
    
    serv.wfile.write(body)
예제 #5
0
    def do_GET(self, serv):
        global OAUTH_SCOPES

        qs = get_qs(serv.path)
        qs2 = {}
        for k in qs:
            if type(qs[k]) in [list, tuple] and len(qs[k]) == 1:
                qs2[k] = qs[k][0]
            else:
                qs2[k] = qs[k]
        qs = qs2

        if "response_type" not in qs or "client_id" not in qs:
            alog("Invaild oauth request 1")
            serv.send_error(400)
            return

        if qs["response_type"] != "code":
            alog("Invaild oauth request 2")
            serv.send_error(400)
            return

        if "redirect_uri" in qs:
            self.redirect_uri = qs["redirect_uri"]

        scope = ""
        if "scope" in qs:
            scope = qs["scope"]

        state = None
        if "state" in qs:
            state = qs["state"]

        restype = qs["response_type"]
        clientid = qs["client_id"]

        if clientid not in self.valid_clients:
            alog("Invaild client id in oauth request")
            serv.send_error(401)
            return

        body = "<html><body>login</body></html>"
        body = bstr(body)

        serv.gen_headers("GET", len(body), "text/html")
        serv.wfile.write(body)
예제 #6
0
 def do_GET(self, serv):
   qs = get_qs(serv.path)
   if "name" not in qs or "accessToken" not in qs or ("path" not in qs and "id" not in qs):
     serv.send_error(400)
     return
   
   if ".." in qs["name"][0]:
     serv.send_error(403)
     return
     
   tok = qs["accessToken"][0]
   userid = do_auth(tok)
   
   if userid == None:
     serv.send_error(401)
     return
   
   if "id" in qs:
     folderid = publicid_to_fileid(qs["id"][0])
   else:
     folderid = qs["path"][0]
   
   if folderid == None:
     serv.send_error(400)
     return
   
   path = local_to_real(folderid + "/" + qs["name"][0])
   
   print("PATH", path, exists(path))
   #see if folder (or a file) already exists
   if exists(path):
     serv.send_error(400)
     return 
   
   os.makedirs(path)
   
   body = json.dumps({"success": True})
   body = bstr(body)
   
   serv.gen_headers("GET", len(body), json_mimetype)
   serv.wfile.write(body)
예제 #7
0
    def do_GET(self, serv):
        qs = get_qs(serv.path)

        #print("userinfo!")

        cur, con = mysql_connect()

        if "accessToken" not in qs:
            elog("access token wasn't provided")
            serv.send_error(400)
            return

        token = qs["accessToken"][0]

        userid = do_auth(token)

        if (userid == None):
            elog("invalid access")
            serv.send_error(401)
            return

        cur.execute("SELECT * FROM users WHERE userid=" + estr(userid))
        ret = cur.fetchone()

        body = json.dumps({
            "username": ret["username"],
            "userid": rot_userid(ret["userid"]),
            "name_last": ret["name_last"],
            "name_first": ret["name_first"],
            "email": ret["email"],
            "permissions": ret["permissions"],
            "last_login": str(ret["last_login"])
        })

        body = bstr(body)

        serv.gen_headers("GET", len(body), json_mimetype)
        serv.wfile.write(body)
예제 #8
0
    def do_GET(self, serv):
        qs = get_qs(serv.path)
        if not ("user" in qs and "password" in qs):
            serv.send_error(400)
            return

        user = qs["user"][0]
        password = qs["password"][0]
        #HACK: wsgi is turning +'s into spaces? how odd
        password = password.replace(" ", "+")

        if not valid_pass(password):
            alog("invalid pass format %s" % password)
            serv.send_error(401)
            return

        cur, con = mysql_connect()
        try:
            qstr = sql_selectall("users", ["username"], [user], [sq.user])
        except SQLParamError:
            do_param_error(user)
            serv.send_error(401)
            return

        cur.execute(qstr)
        ret = cur.fetchone()

        if ret == None:
            alog("invalid user %s" % user)
            serv.send_error(401)
            return

        alog("Fetching refresh token for user %s. . ." % user)

        passwd = ret["password"]
        userid = ret["userid"]

        if passwd != password:
            alog("Invalid password for %s, got: '%s', pass: '******'" %
                 (user, password, ret["password"]))
            serv.send_error(401)
            return

        tok = gen_token("R", userid)
        exprtime = datetime.datetime.now() + datetime.timedelta(days=12)

        alog("Refresh token for %s: %s" % (user, tok))

        cols = ["tokenid", "userid", "type", "permissions", "expiration"]
        values = [tok, userid, toktypes["R"], default_permission, exprtime]
        types = [sq.token, sq.int, sq.int, sq.int, sq.datetime]

        try:
            qstr = sql_insertinto("authtokens", cols, values, types)
        except SQLParamError:
            do_param_error("cols: " + str(cols) + ", values:" + str(values))
            serv.send_error(401)
            return
        """
    qstr = "INSERT INTO authtokens (tokenid,userid,type,permissions,expiration) VALUES("
    
    qstr += estr(tok)+","+estr(userid)+","
    qstr += estr(toktypes["R"])+","+estr(default_permission)+","
    qstr += estr(exprtime)+")"
    """

        cur.execute(qstr)
        con.commit()

        body = json.dumps({"refresh_token": str(tok), "result": 1})
        body = bstr(body)

        serv.gen_headers("GET", len(body), json_mimetype)
        serv.wfile.write(body)
예제 #9
0
 def do_PUT(self, serv):
   alog("fileapi access" + serv.path)
   
   qs = get_qs(serv.path)
   if "accessToken" not in qs or "uploadToken" not in qs:
     elog("fileapi: invalid tokens")
     serv.send_error(400)
     return
   
   tok = qs["accessToken"][0]
   utoken = qs["uploadToken"][0]
   
   userid = do_auth(tok)
   
   if userid == None:
     elog("invalid authorization")
     serv.send_error(401)
     return
   
   status = UploadStatus(utoken)
   if status.invalid:
     elog("invalid upload token ", utoken)
     serv.send_error(401)
     return
     
   if "Content-Range" not in serv.headers:
     elog("missing header " + json.dumps(serv.headers))
     serv.send_error(400)
     return
     
   r = serv.headers["Content-Range"].strip()
   
   if not r.startswith("bytes"):
     elog("malformed request 1")
     serv.send_error(400)
     return
   
   r = r[len("bytes"):].strip()
   r = r.split("/")
   
   if r == None or len(r) != 2:
     elog("malformed request 2")
     serv.send_error(400)
     return
   
   try:
     max_size = int(r[1])
   except ValueError:
     elog("malformed request 3")
     serv.send_error(400)
     return
   
   r = r[0].split("-")
   
   if r == None or len(r) != 2:
     elog("malformed request 4")
     serv.send_error(400)
     return
   
   try:
     r = [int(r[0]), int(r[1])]
   except ValueError:
     elog("malformed request 4")
     serv.send_error(400)
     return
   
   if r[0] < 0 or r[1] < 0 or r[0] >= max_size or r[1] >= max_size \
     or r[0] > r[1]:
     elog("malformed request 5")
     serv.send_error(400)
     return
   
   if status.size == -1:
     status.size = max_size
   
   buflen = r[1]-r[0]+1
   buf = serv.rfile.read(buflen)
   
   if len(buf) != buflen:
     elog("malformed request 6")
     serv.send_error(400)
     return
   
   """
   if not status.file_init:
     status.file = open(status.realpath, "wb")
     csize = 1024*1024*1024
     ilen = math.ceil(max_size/csize);
     
     zerobuf = b""*csize;
    
     for i in range(ilen):
       if i == ilen-1:
         c = b""*(max_size%(csize+1))
       else:
         c = zerobuf;
       
     status.file.write(c)
     status.file.flush()
     status.file.close()
   #"""
   
   if r[0] == 0:
     mode = "wb"
   else:
     mode = "ab"
   
   status.file = open(status.realpath, mode);
   status.file.seek(r[0]);
   status.file.write(buf);
   status.file.flush()
   status.file.close()
   
   status.commit()
   
   body = json.dumps({"success" : True});
   body = bstr(body)
   
   serv.gen_headers("PUT", len(body), json_mimetype)
   serv.wfile.write(body)
예제 #10
0
 def do_GET(self, serv):
   elog("fileapi access" + serv.path)
   
   qs = get_qs(serv.path)
   if "accessToken" not in qs or ("path" not in qs and "id" not in qs):
     serv.send_error(400)
     return
   
   tok = qs["accessToken"][0]
   userid = do_auth(tok)
   
   if userid == None:
     elog("Need user id")
     serv.send_error(401)
     return
   
   path = qs["path"][0]
   if "id" in qs:
     fileid = qs["id"][0]
   else:
     fileid = resolve_path(path)
   
   if fileid == None:
     elog("creating new file")
     cs = os.path.split(path)
     
     folderid = resolve_path(cs[0])
     if folderid == None:
       elog("invalid folder " + cs[0])
       serv.send_error(401);
       return
     
     if len(cs) == 1 or cs[1] == "":
       fname = cs[0]
     else:
       fname = cs[1]
     
     mime = "application/octet-stream"
     fileid = create_file(userid, fname, mime, folderid)
     meta = fetch_file(fileid);
   else:
     meta = fetch_file(fileid);
   
   if meta == None:
     elog("Invalid file id")
     serv.send_error(400)
     return
   
   print("\n\nFILE", meta, "\n\n")
   if is_folder(meta):
     elog("target file is a folder" + meta["name"])
     serv.send_error(401)
     return
   
   utoken = gen_token("U", userid);
   
   ustatus = UploadStatus() 
   ustatus.create(utoken, path, userid, fileid, meta["parentid"])
   ustatus.commit()
   
   f = open(ustatus.realpath, "w");
   f.close();
   
   realpath = ustatus.realpath
   cur, con = mysql_connect()
   
   try:
     qstr = sql_update("filedata", ["diskpath"], [realpath], [sq.path], ["fileid"], [fileid], [sq.int])
   except SQLParamError:
     do_param_error("upload start")
     serv.send_error(401)
   
   """
   qstr = "UPDATE filedata SET "
   qstr += "diskpath=%s"%estr(realpath)    
   qstr += " WHERE fileid=%d"%fileid
   #"""
   
   cur.execute(qstr)
   con.commit()
   
   body = json.dumps({"uploadToken" : utoken});
   body = bstr(body)
   
   print("\nupload start result:", body, "\n\n\n")
   
   serv.gen_headers("GET", len(body), json_mimetype)
   serv.wfile.write(body)
예제 #11
0
 def do_GET(self, serv):
   qs = get_qs(serv.path)
   if "name" not in qs or "accessToken" not in qs or ("path" not in qs and "id" not in qs):
     serv.send_error(400)
     return
   
   tok = qs["accessToken"][0]
   userid = do_auth(tok)
   
   if userid == None:
     serv.send_error(401)
     return
   
   if "id" in qs:
     folderid = publicid_to_fileid(qs["id"][0])
   else:
     folderid = [userid, resolve_path(qs["path"][0])]
   
   path = None
   if folderid == None:
     serv.send_error(400)
     return
   
   if userid != folderid[0]:
     self.send_error(401)
     
   folderid = folderid[1];
   
   if folderid != 1:
     cols   = ["fileid", "userid"]
     values = [folderid, userid]
     types  = [sq.int  , sq.int]
     
     try:
       qstr = sql_selectall("filedata", cols, values, types)
     except SQLParamError:
       do_param_error("dirnew")
       serv.send_error(400)
       return 
       
     cur, con = mysql_connect()
     cur.execute(qstr)
     ret = cur.fetchone()
     
     if ret == None:
       serv.send_error(400)
       return 
     
     path = "/" + ret["name"]
     
     while ret != None and ret["parentid"] != ROOT_PARENT_ID:
       cols   = ["id"    ]
       values = [ret["parentid"]]
       types  = [sq.int]
       
       try:
         qstr = sql_selectall("filedata", cols, values, types)
       except SQLParamError:
         do_param_error("dirnew")
         serv.send_error(400)
         return 
         
       cur, con = mysql_connect()
       cur.execute(qstr)
       ret = cur.fetchone()
       
       if ret != None:
         path = ret["name"] + "/" + path 
     
     path = path + "/" + qs["name"][0]
   else:
     path = "/" + qs["name"][0]
     
   print("path", path)
   print("folderid", folderid);
   
   #see if folder (or a file) already exists
   if resolve_path(path) != None:
     serv.send_error(400)
     return 
   
   id = create_file(userid, qs["name"][0], FOLDER_MIME, folderid);
   print("FINAL FOLDER ID:", id, folderid);
   
   body = json.dumps({"success": True})
   body = bstr(body)
   
   serv.gen_headers("GET", len(body), json_mimetype)
   serv.wfile.write(body)
예제 #12
0
 def do_GET(self, serv):
   qs = get_qs(serv.path)
   if "accessToken" not in qs or ("path" not in qs and "id" not in qs):
     serv.send_error(400)
     return
   
   tok = qs["accessToken"][0]
   userid = do_auth(tok)
   
   if userid == None:
     elog("Invalid access in file api")
     serv.send_error(401)
     return
   
   if "id" in qs:
     folderid = publicid_to_fileid(qs["id"][0])
   else:
     folderid = [userid, resolve_path(qs["path"][0])]
   
   if folderid == None or folderid[0] != userid:
     elog("Bad folder " + str(qs["id"][0]) if folderid == None else "Invalid user " + str(userid) + ", " + str(folderid))
     serv.send_error(401)
     return
   
   folderid = folderid[1]
   
   types  = [sq.int  ,  sq.int   ]
   cols   = ["userid", "parentid"]
   values = [userid  , folderid  ]
   
   try:
     qstr = sql_selectall("filedata", cols, values, types)
   except SQLParamError:
     do_param_error("dirlist")
     serv.send_error(400)
     return
   
   """
   qstr = "SELECT name,fileid,mimeType FROM filedata "
   qstr += "WHERE userid="+estr(userid) + " AND "
   qstr += "parentid="+estr(folderid)
   """
   
   cur, con = mysql_connect()
   cur.execute(qstr)
   ret = cur.fetchall()
   
   files = []
   if ret != None:
     for row in ret:
       f = {}
       f["name"] = row["name"]
       f["id"] = fileid_to_publicid(row["fileid"], userid)
       f["mimeType"] = row["mimeType"]
       f["is_dir"] = row["mimeType"] == FOLDER_MIME
       
       files.append(f)
   
   body = json.dumps({"items": files})
   body = bstr(body)
   
   serv.gen_headers("GET", len(body), json_mimetype)
   serv.wfile.write(body)
예제 #13
0
  def do_GET(self, serv):
    elog("fileapi access" + serv.path)
    
    qs = get_qs(serv.path)
    if "accessToken" not in qs or ("path" not in qs and "id" not in qs):
      serv.send_error(400)
      return
    
    tok = qs["accessToken"][0]
    userid = do_auth(tok)
    
    if userid == None:
      elog("Need user id")
      print("Bad auth")
      serv.send_error(401)
      return
    
    path = qs["path"][0]
    
    if "id" in qs:
      fileid = publicid_to_fileid(qs["id"][0])
    else:
      fileid = urllib.unquote(path)
    
    meta = File(fileid, userid)
    
    if meta != None:
      print("DISKPATH", meta.diskpath)

    if meta == None or not os.path.exists(meta.diskpath):
      elog("creating new file")
      
      cs = os.path.split(path)
      folderid = cs[0]
      
      f = File(folderid, userid)
      if not os.path.exists(f.diskpath):
        elog("invalid folder " + f.diskpath)
        print("invalid folder " + f.diskpath)
        serv.send_error(401);
        return
      
      if len(cs) == 1 or cs[1] == "":
        fname = cs[0]
      else:
        fname = cs[1]
      
      mime = "application/octet-stream"
      
      #create empty file
      f = open(f.diskpath+"/"+fname, "w")
      f.close()
      
      meta = File(fileid, userid)
    
    if meta == None:
      elog("Invalid file id")
      serv.send_error(400)
      return
    
    print("\n\nFILE", meta, "\n\n")
    if is_folder(meta):
      elog("target file is a folder" + meta["name"])
      serv.send_error(401)
      return
    
    utoken = gen_token("U", userid);
    
    ustatus = UploadStatus()
    
    #ignore fileid/parentid in upload status token
    ustatus.create(utoken, path, userid, fileid, -1)
    try:
      ustatus.commit()
    except:
      import traceback
      elog("USTATUS.COMMIT failed!")
      
      traceback.print_exc()
      
    f = open(ustatus.realpath, "w");
    f.close();
    
    realpath = ustatus.realpath
    
    body = json.dumps({"uploadToken" : utoken});
    body = bstr(body)
    
    print("\nupload start result:", body, "\n\n\n")
    
    serv.gen_headers("GET", len(body), json_mimetype)
    serv.wfile.write(body)
예제 #14
0
 def do_GET(self, serv):
   qs = get_qs(serv.path)
   
   if "accessToken" not in qs or ("path" not in qs and "id" not in qs):
     serv.send_error(400)
     return
   
   tok = qs["accessToken"][0]
   userid = do_auth(tok)
   
   if userid == None:
     serv.send_error(401)
     return
   
   if "path" in qs:
     fileid = qs["path"][0]
     fileid = urllib.unquote(fileid);
   else:
     fileid = qs["id"][0]
   
   path = local_to_real(fileid);
   if not os.path.exists(path):
     serv.send_error(404);
     return
   
   st = os.stat(path)
   fname = fileid.replace("\\", "/").strip()
   dir = ""
   
   if "/" in fname and fname[-1] != "/":
     dir = fname[:fname.rfind("/")].strip()
     fname = fname[len(dir):]
   
   while fname[0] == "/":
     fname = fname[1:]
     
   #ROOT_PARENT_ID      
   
   mime = "unknown"
   if stat.S_ISDIR(st.st_mode):
     mime = FOLDER_MIME
   else:
     pass #deal with later
   
   #stupid quoting
   #id = urllib.quote(fileid, "").strip()
   id = fileid_to_publicid(fileid, userid).strip()
   
   #if id[0] == "'" or id[0] == "\"" and id[0] == id[-1]:
   
   f = {
     'name'     : fname,
     'id'       : id,
     'parentid' : dir,
     'mimeType' : mime,
     'modified' : st.st_mtime,
     'is_dir'   : stat.S_ISDIR(st.st_mode)
   };
   
   f2 = {}
   for k in f:
     if k in file_restricted_fields: continue
     f2[k] = f[k]
   
   body = json.dumps(f2)
   body = bstr(body)
   
   serv.gen_headers("GET", len(body), json_mimetype)
   serv.wfile.write(body)
예제 #15
0
 def do_GET(self, serv):
   qs = get_qs(serv.path)
   if "accessToken" not in qs or ("path" not in qs and "id" not in qs):
     serv.send_error(400)
     return
   
   tok = qs["accessToken"][0]
   userid = do_auth(tok)
   
   if userid == None:
     elog("Invalid access in file api")
     serv.send_error(401)
     return
   
   if "id" in qs:
     path = publicid_to_fileid(qs["id"][0])
   else:
     path = qs["path"][0]
     path = urllib.unquote(path).strip();
   
   print("PATHPATH", path);
   
   dir = File(path, userid)
   
   if ".." in path:
     serv.send_error(401)
     return 
   
   if not serv_all_local:
     prefix = files_root#+rot_userid(userid)
     try:
       os.makedirs(prefix)
     except FileExistsError:
       pass
       
   dirpath = local_to_real(path)
   
   files = []
   for f in listdir(dirpath):
     path2 = path + os.path.sep + f
     file = File(path2, userid)
     f = {}
     
     if file == None:
       continue
       print("error!", dirpath)
     #if file == None: continue
     
     f["name"] = file.name
     f["id"] =  file.id
     f["mimeType"] = file.mimeType
     f["is_dir"] =  1 if file.is_dir else 0
     f["parentid"] = file.parentid
     
     files.append(f)
   
   body = jsondumps({"items": files})
   body = bstr(body)
   
   serv.gen_headers("GET", len(body), json_mimetype)
   serv.wfile.write(body)