0xGA: Check-in [e93a96317e]

Yet another PHP framework, but made for org-mode and geeks.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:First bit of code
Timelines: family | ancestors | descendants | both | narv
Files: files | file ages | folders
SHA1:e93a96317eb496bd99967e5013b05abd35e9885c
User & Date: milouse 2014-05-01 00:28:14
Context
2014-05-03
00:14
Add default error page template and better regex for routes check-in: 0b81284ae3 user: milouse tags: narv
2014-05-01
00:28
First bit of code check-in: e93a96317e user: milouse tags: narv
00:01
tiny doc + ignore list check-in: 95f1b3168c user: milouse tags: narv
Changes

Added narv.















































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
#!/usr/bin/env bash

if ! which python3 &> /dev/null ; then
    echo "You must have python3 installed on your computer to use Narv."
    exit 1
fi

function usage_help {
    cat <<EOF
Narv - Tiny org-mode file server

Platform: `uname -o` `uname -r`; `python3 --version`

Usage: $0 [command] [args] <appname>

Where command should be one of:

help: show general help
init: initialize a new narv repository
create: initialize a new website
start: start narv server (require root priviledges to chroot)
stop: stop narv server (require root priviledges to chroot)
restart: restart narv server (require root priviledges to chroot)

And args could be:

--dest|-d <value>: working repository. Default is pwd
--host|-H <value>: domain name of your website. Default is localhost
EOF
}

function narv_start {
    if [ -f "$WORKINGREP/var/$APPNAME.pid" ] ; then
        echo "Your Narv application is already running."
        exit 1;
    fi
    echo -n "Starting $WORKINGREP/usr/bin/$APPNAME.py"
    $WORKINGREP/usr/bin/$APPNAME.py &>> $WORKINGREP/var/log/$APPNAME.log &
    pgrep -f $APPNAME.py > $WORKINGREP/var/$APPNAME.pid
    echo "                   [OK]"
}

function narv_stop {
    if [ ! -f "$WORKINGREP/var/$APPNAME.pid" ] ; then
        echo "Your Narv application is NOT running."
        exit 1;
    fi
    echo -n "Stopping $WORKINGREP/usr/bin/$APPNAME.py"
    pkill -f $APPNAME.py
    rm $WORKINGREP/var/$APPNAME.pid
    echo "                   [OK]"
}

function narv_restart {
    if [ ! -f "$WORKINGREP/var/$APPNAME.pid" ] ; then
        echo "Your Narv application is NOT running."
        exit 1;
    fi
    echo -n "Stopping $WORKINGREP/usr/bin/$APPNAME.py"
    pkill -f $APPNAME.py
    echo "                   ..."
    echo -n "Starting $WORKINGREP/usr/bin/$APPNAME.py"
    $WORKINGREP/usr/bin/$APPNAME.py &>> $WORKINGREP/var/log/$APPNAME.log &
    pgrep -f $APPNAME.py > $WORKINGREP/var/$APPNAME.pid
    echo "                   [OK]"
}

function init_chroot {
    if [ "$UID" != "0" ] ; then
        echo "You must be root to create the chroot"
        return
    fi

    # Programs to add in the chroot for minimal functionnalities
    BINS="bash env false python3"
    echo "Populate new chroot... Please wait"

    for basecommand in $BINS ; do
        # Look for the totality of involved binaries per program
        all=`whereis -b $basecommand | cut -f2 -d":"`

        for comm in $all ; do
            # Create parent folder and copy current binary
            mkdir -p $WORKINGREP`dirname $comm` > /dev/null 2>&1
            cp -R -L "$comm" $WORKINGREP`dirname $comm`

            # Find related lib and copy them to the chroot
            for f in `ldd $comm 2>/dev/null | cut -f2 -d ">" | cut -f1 -d "(" ` ; do
                if [[ -f $f || -h $f ]]; then
                    mkdir -p $WORKINGREP`dirname $f` > /dev/null 2>&1
                    cp -R -L "$f" $WORKINGREP`dirname $f`
                fi
            done
        done
    done

    # We need this lib from threading too
    cp -R -L /usr/lib/libgcc_s.so.1 $WORKINGREP/usr/lib/

    # Creating /dev/null
    install -dm 755 $WORKINGREP/dev
    mknod $WORKINGREP/dev/null c 1 3

    # Creating urandom
    mknod -m 0444 $WORKINGREP/dev/random c 1 8
    mknod -m 0444 $WORKINGREP/dev/urandom c 1 9

    exec 6>&1 # bind fd #6 to stdout (save stdout)
    exec > $WORKINGREP/etc/passwd # redirect stdout to etc/passwd
    cat <<EOF
root:x:0:0:root:/root:/bin/bash
nobody:x:1:1:nobody:/:/bin/false
EOF
    
    exec > $WORKINGREP/etc/group # redirect stdout to etc/group
    cat <<EOF
root:x:0:root
nobody:x:1:
EOF

    exec 1>&6 6>&- # Restore stdout and close fd #6
    chmod 644 $WORKINGREP/etc/passwd
    chmod 644 $WORKINGREP/etc/group    


    # Creating /bin for compatibility. Link MUST be local
    if [ ! -e "$WORKINGREP/bin" ] ; then
        cd $WORKINGREP
        ln -s usr/bin
    fi

    echo "Chroot created"
}


APPNAME=$USER
FOSSILFILE=/dev/null
COMMAND="help"
WORKINGREP=`pwd`
DOMAINNAME='localhost'

if [ $# -gt 0 ] ; then
    while [ -n "$1" ] ; do
        case $1 in
            --dest|-d)
                shift
                WORKINGREP=`realpath $1`
                ;;
            --fossil|-f)
                shift
                FOSSILFILE=`realpath $1`
                ;;
            --host|-H)
                shift
                DOMAINNAME=$1
                ;;
            console|create|init|init-chroot|restart|start|stop|-h|'help')
                COMMAND=$1
                ;;
            *)
                APPNAME=$1
                ;;
        esac
        shift
    done
fi

if [ "$WORKINGREP" = "/" ] ; then
    echo ""
    echo "DO NOT RUN THIS SCRIPT AT THE ROOT OF YOUR SYSTEM, YOU FOOL"
    echo ""
    echo "Please choose a more appropriate destination"
    echo "like /srv/http, /home/whatever/public_html or /var/www"
    exit 1
fi

case $COMMAND in
    -h|'help')
        usage_help
        ;;
    init)
        if [ -z "$WORKINGREP" ] ; then
            echo
            echo "Please provide necessary informations:"
            echo
            echo "--dest|-d: Destination folder of your installation"
            echo
            echo "If you have any doubt, please see help"
            echo "$0 help"
        fi

        if [ `dirname $FOSSILFILE` = "$WORKINGREP" ] ; then
            echo "For security reasons, install directory and fossil directory MUST be different."
            exit 1
        fi

        echo "Narv init"
        # echo ":: will save fossil repository file in $FOSSILFILE"
        echo ":: will init Narv in $WORKINGREP"

        if [ -e "$WORKINGREP" ] ; then
            echo
            echo "ERROR: $WORKINGREP already exists on your system."
            echo
            echo "If you really wants to do a fresh install at this place, remove it first.
This program will now exit to let you do all the necessary things before."
            exit 1
        fi

        #echo ":: fetching sources"
        #fossil clone http://projects.depar.is/0xGA $FOSSILFILE

        mkdir $WORKINGREP
        #fossil open $FOSSILFILE >/dev/null
        #fossil close

        echo ":: creating shared necessary directories structure"
	install -dm 755 $WORKINGREP/var/log
	install -dm 777 $WORKINGREP/var/tmp
	install -dm 755	$WORKINGREP/usr/bin
	install -dm 755	$WORKINGREP/etc

	install -Dm 755 narv.py $WORKINGREP/usr/bin
	install -Dm 755 narv    $WORKINGREP/usr/bin

        # Init the stuffs needed for chrooting

        echo "General installation finished."
        echo "You may now want to create your first app by entering the command:"
        echo "$WORKINGREP/usr/bin/narv create [-d $WORKINGREP] <appname>"
        ;;
    create)
        if [ -z $APPNAME -o -z $DOMAINNAME ]; then
            echo
            echo "Please provide necessary informations:"
            echo
            echo "--dest|-d: Destination folder of your installation"
            echo "--host|-H: Domain name of your application"
            echo "<appname>: Name of your application"
            echo
            echo "If you have any doubt, please see help"
            echo "$0 help"
        fi

        echo ":: configuring new Website"
        install -dm 755 $WORKINGREP/home/$APPNAME/.themes
        install -dm 755 $WORKINGREP/srv/$APPNAME

        exec 6>&1 # bind fd #6 to stdout (save stdout)
        exec > $WORKINGREP/etc/rc.conf # redirect stdout to etc/rc.conf
        cat <<EOF
[$DOMAINNAME]
debug = 0
appname = $APPNAME
EOF

        exec > $WORKINGREP/etc/routes.conf
        cat <<EOF
[$DOMAINNAME]
/ = my_first_custom_path
EOF

        exec > $WORKINGREP/usr/bin/$APPNAME.py
        cat <<EOF
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from narv import IcanDoThat
from narv import Narv

class MyBeautifulApp(IcanDoThat):

    def my_first_custom_path(self):
        self.extension = 'html'
        return b'<h1>Hello World!</h1>'


if __name__ == "__main__":
    app = Narv(('', 8000), MyBeautifulApp)
    app.start()
EOF

        exec > $WORKINGREP/var/$APPNAME.el
        cat <<EOF
;;; Default to HTML5
(setq org-html-doctype "html5")
(setq org-html-html5-fancy t)

;;; Disable default org style (you DO want to use your own style)
(setq org-html-head-include-default-style nil)

;;; Project configuration
(setq org-publish-project-alist
      '(
        ("${APPNAME}-org"
         :base-directory "${WORKINGREP}/home/$APPNAME"
         :recursive t
         :publishing-function org-html-publish-to-html
         :publishing-directory "${WORKINGREP}/srv/$APPNAME"
         :base-extension "org"
;;       :language "fr"                     ;; Your language?
;;       :headline-levels 3                 ;; You can customize
;;       :section-numbers nil               ;; the following lines too
;;       :table-of-contents nil
;;       :html-preamble "<h1>My Blog</h1>"
;;       :html-postamble "<p>Still reading?</p>"
;;       :html-head "<link rel=\"stylesheet\" href=\"/.themes/style.css\" type=\"text/css\"/>"
         )
        ("${APPNAME}-data"
         :base-directory "${WORKINGREP}/home/$APPNAME"
         :recursive t
         :base-extension "png\\|jpg\\|pdf\\|ogg"
         :publishing-function org-publish-attachment
         :publishing-directory "${WORKINGREP}/srv/$APPNAME")
        ("${APPNAME}-style"
         :base-directory "${WORKINGREP}/home/${APPNAME}/.themes"
         :recursive t
         :base-extension "css\\|js\\|png\\|jpg\\|otf"
         :publishing-function org-publish-attachment
         :publishing-directory "${WORKINGREP}/srv/${APPNAME}/.themes")
        ("$APPNAME" :components ("${APPNAME}-org" "${APPNAME}-data" "${APPNAME}-style"))))
EOF

        exec 1>&6 6>&- # Restore stdout and close fd #6

        chmod u+x $WORKINGREP/usr/bin/$APPNAME.py

        echo "Application installation finished."
        echo ":: A sample emacs configuration file has been created in
:: $WORKINGREP/$APPNAME.el
:: Feel free to customize it."
        echo
        echo ":: Sample configuration files has been put in
:: $WORKINGREP/etc/
:: Don't forget to review and customize them."
        echo
        echo ":: You may start your new app now by entering the following command:"
        echo
        echo "$0 start"
        ;;
    start)
        narv_start
        ;;
    stop)
        narv_stop
        ;;
    restart)
        narv_restart
        ;;
    init-chroot)
        init_chroot
        ;;
    console)
        cat <<EOF
Narv - Tiny org-mode file server - Console
Platform: `uname -o` `uname -r`; `python3 --version`
EOF
        while [ 0 ] ; do
            echo -n ">> "
            read SUBCOMMAND

            case $SUBCOMMAND in
                'help')
                    usage_help
                    ;;
                'bye'|'exit'|quit)
                    exit 0
                    ;;
                start)
                    narv_start
                    ;;
                stop)
                    narv_stop
                    ;;
                restart)
                    narv_restart
                    ;;
                init-chroot)
                    init_chroot
                    ;;
                *)
                    echo "Wrong command $SUBCOMMAND. Try help"
            esac
        done
        ;;
    *)
        echo "There's something strange
in your neighborhood.
Who ya gonna call?"
        ;;
esac

Added narv.py.

















































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import io
import re
import pwd
import grp
import sys
import signal
import urllib
import shutil
import fnmatch
import threading
import configparser
from http.server import HTTPServer
from http.server import BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
from configparser import ConfigParser


NARV_DEBUG = True
def log(text, force=False):
    global NARV_DEBUG

    if NARV_DEBUG or force:
        print(text)


class ResourceHelper:
    """ Utility to extract and expose various information on resources served """

    content_types = {
        'html': 'text/html; charset=utf-8',
        'jpg': 'image/jpeg',
        'jpeg': 'image/jpeg',
        'png': 'image/png',
        'css': 'text/css; charset=utf-8',
        'otf': 'application/font-sfnt',
        'woff': 'application/font-woff',
        'atom': 'application/atom+xml; charset=utf-8',
        'json': 'application/json; charset=utf-8',
        'js': 'text/javascript; charset=utf-8',
        'py': 'text/plain',
        'el': 'text/plain',
    }

    def __init__(self, request, App):

        self.routes = []
        self.App = App
        self.appname = App.appname

        routes = ConfigParser()
        routes.read('etc/routes.conf')
        if self.App.current_domain in routes:
            self.routes = routes[self.App.current_domain]

        self.request_path = urllib.parse.unquote(request)
        self.resource_path = None
        self.resource_ext = None
        self.resource_is_method = False
        self.content = None
        self.content_type = None


    def guess_content_type(self):

        if self.resource_path == None:
            return

        if self.resource_is_method and self.App.extension != None:
            ext = self.App.extension
        else:
            root, ext = os.path.splitext(self.resource_path)
            ext = ext[1:]

        if ext != '' and ext in self.content_types:

            self.resource_ext = ext
            self.content_type = self.content_types[ext]

            log('[{0}] has extension {1} and content_type {2}'.format(
                self.resource_path, self.resource_ext, self.content_type))


    def test_local_file_exists(self, request):

        log("[{0}] Test if local file {0} exists.".format(request))

        if os.path.isfile(request):
            log("[{0}] Match.".format(request))
            self.resource_path = request
            return True

        return False


    def test_method_exists(self, request):

        log("[{0}] Test if method {0} exists in your App".format(request))
        if request in dir(self.App):
            log("[{0}] Match".format(request))
            self.resource_path = request
            self.resource_is_method = True
            return True


    def extract_interesting_routes(self):
        interesting_routes = []
        tokens = False

        for potential_path in self.routes:
            if fnmatch.fnmatch(self.request_path, potential_path):
                log("[{0}] Found potential match with {1}".format(
                    self.request_path, potential_path
                ))

                expand_wildcards = re.sub(r'\*', '([^/]+)', potential_path)
                tokens = re.search(
                    expand_wildcards,
                    self.request_path
                )

                if tokens:
                    interesting_routes.append(
                        self.routes[potential_path].format(*tokens.groups()))

        return interesting_routes


    def find_route(self):

        loc_path_test = 'srv/{0}{1}'.format(self.appname, self.request_path)
        if self.test_local_file_exists(loc_path_test):
            return True

        log("[{0}] Try to find a candidate in the user defined routes".format(self.request_path))

        for route in self.extract_interesting_routes():
            if self.test_method_exists(route):
                return True

            route = 'srv/{0}/{1}'.format(self.appname, route)
            if self.test_local_file_exists(route):
                return True

        return False


    def parse_content(self, content):
        #content = re.sub(r'\s(src|href)="media/',
        #                 r' \1="{0}/media/'.format(
        #                     os.path.basename(
        #                         os.path.dirname(self.resource_path))),
        #                 content.decode('utf-8'))
        #return bytes(content, 'utf-8')
        return content


    def preprocess_content(self):
        success = True
        if self.resource_is_method:
            log("[{0}] Spawn custom content method".format(self.resource_path))
            self.content = getattr(self.App, self.resource_path)()

            if self.content == None:
                success = False

        self.guess_content_type()
        return success


    def send_content(self):
        if self.resource_is_method:
            self.App.wfile.write(self.content)

        else:
            with open(self.resource_path, 'rb') as f:
                if self.resource_ext == 'html':
                    self.App.wfile.write(
                        self.parse_content(f.read()))

                else:
                    shutil.copyfileobj(f, self.App.wfile)



# TODO: May be usefull !!
class RedirectHandler(BaseHTTPRequestHandler):
    def do_HEAD(s):
        s.send_response(301)
        # s.send_header("Location", REDIRECTIONS.get(s.path, LAST_RESORT))
        s.end_headers()
    def do_GET(s):
        s.do_HEAD()



class IcanDoThat(BaseHTTPRequestHandler):
    """ Main HTTP handler """
    server_version = '0xGA/0.1'

    def __init__(self, request, client_address, server):
        self.error = False
        self.extension = None
        self.current_domain = server.server_name
        self.current_port = server.server_port

        BaseHTTPRequestHandler.__init__(self, request, client_address, server)


    def load_config(self):
        host_infos = self.headers.get('host','').split(':')
        self.current_domain = host_infos[0]
        log('Request for {0} processed by {1}'.format(
            self.current_domain,
            threading.currentThread().getName()))

        config = ConfigParser()
        config.read('etc/rc.conf')

        if not self.current_domain in config:
            self.error = 'Domain is not reachable in configuration file'

        else:
            self.config = config[self.current_domain]
            global NARV_DEBUG
            NARV_DEBUG = self.config.getboolean('debug')

            self.appname = None
            if 'appname' in self.config:
                self.appname = self.config['appname']
                log('Request is for App {0}'.format(self.appname))

            else:
                self.error = 'No claimed application in config file'


    def do_404(self, reason='File not found'):
        log('[Error 404] {0}'.format(reason), True)
        self.build_headers(404)
        self.wfile.write(bytes(reason, 'utf-8'))


    def do_501(self, reason='Lack of configuration'):
        log('[Error 501] {0}'.format(reason), True)
        self.build_headers(501)
        self.wfile.write(bytes(reason, 'utf-8'))


    def build_headers(self, resno, content_type = 'text/plain'):
        self.send_response(resno)
        if content_type != None:
            self.send_header('Content-Type', content_type)
        self.end_headers()


    def do_GET(self):
        self.load_config()

        if not self.error:
            rh = ResourceHelper(self.path, self)

            if rh.find_route() and rh.preprocess_content():
                self.build_headers(200, rh.content_type)
                rh.send_content()

            else:
                self.do_404()

        else:
            self.do_501(self.error)



class NarvThreadedServer(ThreadingMixIn, HTTPServer):
    """Main threaded server"""


class Narv:
    def __init__(self, server_infos=('', 8000), request_handler=IcanDoThat):

        signal.signal(signal.SIGINT, self.shutdown)
        signal.signal(signal.SIGTERM, self.shutdown)

        self.server = NarvThreadedServer(server_infos, request_handler)
        server_thread = threading.Thread(target=self.server.serve_forever)
        server_thread.daemon = True
        server_thread.start()

        narv_root_path = os.path.normpath(os.path.join(
            os.path.dirname(os.path.abspath(__file__)),
            '../../'))

        if os.getuid() == 0:
            os.chroot(narv_root_path)
            os.chdir("/")
            log("Dropping priviledges to UID {0} GID {1}".format('nobody', 'nobody'))

            # Remove group privileges
            os.setgroups([])

            # Try setting the new uid/gid
            os.setgid(grp.getgrnam('nobody').gr_gid)
            os.setuid(pwd.getpwnam('nobody').pw_uid)

            # Ensure a very conservative umask
            os.umask(int('077', 8))
        else:
            os.chdir(narv_root_path)


    def start(self):
        log("Serving {0} at port {1}".format(self.server.server_name, self.server.server_port))
        self.server.serve_forever()


    def shutdown(self, signal, frame):
        log("\nKthxbye", True)
        self.server.shutdown()
        sys.exit(0)



if __name__ == "__main__":
    app = Narv()
    app.start()