{ "info": { "author": "Outernet Inc", "author_email": "branko@outernet.is", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: Bottle", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.4", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI" ], "description": "=============\nbottle-fdsend\n=============\n\nThis package implements functions for constructing bottle's ``HTTPResponse``\nobjects from file handles. Unlike the ``bottle.static_file()`` function,\nfunctions in this package allow for serving files constructed in memory, or\nunpacked from compressed archives into memory.\n\nInstallation\n============\n\nTo install bottle-fdsend, you can use pip or easy_install commands::\n\n pip install bottle-fdsend\n\n easy_install bottle-fdsend\n\nBasic usage\n===========\n\nThe function we will be using most of the time is the ``fdsend.send_file()`` \nfunction. At it's simplest, we simply pass a file-like object to this\nfunction and it will return a ``bottle.HTTPResponse`` object.\n\nFor example::\n\n from StringIO import StringIO\n from fdsend import send_file\n\n def my_request_handler():\n s = StringIO('foo')\n return send_file(s)\n\nBecause we are working with in-memory files and not physical files, however,\nnone of the common response headers are set if we don't supply additional\nmetadata about the file. In order to set Content-Type, Content-Length and\nsimilar headers, we need to pass a few optional arguments.\n\nNote that ``send_file()`` merely constructs a response object. We have to\nreturn it in order to have bottle serve it. We also need to keep in mind that\nthe returned response object is a brand new one and anything we do to\n``bottle.response`` is not reflected on it. If we need to set additional\nheaders and such, we must do so on the returned response object, not the\nglobal ``bottle.response`` object.\n\nContent type\n============\n\nThere are two ways to set the Content-Type header. One is to pass the ctype\nargument::\n\n def my_request_handler():\n ....\n return send_file(s, ctype='text/html')\n\nAnother method is to specify a filename with extension:\n\n def my_request_handler():\n ...\n return send_file(s, filename='foo.html')\n\nIf you pass both arguments, the ``ctype`` argument takes precedence when it\ncomes to Content-Type header.\n\nCharacter set and encoding\n==========================\n\nWhen we set the Content-Type header by means of passing a filename, the content\ntype is automatically calculated based on file extension. In case of files\nwhose MIME type (content type) starts with 'test/' (e.g., 'text/html',\n'text/plain', and so on), character set is appended to the Content-Type header.\n\nFor example, ``send_file(s, filename='foo.html')`` results in a Content-Type\nheader that looks like this::\n\n Content-Type: text/html; charset=UTF-8\n\nThe 'UTF-8' character set is the default. If our data is using a different\ncharacter set, we need to explicitly specify it. ::\n\n def my_request_handler():\n ...\n return send_file(s, filename='foo.html', charset='ascii')\n\nWith above snippet, we get a different Content-Type header::\n\n Content-Type: text/html; charset=ascii\n\nAnother header gets automatically added depending on file extension, and that\nis the Content-Encoding header. This applies to compressed files. For example::\n\n def my_request_handler():\n ...\n return send_file(s, filename='foo.html.gz')\n\nThe above snippet generates the following headers:\n\n Content-Type: text/html; charset=UTF-8\n Content-Encoding: gzip\n \nThe Content-Encoding header cannot be set manually, but it can be omitted by\nmanually passing the ``ctype`` argument.\n\nFile size and byte serving\n==========================\n\nBecause it would be wasteful to read from the file handle just to obtain the\nfile size, it is our responsibility to know in advance the size of our file and\ntell ``send_file()`` what size it should use. This is done by using the aptly\nnamed ``size`` parameter.\n\n def my_request_handler():\n ...\n return send_file(s, size=2000)\n\nThe size is in bytes, and when it is passed, two headers are added::\n\n Content-Length: 20000\n Accept-Range: bytes\n\nThe first header tells the client the size of the payload, and the second\nheader announces we are able to do byte serving_. Byte serving is especially\nuseful when browsers want to retrieve portions of the files (e.g., resume a\ndownload, load files in stages, like in video players, PDF extensions, etc).\n\nAs programmers, we don't really need to do anything to take advantage of byte\nserving techniques: ``send_file()`` takes care of it. However, we do need to\nknow the total size of the file and pass it.\n\nNote that response when doing byte serving is 206, not 200.\n\nFile timestamp and 304 Not Modified responses\n=============================================\n\nIf you want the Last-Modified header to be set, you must pass the timestamp\nargument. The timestamp must be in seconds since Unix epoch. ::\n\n def my_request_handler():\n ...\n return send_file(s, timestamp=1429458831)\n\nThe above timestamp will generate the following Last-Modified header::\n\n Last-Modified: Sun, 19 Apr 2015 15:53:51 GMT\n\nPassing the timestamp also causes ``send_file()`` to automatically return a\nHTTP 304 Not Modified response when client includes a valid\n``If-Modified-Since`` request header.\n\nContent-Disposition\n===================\n\nWhen Content-Disposition header is set to a value of 'attachment', most modern\nbrowsers will offer the user to download the file (by opening a download\ndialog, for instance) instead of trying to display the contents in the browser\nwindow. To set this header, we need to pass both the filename and the\n``attachment`` argument::\n\n def my_request_handler():\n ...\n return send_file(s, filename='foo.html', attachment=True)\n\nByte serving wrappers\n=====================\n\nLastly, we can control how the ranges are returned from the file-like object in \nbyte serving. \n\nThe simplest wrapper we can use is the bottle's own ``bottle._file_iter_range`` \ngenerator function. This wrapper allows us to iterate over the desired range\nand return file data in chunks (1MB by default). \n\nWhile this works in most cases, it does not work for some types of file-like\nobjects, such as file handles for ZIP file contents using DEFLATE compression\nwhich do not allow ``seek()`` to be called on them. (Not the mention the fact\nthat ``bottle._file_iter_range`` is not a public API and therefore subject to\nchange).\n\nThis package provides two alternatives. One is\n``fdsend.rangewrapper.range_iter`` generator function and another is\n``fdsend.rangewrapper.RangeWrapper`` class.\n\nThe generator function is similar to bottle's generator function, but\nspecifically designed to work around file-like objects that do not support\n``seek()``.\n\nThe ``RangeWrapper`` is a bit different and it returns a file-like object that\nhas its own ``read()`` method which is restricted to the requested range.\n\nThe primary difference between the two is whether ``wsgi.file_wrapper`` feature\nis used on not. This feature requires a file-like object to be passed in order\nto be used.\n\nThe default wrapper is ``fdsend.rangewrapper.range_iter``.\n\nIt is also possible to write your own wrapper. The wrapper must be a callable\n(function, class, etc) and must accept the following positional arguments:\n\n- file handle\n- offset (in bytes from the start of the file)\n- length (size of the range in bytes)\n\nThe return value must be a valid WSGI response body (string, iterable,\nfile-like object).\n\nFeature requests and bug reports\n================================\n\nPlease report all feature requests and bugs to our `issue tracker`_.\n\n.. _byte serving: https://en.wikipedia.org/wiki/Byte_serving\n.. _issue tracker: https://github.com/Outernet-Project/bottle-fdsend/issues", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/Outernet-Project/bottle-fdsend", "keywords": "file static http response bottle", "license": "GPLv3", "maintainer": null, "maintainer_email": null, "name": "bottle-fdsend", "package_url": "https://pypi.org/project/bottle-fdsend/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/bottle-fdsend/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/Outernet-Project/bottle-fdsend" }, "release_url": "https://pypi.org/project/bottle-fdsend/0.1.1/", "requires_dist": null, "requires_python": null, "summary": "Library for constructing responses from file descriptors", "version": "0.1.1" }, "last_serial": 1513236, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "85b37b3d7ba2a00f12ab1169dd3d295c", "sha256": "4a97391e6276a285fbeb48ffa08b17a1dc1cb8fa9f25a88024daaaca88e20ea5" }, "downloads": -1, "filename": "bottle-fdsend-0.1.tar.gz", "has_sig": false, "md5_digest": "85b37b3d7ba2a00f12ab1169dd3d295c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9544, "upload_time": "2015-04-19T19:32:04", "url": "https://files.pythonhosted.org/packages/f6/3e/0d2f9ca31b253f9c082759129627909ad3341bb0d0e563382c21616543cb/bottle-fdsend-0.1.tar.gz" }, { "comment_text": "", "digests": { "md5": "91849da096be8a130072a5afa9e58e9c", "sha256": "e918975f4f4f76feb8720f7bead3bf6eab79d084a5cd6a38ebb6341dbc6394f2" }, "downloads": -1, "filename": "bottle-fdsend-0.1.zip", "has_sig": false, "md5_digest": "91849da096be8a130072a5afa9e58e9c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18033, "upload_time": "2015-04-19T19:32:08", "url": "https://files.pythonhosted.org/packages/07/83/12af785400b47fc5577791d2432aa3f97263d95b757803dbdcd959efc86f/bottle-fdsend-0.1.zip" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "e4d02f1bd8c7a4ba884f8bbf5736012e", "sha256": "a0fa4f69afb7afd820577d09858557ea1905040e0a7f799dc9162fce6b8dc593" }, "downloads": -1, "filename": "bottle-fdsend-0.1.1.tar.gz", "has_sig": false, "md5_digest": "e4d02f1bd8c7a4ba884f8bbf5736012e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9551, "upload_time": "2015-04-20T16:54:24", "url": "https://files.pythonhosted.org/packages/63/62/684553c8dc854a07c613148fd5374e0ad5b8826ab0f8059c113dd2f7e1e8/bottle-fdsend-0.1.1.tar.gz" }, { "comment_text": "", "digests": { "md5": "1089860622c6b13d87c031cd2ed22472", "sha256": "adddf7866b4c3e2022cc98d812ce3326af34357dbbc7c157ef80a5f18af82b46" }, "downloads": -1, "filename": "bottle-fdsend-0.1.1.zip", "has_sig": false, "md5_digest": "1089860622c6b13d87c031cd2ed22472", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18091, "upload_time": "2015-04-20T16:54:27", "url": "https://files.pythonhosted.org/packages/55/33/03591d5ec85fd512985c8eaf97580321869d36652137e76288437c182a91/bottle-fdsend-0.1.1.zip" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e4d02f1bd8c7a4ba884f8bbf5736012e", "sha256": "a0fa4f69afb7afd820577d09858557ea1905040e0a7f799dc9162fce6b8dc593" }, "downloads": -1, "filename": "bottle-fdsend-0.1.1.tar.gz", "has_sig": false, "md5_digest": "e4d02f1bd8c7a4ba884f8bbf5736012e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9551, "upload_time": "2015-04-20T16:54:24", "url": "https://files.pythonhosted.org/packages/63/62/684553c8dc854a07c613148fd5374e0ad5b8826ab0f8059c113dd2f7e1e8/bottle-fdsend-0.1.1.tar.gz" }, { "comment_text": "", "digests": { "md5": "1089860622c6b13d87c031cd2ed22472", "sha256": "adddf7866b4c3e2022cc98d812ce3326af34357dbbc7c157ef80a5f18af82b46" }, "downloads": -1, "filename": "bottle-fdsend-0.1.1.zip", "has_sig": false, "md5_digest": "1089860622c6b13d87c031cd2ed22472", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18091, "upload_time": "2015-04-20T16:54:27", "url": "https://files.pythonhosted.org/packages/55/33/03591d5ec85fd512985c8eaf97580321869d36652137e76288437c182a91/bottle-fdsend-0.1.1.zip" } ] }