Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Delete Idris source, add Literate Programming document |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
06ec941e6024f56b388889a9cab41ad3 |
| User & Date: | sehqlr 2017-12-17 21:56:51.465 |
Context
|
2017-12-21
| ||
| 02:00 | Renamed the org file, and finally got the GET requests to work check-in: fdaa20eb53 user: sehqlr tags: trunk | |
|
2017-12-17
| ||
| 21:56 | Delete Idris source, add Literate Programming document check-in: 06ec941e60 user: sehqlr tags: trunk | |
|
2017-12-05
| ||
| 17:19 | more changes to org file check-in: 87058bb2cc user: sehqlr tags: trunk | |
Changes
Deleted DataStore.idr.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to Project.org.
1 2 3 4 5 | #+TITLE: Static: a semi-dynamic documents-as-database web content management system This is a literate programming document for this project. Version control will be Fossil SCM. | > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | > > | | < < | | | > > > | | | < > | | > > > > > > > > > | | < > > > | < < > > > | | | | | > > > > | | > | < > | | < < < > > > < < < > > > > < < | | > > > < < > | | | < > > > > | | < > > | | | > < | | | > > > > | > > | < | | < < | < < > | | > > > > > > > > > | > > > | > > > > > < > > > > > | | > | | | < > > < > > > > | < < > | > > > > | > | > | < < > | > | > | | < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
#+TITLE: Static: a semi-dynamic documents-as-database web content management system
# Local Variables:
# org-src-preserve-indentation: t
# End:
This is a literate programming document for this project. Version control will
be Fossil SCM.
* Overview
** What does the tagline mean?
The tagline for this project is, "a database-as-document web content
management system". Since these are pre-buzzwords, no one can guess the meaning.
*** "semi-dynamic" means blending the best parts of static and dynamic sites
Web sites and applications are either static files only or
static template files injected with data, AKA "dynamic web
pages". This system will be a hybrid of the two. The first
iterations of this project will only support the static site
half of the equation first, since the dynamic site features
depend on them.
*** "database-as-documents" means whole documents are stored in a database
HTTP revolves around documents, which are typically stored within a web
servers' file system. Dynamic sites combine static template files with
queries to a data store. I want to create is a system where all of the
documents on a server are wholly within a database system, and HTTP
requests are mapped to SQL statements. There are a lot of technical
implications with this kind of system, especially when it comes to
security, which we'll explore.
*** Web Content Management System means an integrated tool
I want an integrated tool that handles the web server, document
versioning, static site generation, and everything else that developers
know how to do today, but can also be used by normal folks. I also want
a tool that can run locally and remotely the same, like Fossil SCM.
** What this document is
This is going to be a Literate Programming document, where I sketch out the
system from a high level and then drill down on each part. Each part should
include any testing that verifies the code. Because =org-mode= makes it really
easy to tangle one document into multiple files, the code base will conform to
a conventional shape for whatever language it is in.
I plan on using Python as the language of the first prototype, since I've
worked with Python the longest. However, once I understand that
implementation, I plan on rewriting it in Haskell.
* The Code
In this section, I specify and then implement the different components of this
application, and define some tests for them as well. Each component will have
its own section.
** Document schema
All of the code snippets below assume this schema for the =documents= table.
#+NAME: documents schema
#+BEGIN_SRC sql
DROP TABLE IF EXISTS documents;
CREATE TABLE documents (
id PRIMARY KEY,
fpath TEXT,
content BLOB
);
#+END_SRC
** Running the server
This is lifted directly from the [[https://docs.python.org/3/library/http.server.html][=http.server= documentation on python.org]].
#+NAME: run the server
#+BEGIN_SRC python
def run(server_class=HTTPServer, handler_class=BaseHTTPRequestHandler):
server_address = ('', 8000)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
#+END_SRC
** Make file
Since I'm going to be dealing with a server and a database, I'm going to
write a =Makefile= to manage it.
*** =website.db= target
Create a fresh DB file when we change the schema
#+NAME: website make target
#+BEGIN_SRC makefile
website.db: schema.sql
$(RM) website.db
cat schema.sql | sqlite3 website.db
#+END_SRC
*** =all= target
#+NAME: all make target
#+BEGIN_SRC makefile
.PHONY: all
all: database
#+END_SRC
** =StaticRequestHandler= class
The next thing I need to do is define =StaticRequestHandler=, the class that
I'll pass into the =run= function. I'll start by defining a new class that
inherits from =BaseHTTPRequestHandler=.
#+BEGIN_SRC python
class StaticRequestHandler(BaseHTTPRequestHandler):
pass
#+END_SRC
#+NAME: StaticRequestHandler class
#+BEGIN_SRC python :export none :noweb yes
class StaticRequestHandler(BaseHTTPRequestHandler):
<<GET method>>
#+END_SRC
The =StaticRequestHandler= class will match the URL of the request to a SQL
query, send that query, get the document, and return the document to the
HTTP client.
*** Get a document by ID
If you know what document you need by ID, fetch that from the DB directly.
I believe that this will be the easiest to implement, and it'll be what is
used for accessing a page long term. In this way, the URL for these will be
like a citation link.
According the docs, I my Handler needs to define a method named =do_GET= to
process =GET= requests. I'll add that method first.
#+BEGIN_SRC python
def do_GET(self):
pass
#+END_SRC
#+NAME: GET method
#+BEGIN_SRC python
def do_GET(self):
self.wfile = self.path
#+END_SRC
According to the docs, the path of the request is stored in =self.path=. At
first, I was going to write a test/REPL command to take a look at the type
interactively, but I forgot that Python has cOOPling making it really hard
to test in the small. I guess I'll have to write a make target to run the
server and test it in the shell.
#+NAME: server make target
#+BEGIN_SRC makefile
server:
chmod 755 static.py && ./static.py
#+END_SRC
*** Get a document by path
This is the original vision for this project. The =static= web server
should behave exactly like a regular web server, where paths correspond
with documents.
*** Error pages, especially 404
If the document doesn't exist in the database, the class should be able to
return a 404 page, preferably from the database as well. That leads me to
conclude that the database should have error pages in a separate table
where they are indexed solely by HTTP status code.
#+NAME: error pages schema
#+BEGIN_SRC sql
DROP TABLE IF EXISTS error_pages;
CREATE TABLE error_pages (
status_code INT PRIMARY KEY,
page BLOB
);
#+END_SRC
* Files
** =static.py=
#+BEGIN_SRC python :tangle static.py :noweb yes
#!/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
import sqlite3
<<run the server>>
<<StaticRequestHandler class>>
def main():
run(handler_class=StaticRequestHandler)
if __name__ == "__main__":
main()
#+END_SRC
** =test.py=
#+BEGIN_SRC python :tangle test.py :noweb yes
import unittest
import .static
#+END_SRC
** =Makefile=
#+BEGIN_SRC makefile :tangle Makefile :noweb yes
<<all make target>>
<<website make target>>
<<server make target>>
#+END_SRC
** =schema.sql=
#+BEGIN_SRC sql :tangle schema.sql :noweb yes
<<docuemnts schema>>
<<error pages schema>>
#+END_SRC
|
Deleted main.idr.
|
| < < |