Package: httpuploader
An HTTP server that displays a directory listing, much like Python’s
default http.server module, except this one allows directory creation
and file upload by the user.This can be useful anytime you want to quickly share files a directory,
for example in a classroom where the students need to obtain one or
more files from the instructor and need to upload their exercise.
In that case the instructor finds out their machine’s IP address,
communicates the urlhttp://ipaddress:port/to the students, opens
a command window and runs httpuploader like this:$ python3 httpuploader.py -p port -d directoryand they now have a quick server.Httpuploader is a single file withno dependenciesoutside the
Python Standard Library. It is a WSGI application so that it can be
imported as a module and run
in any WSGI compliant server like mod_wsgi, Rocket, uWSGI, etc. just by
instantiating theWSGIAppclass with the top directory to serve and
a boolean value telling it whether to show hidden files and directories.The client’s browsers need Javascript activated. It won’t work in old
versions of Internet Explorer though. Get the latest version or Edge.InstallingAn install is not really necessary since, being a single file, it can be
just dropped anywhere convenient. However asetup.pyprogram is provided
for convenience so that it can be downloaded fromPyPI.orgusingpip:$ pip3 install httpuploaderIt can also be installed usingsetup.pyas follows:$ python3 setup.py installAPIThis version contains a RESTful API that can be used by other applications
as a remote file manager, allowing not only to upload and download files
and create directories, but to delete files and entire trees, calculate
checksums, download compressed files and compressed archive directories,
and copy and move on the same or different directories.It is possible to enable or disable all, some or none of the possible
operations on either a global or per directory (or file) basis. See theconfigurationsection.The API responds always with a JSON object with the following structure:{
    "version": <the API version>,
    "rc": <the status code, e.g. 404>,
    "msg": <the status message, e.g. "Not found">,
    "data": <a json object containing the response of the call>
}In the case of errors, thedatafield contains an object, containing
a field namedextrawith an extended explanation of the error.The API calls have the form/api/<version>/resource?cmd=<command>&<args...>where<version>is the API version number, can be just1,1.0or1.0.0. At this moment, it is the only version available, but version1will indicate the highest API version available of the1.x.xrange.Available CommandsDirectory OperationslistList the contents of a directory. Does not need to be specified:GET /api/1/<directory>?cmd=list
GET /api/1/<directory>The response data field contains the following fields:name:Name of the directoryfiles:List of file objectsdirectories:List of directorieslinks:List of possible operationsarchiveDownload a compressed archive with the contents of the directory:GET /api/1/<directory>?cmd=archive&format=<zip|tar.gz>mkdirCreate new directory:POST /api/1/<directory>?cmd=mkdirIf successful, the response will be204 No contentuploadUpload file(s) to directory:POST /api/1/<directory>?cmd=uploadThe files can be uploaded by simply sending the file in the body of the
request, or sending several files in a multipart message.If successful, the response will be204 No contentdeleteRemove the directory:DELETE /api/1/<directory>This command removes the entire tree without asking for confirmation. Use
with caution.If successful, the response will be204 No contentFile OperationsdownloadDownload a file:GET /<path>
GET /api/1/<path>
GET /api/1/<path>?cmd=downloadIt is not necessary to specify the command or the API/version prefix.
The mime type of the file is guessed based on the name using the Python
Standard Librarymimetypesmodule.infoMiscellaneous information about a file:GET /api/<version>/path?cmd=infoUpon success, the responsedatafield will contain a JSON object with
the following files:name:The name of the file.size:The size in bytes, as a number.human_size:The size in a string, expressed in the easiest to read unit.path:Path from the top directory.checksum:The sha256 checksum.atime:Last access time, as a string in ISO format.mtime:Last modification time, as a string in ISO format.ctime:Creatrion time, as a string in ISO format.Example:GET /api/1/opt/jdk1.8.0_51/COPYRIGHT?cmd=info
{
  "rc": 200,
  "msg": "OK",
  "api_version": "1.0.0",
  "data": {
    "name": "COPYRIGHT",
    "size": 3244,
    "human_size": "3.17 KB",
    "path": "/opt/jdk1.8.0_51",
    "checksum": "89471aea3957922df21c7088d2687c4e43f5ff14e635e7d971083dde540b45e3",
    "atime": "2019-11-15T23:33:56.430384+00:00",
    "mtime": "2015-06-09T02:37:58+00:00",
    "ctime": "2015-07-20T18:17:40.394882+00:00"
  }
}compressCompress and download a single file:GET /api/1/<path>?cmd=compress&format=<zip|tar.gz>checksumCompute, and optionally check, the SHA256 checksum of a file:GET /api/1/<path>?cmd=checksum
GET /api/1/<path>?cmd=checksum&match=<checksum>If no arguments are given the checksum of the file is computed and
returned in thedatafield of the JSON response, which has the
following fields:filename:The base filename for which the checksum was computed.checksum:The SHA256 digest as a lower case hexadecimal number.If thematchargument was used, it is used to compare it to the
computed checksum, and the following field is returned in addition to
the above:match:A boolean indicating whether the checksums match.Example:GET /api/1/opt/jdk1.8.0_51/COPYRIGHT?cmd=checksum&match=89471aea3957922df21c7088d2687c4e43f5ff14e635e7d971083dde540b45e3
{
  "rc": 200,
  "msg": "OK",
  "api_version": "1.0.0",
  "data": {
    "checksum": "89471aea3957922df21c7088d2687c4e43f5ff14e635e7d971083dde540b45e3",
    "filename": "COPYRIGHT",
    "match": true
  }
}copyCopy a file:POST /api/1/<path>?cmd=copy&dest=<newfile>If successful, the response will be204 No contentmoveMove or rename a file:POST /api/1/<path>?cmd=move&dest=<newfile>If successful, the response will be204 No contentConfigurationIt is possible to manage permissions for each of the operations
supported by the API on a global or per directory or file basis. These
permissions should be specified in a Windows .ini configuration file.Each section in the .ini file has a variable called ‘allow’ whose contents
are the names of the individual API commands, separated by commas, or
the special wordsallornonewhich grant permission for all
actions or deny them respectively.There is aDEFAULTsection that contains the global commands that
are allowed in all the directories not specified and sections for each
directory or file for which we want different permissions. For example,
consider the following.inifile:[DEFAULT]
allow = list, download, mkdir, upload, info, checksum
[/dir_004]
allow = ${DEFAULT:allow}, compress, archive
[/dir_003]
allow = ${/dir_004:allow}
[/dir_003/dir_025]
allow = all
[/dir_003/dir_024/dir_026]
allow = noneThe default section applies globally and provides a restricted, but
reasonable set of commands. The sections[/dir_004]and[/dir_003]specify an augmented set of permissions, based on those of the default
section. This is important: once we have a section for a directory, the
global permissions no longer apply and we must explicitly allow all the
command that we want. In this example we areinheritingthe permissions using theExtended Interpolationnotation provided by
the Pythonconfigparsermodule.All operations will be permitted for the directory/dir_003/dir_025and everything under it, including copying and deletion, and on
directory/dir_003/dir_024/dir_026no operations whatsoever are
permitted and we won’t even be able to list its contents.The configuration file is specified using the--configcfgcommand
line option, e.g.:$ httpuploader --config config.ini --rootdir $HOMEIf no configuration file is specified, the default permissions settings
will be:[DEFAULT]
allow = list, download, mkdir, uploadLicenseThis software is released under theMIT License