File: usagestats_server.py

package info (click to toggle)
usagestats 0.5-1
  • links: PTS
  • area: main
  • in suites: stretch
  • size: 172 kB
  • ctags: 73
  • sloc: python: 555; sh: 60; makefile: 17
file content (101 lines) | stat: -rw-r--r-- 3,071 bytes parent folder | download | duplicates (2)
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
"""Simple WSGI script to store the usage reports.
"""


import os
import re
import time


DESTINATION = '.'  # Current directory
MAX_SIZE = 524288  # 512 KiB


date_format = re.compile(br'^[0-9]{2,12}\.[0-9]{1,3}$')


def store(report, address):
    """Stores the report on disk.
    """
    now = time.time()
    secs = int(now)
    msecs = int((now - secs) * 1000)
    submitted_date = filename = None  # avoids warnings
    while True:
        submitted_date = '%d.%03d' % (secs, msecs)
        filename = 'report_%s.txt' % submitted_date
        filename = os.path.join(DESTINATION, filename)
        if not os.path.exists(filename):
            break
        msecs += 1

    lines = [l for l in report.split(b'\n') if l]
    for line in lines:
        if line.startswith(b'date:'):
            date = line[5:]
            if date_format.match(date):
                with open(filename, 'wb') as fp:
                    if not isinstance(address, bytes):
                        address = address.encode('ascii')
                    fp.write(b'submitted_from:' + address + b'\n')
                    fp.write(('submitted_date:%s\n' % submitted_date)
                             .encode('ascii'))
                    fp.write(report)
                return None
            else:
                return "invalid date"
    return "missing date field"


def application(environ, start_response):
    """WSGI interface.
    """

    def send_response(status, body):
        if not isinstance(body, bytes):
            body = body.encode('utf-8')

        start_response(status, [('Content-Type', 'text/plain'),
                                ('Content-Length', '%d' % len(body))])
        return [body]

    if environ['REQUEST_METHOD'] != 'POST':
        return send_response('403 Forbidden', "invalid request")

    # Gets the posted input
    try:
        request_body_size = int(environ['CONTENT_LENGTH'])
    except (KeyError, ValueError):
        return send_response('400 Bad Request', "invalid content length")
    if request_body_size > MAX_SIZE:
        return send_response('403 Forbidden', "report too big")
    request_body = environ['wsgi.input'].read(request_body_size)

    # Tries to store
    response_body = store(request_body, environ.get('REMOTE_ADDR'))
    if not response_body:
        status = '200 OK'
        response_body = "stored"
    else:
        status = '501 Server Error'

    # Sends the response
    return send_response(status, response_body)


if __name__ == '__main__':
    use_werkzeug = os.environ.get('USAGESTATS_SERVER_USE_WERKZEUG', 'no')
    if use_werkzeug.lower() in ('yes', '1', 'y', 'on', 'true'):
        from werkzeug.serving import run_simple

        run_simple('localhost', 8000, application)
    else:
        from twisted.internet import reactor
        from twisted.web import server
        from twisted.web.wsgi import WSGIResource

        resource = WSGIResource(reactor, reactor.getThreadPool(), application)

        site = server.Site(resource)
        reactor.listenTCP(8000, site)
        reactor.run()