cofan Reference

Date:

2019-01-30

Version:

0.0.3

Authors:

cofan is an http server library for serving files and any other things. You use it to share content in the form of a website. The current classes give you the following:

  • Serve the content of a local directory in a form similar to file browser with icons for directories and files based on their extension.
  • Serve the content of a local zip file the same way as the local directories.
  • List the content of a local directory in json form.
  • Serve local html files as a web site.
  • Organize your urls in prefix trees.
  • Response differently for different ip addresses

It also supports requests of partial files to resume previously interrupted download.

Here is an example of how to use it:

from cofan import *
import pathlib

#our site will be like this:
#   /           (this is our root. will list all the branches below)
#   |
#   |- vid/
#   |  this branch is a file browser for videos
#   |
#   -- site/
#      this will be a web site. just a collection of html files

#lets make an http file browser and share our videos
#first, we specify the icons used in the file browser
#you can omit the theme. it defaults to `humanity`
icons = Iconer(theme='humanity')

#now we create a Filer and specify the path we want to serve
vid = Filer(pathlib.Path.home() / 'Videos', iconer=icons)

#we also want to serve a web site. lets create another filer. since the root
#directory of the site contains `index.html` file, the filer
#will automatically redirect to it instead of showing a file browser
#no file browser also means we do not need to specify `iconer`
#parameter. you can still use it if you want but that would not be very
#useful
site = Filer(pathlib.Path.home() / 'mysite')

#now we need to give prefixes to our branches
#we create a patterner
patterns = Patterner()

#then we add the iconer, filers with their prefixes
#make sure to add a trailing slash
patterns.add('vid/', vid)
patterns.add('site/', site)
#we also need to add our iconer
#you need to tell the iconer about its prefix. by default it assumes
#`__icons__`
patterns.add('__icons__/', icons)

#now we have all branches. but what if the user types our root url?
#the path we will get will be an empty string which is not a prefix of any
#branch. that will be a 404
#lets make the root list and other branches added to `patterns`
#the branches will be shown like the file browser but now the icons will be
#for the patterns instead of file extensions
#we need to specify where the icons are taken from
#the icons file should contain an icon named `vid.<ext>` and an icon named
#`site.<ext>` where <ext> can be any extension.
root = PatternLister(patterns, root=pathlib.Path.home() / 'icons.zip')

#and we add our root to the patterns with empty prefix
patterns.add('', root)

#now we create our handler like in http.server. we give it our patterner
handler = BaseHandler(patterns)

#and create our server like in http.server
srv = Server(('localhost', 8000), handler)

#and serve forever
srv.serve_forever()

#now try to open your browser on http://localhost:8000/

This module can also be run as a main python script to serve files from a directory.

commandline syntax:

python -m cofan.py [-a <addr>] [<root>]

options:

  • -a <addr>, –addr <addr>: specify the address and port to bind to. <addr> should be in the form <ip>:<port> where <ip> is the ip address and <port> is the tcp port. defaults to localhost:8000.

args:

  • root: The root directory to serve. Defaults to the current directory.
class cofan.BaseHandler(provider)

Base http handler class in cofan library. It holds a provider instance and gets the response of all requests from it. Note that unlike what is usually done in http.server, when creating an http.HTTPServer instance, you should pass an instance of BaseHandler instead of the class itself. For example:

myprovider = Filer('/path/to/my/directory')
myhandler = BaseHandler(myprovider)
srv = http.server.HTTPServer(('localhost', 80), myhandler)

BaseHandler has one class attribute:

__header_modifiers__: A tuple of request headers which have modifier methods in this class. For each header present in a request, self.mod_<header>() is called where <header> is the header name. The modifier method must return the response, headers and content after any necessary modification. It must take the following arguments:

  • response: Last response status code after any previous modifications by other modifier mehtods.
  • headers: Last headers after any previous modifications by other modifier mehtods.
  • content: Last content file after any previous modifications by other modifier mehtods.

This tuple currently has only one header: Range. See self.mod_Range() for the modification applied.

do_GET()

Calls BaseProvider.get_content() from self.provider and sends the returned response, headers and content. After this process is done, the content file is closed and the returned post processing fucntion is called. This happens regardless of whether the process ended with success or not.

do_HEAD()

Same as self.do_GET() but does not send any content.

get_response()

Called by self.do_GET() and self.do_HEAD(). Parses the url path and query string and replaces all url escapes. After that, it gets the response self.provider.get_content(). Before returning the response, headers, content file and post processing callables, it calls any modifier method that should be called. If the method fails while applying modifications, it closes the content file and calls the post processing callable before propagating the exception.

mod_Range(response, headers, content)

Called when the Range header is present in the request. If the response status code is 200 (OK) and the content file is seekable, the status code is changed to 206 (Partial Content) and the content file is changed to a partial file pointing to the requested range. Response status code is changed to 416 (Requested Range Not Satisfiable) if the range start is not between 0 and total size or if the range end is not between start and total size.

class cofan.BaseProvider

basic provider class. each time a request is intended to this provider, the provider should return a response code, headers and body. it defines two methods:

  • get_content(): this should return the response code, headers and body
  • short_response(): helper method to send a response code and its description.

You probably want to use one of BaseProvider subclasses or inherit it in your own class.

classmethod get_content(handler, url, query={}, full_url='')

This method is called by the http.server.BaseHTTPRequestHandler object when a request arrives. It must returns a tuple containing:

  • Response code
  • Response headers
  • Response body
  • Postprocessing callable

The response code should be an integer or a member of http.HTTPStatus. Response headers should be a dictionary where keys are header keywords and values are header values. The body must be a readable file like object. Postprocessing callable is a callable object which takes no arguments. It is called after the request is served. The body object is closed automatically after serving the request and does not need to be closed in the postprocessing callable.

This method should be overridden in subclasses. The default implementation is to send OK response code with a body that contains short description of the response code.

args:

  • handler (http.server.BaseHTTPRequestHandler): The object that called this method.
  • url (str): The url that was requested after removing all prefixes by other providers. Look at Patterner for information of how prefixes are stripped.
  • query (dict): Request query arguments. Defaults to empty dictionary.
  • full_url (str): The full url that was requested without removing prefixes. Defaults to empty string

returns:

  • response (http.HTTPStatus): Response code.
  • headers (dict): Response headers.
  • content (binary file-like object): The response content.
  • postproc (callable): A callable that will be called after serving the content. This callable will be called as long as the get_content() method succeded regardless whether sending the content to the client succeded or not. The intention of this callable is to close all files other than content in case there are open files. For example, if content is a file inside a zip file, closing content is not enough without closing the parent zip file.
static short_response(response=<HTTPStatus.OK: 200>, body=None)

Convinience method which can be used to send a status code and its description. It returns the same values as get_content but the code is specified as a parameter and the body defaults to a description of the code.

args:

  • response (http.HTTPStatus): Response code to send. Defaults to http.HTTPStatus.OK.
  • body: The value to send in the body. It defaults to None which sends a short description of the code. If the body is not a bytes object, it is converted to a string and then encoded to utf8.

returns:

  • response (http.HTTPStatus): Response code given in the args.
  • headers (dict): Response headers dict with text/html in Content-Type header and the length of the body in Content-Length header.
  • content (binary file-like object): Description of response as a utf-8 encoded string if body arg is None. Otherwise, returns body represented as utf-8 encoded string.
  • postproc: Always a value of None.
class cofan.Filer(root, iconer=None)

Same as JFiler when the url points to a file. If the url points to a directory, the content of the directory is sent as an html file presenting directory content as a file browser with icons instead of JSON.

get_content(handler, url, query={}, full_url='')

Serves files based on the url given starting from the self.root. If the url points to a file, the file is served. Last-Modified header is sent to help clients cache the file. If the url points to a directory, a list of files it contains is served as a JSON object with 2 members:

  • dirs: List of directories under the requested directory. If full_url parameter is not an empty string, a ‘..’ value is added to the dirs list.
  • files: List of files under the requested directory.

If the url does not point to a file or directory under self.root, it responds with NOT FOUND.

serve_dir(handler, url, query={}, full_url='')

Overrides JFiler.serve_dir(). Sends an html file containing subdirectories and files present in the requested directory in a similar way to file browsers. Icons are taken from self.iconer.

class cofan.IPPatterner

The same as Patterner but relays requests based on IP address patterns instead of url.

get_content(handler, url, query={}, full_url='')

Searches the pattern list for a pattern that matches the beginning of the url and relays the request to the corresponding provider. If not found, sends a NOT FOUND response. The search is done from the first added pattern. If two patterns overlap, the more specific pattern should be added first. For example, files/mysite/ should be added before files/. Otherwise, any request to files/mysite/ will be served by files/ since it will be checked first.

class cofan.Iconer(root=None, theme='humanity', prefix='__icons__/')

Same as Ziper but used to serve file icons used in Filer and Ziper. Defines methods to help other objects find icon urls for files of different types. The root of Iconer is a zip file which contains image files in its toplevel. The name of each image file should be in the form <name>.<ext> where <ext> can be any extension and <name> can be any of the following:

  • The string directory. It makes the image used as the icon for directories.
  • A file extension. It makes the image used for file of this extension.
  • General mimetype (such as audio, video, text, …). It makes the image used for this mimetype if the file extension image does not exist.
  • The string generic. It makes the image used as a fallback icon if none of the above was found.

Any file without extension in self.root is ignored.

get_content(handler, url, query={}, full_url='')

Overrides Filer.get_content(). Gives the same result as Filer.get_content() but looks at the content of a zip file instead of a directory.

get_icon(name)

This method is to be used in other content providers to get icons. Returns the url of an icon for name. The icon is constructed in the following way:

  • The extension is extracted from name. If name has no extension, the full value of name is taken.
  • If there is a file in self.root named as the extension of name extracted in the previous step, the url of this file is returned. For example, if name is foo.mp4, this method will look for a file named mp4.<extension> where <extension> may be any string. The extension is case insensitive so foo.mp4 will be the same as foo.MP4.
  • If there is no file found in the previous step, the mimetype is guessed and the general type is taken (such as audio, video, etc…).
  • If there is a file in self.root with the same name as the generel mimetype extracted in the previous step, the url of this file is returned. For example, if name is foo.mp4, this method will look for a file named mp4.<anything> first. If it there is no such file in self.root, the method will look for video.<anything>. <anything> may be any string.
  • If there is no file found in the previous step, this method looks for a file named generic.<anything> and the url of this file is returned.
  • If there is no file found in the previous step, an empty string is returned.
get_icons()

Used in self.__init__(). Looks at the toplevel content of self.root for any files and makes a dictionary for each file. The keys of the dictionary are file names without extensions and the values are the file names with extensions. Any files without extension are ignored. The dictionary is used to look for icons without opening the zip file.

class cofan.JFiler(root)

Lists directory contents and serves files from local file system based on the recieved url.

exists(url)

Returns True if the url points to an existing file or directory under self.root. Otherwise returns False.

args:

  • url (path-like object): The recieved url to check.
returns: True if url is an existing file or subdirectory in
self.root. False otherwise.
get_content(handler, url, query={}, full_url='')

Serves files based on the url given starting from the self.root. If the url points to a file, the file is served. Last-Modified header is sent to help clients cache the file. If the url points to a directory, a list of files it contains is served as a JSON object with 2 members:

  • dirs: List of directories under the requested directory. If full_url parameter is not an empty string, a ‘..’ value is added to the dirs list.
  • files: List of files under the requested directory.

If the url does not point to a file or directory under self.root, it responds with NOT FOUND.

get_file_list(url, parent=False)

Called by self.get_content. Returns a dictionary containing 2 members:

  • dirs: A list of directories under the directory pointed by url.
  • files: A list of files under the directory pointed by url.

args:

  • url (path-like object): The directory url to list its content.
  • parent (bool): If True, adds ‘..’ to the dirs list. Defaults to False.
is_dir(url)

Returns True if the url points to an existing directory under self.root. Otherwise returns False.

args:

  • url (path-like object): The recieved url to check.
return: True if url is an existing subdirectory of self.root. False
otherwise.
is_file(url)

Returns True if the url points to an existing file under self.root. Otherwise returns False.

args:

  • url (path-like object): The recieved url to check.
returns: True if url is an existing file in self.root or one of its
subdirectories. False otherwise.
serve_dir(handler, url, query={}, full_url='')

Called by self.get_content() when the url points to a direcotry. Gets a list of directories and files under the requested directory pointed by url argument.

Takes the same arguments as self.get_content().

serve_file(handler, url, query={}, full_url='')

Called by self.get_content() when the url points to a file. Serves the file content as a JSON object.

Takes the same arguments as self.get_content().

class cofan.PatternLister(provider, root=None, exclude='|__.*__/?', include='.*')

Similar to Filer but instead of showing content of a directory, shows the prefixes added to a Patterner. It also provides icon urls for the prefixes. See Patterner for more details of the Patterner provider.

get_content(handler, url, query={}, full_url='')

Overrides Iconer.get_content(). If the url is empty string, returns a list of prefixes in self.provider. If the url starts with __pattern_icons__/, returns an icon from self.root.

get_icon(name, full_url='')

Returns the icon of the prefix name. Unlike Iconer, this method takes name itself after striping any trailing slashes as the name of the icon.

serve_patterns(handler, url, query={}, full_url='')

Same as Filer.serve_dir() but returns prefixes from self.provider instead of directories. Used in self.get_content().

class cofan.Patterner

BaseProvider subclass that relays requests to other providers based on requested url pattern. The other providers are added to the Patterner instance with the request url pattern they should get. When the Patterner gets a request, it searches for a pattern that matches the beginning of the url. When found, the Patterner calls get_content() method of the target provider, giving it the same parameters but with the prefix stripped from the beginning of the url.

add(pattern, provider, title='')

Adds a pattern and a provider to the Patterner.

args:

  • pattern (str): A string containing the url prefix of the provider.
  • provider (BaseProvider): The provider to relay the request to.
get_content(handler, url, query={}, full_url='')

Searches the pattern list for a pattern that matches the beginning of the url and relays the request to the corresponding provider. If not found, sends a NOT FOUND response. The search is done from the first added pattern. If two patterns overlap, the more specific pattern should be added first. For example, files/mysite/ should be added before files/. Otherwise, any request to files/mysite/ will be served by files/ since it will be checked first.

get_patterns()

Returns the pattern strings added to the Patterner.

get_title(pattern)

Returns the pattern title.

args:

  • pattern (str): the pattern to look for its title.

returns:

The pattern title.
remove(pattern)

Removes a pattern and its provider from the pattern list. If a pattern exists multiple times (which you should not do anyway), only the first occurance is removed.

args:
pattern (str): Pattern to remove.
class cofan.Server(server_address, RequestHandlerClass, bind_and_activate=True)

same as http.server.HTTPServer but handles requests in daemon threads.

class cofan.Statuser(response=<HTTPStatus.NOT_FOUND: 404>)

A subclass of BaseProvider. This provider is very similar to BaseProvider. The only difference is that it takes the response code in its constructor and sends this response code instead of OK.

get_content(handler, url, query={}, full_url='')

This method is called by the http.server.BaseHTTPRequestHandler object when a request arrives. It must returns a tuple containing:

  • Response code
  • Response headers
  • Response body
  • Postprocessing callable

The response code should be an integer or a member of http.HTTPStatus. Response headers should be a dictionary where keys are header keywords and values are header values. The body must be a readable file like object. Postprocessing callable is a callable object which takes no arguments. It is called after the request is served. The body object is closed automatically after serving the request and does not need to be closed in the postprocessing callable.

This method should be overridden in subclasses. The default implementation is to send OK response code with a body that contains short description of the response code.

args:

  • handler (http.server.BaseHTTPRequestHandler): The object that called this method.
  • url (str): The url that was requested after removing all prefixes by other providers. Look at Patterner for information of how prefixes are stripped.
  • query (dict): Request query arguments. Defaults to empty dictionary.
  • full_url (str): The full url that was requested without removing prefixes. Defaults to empty string

returns:

  • response (http.HTTPStatus): Response code.
  • headers (dict): Response headers.
  • content (binary file-like object): The response content.
  • postproc (callable): A callable that will be called after serving the content. This callable will be called as long as the get_content() method succeded regardless whether sending the content to the client succeded or not. The intention of this callable is to close all files other than content in case there are open files. For example, if content is a file inside a zip file, closing content is not enough without closing the parent zip file.
class cofan.Ziper(root, iconer=None)

Same as Filer but serves the content of a zip file instead of a directory. The root in the constructor must be a zip file. Files served from this class are not seekable so resuming download is not possible for the content of a Ziper.

exists(url, root=None)

Overrides Filer.exists(). Looks at the content of the zip file instead of a directory.

get_content(handler, url, query={}, full_url='')

Overrides Filer.get_content(). Gives the same result as Filer.get_content() but looks at the content of a zip file instead of a directory.

get_file_list(url, root=None, parent=False)

Overrides Filer.get_file_list(). Looks at the content of the zip file instead of a directory.

is_dir(url, root=None)

Overrides Filer.is_dir(). Looks at the content of the zip file instead of a directory.

is_file(url, root=None)

Overrides Filer.is_file(). Looks at the content of the zip file instead of a directory.

serve_dir(handler, url, query={}, full_url='', root=None)

Overrides Filer.serve_dir(). Looks at the content of a zip file instead of a directory.

This method has an additional optional argument:

root (zipfile.ZipFile): Opened self.root It is used in self.get_content() to avoid opening and closing self.root multiple times. Defaults to None which means self.root will be opened and a new zipfile.ZipFile instance will be created.
serve_file(handler, url, query={}, full_url='', root=None)

Overrides JFiler.serve_dir(). Looks at the content of the zip file instead of a directory.

This method has an additional optional argument:

root(zipfile.ZipFile) Opened self.root. It is used in self.get_content() to avoid opening and closing self.root multiple times. Defaults to None which means self.root will be opened and a new zipfile.ZipFile instance will be created.