This repository has been archived by the owner on May 18, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 38
/
host_files.py
executable file
·180 lines (153 loc) · 5.73 KB
/
host_files.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
#!/bin/env python
"""Hosts files from the local directory using SSL."""
from __future__ import print_function
import signal
import socket
import ssl
import subprocess
import sys
import threading
killed = False
# pylint: disable=C0411
if sys.version_info.major < 3:
import SimpleHTTPServer
import SocketServer
import urllib
Server = SocketServer.TCPServer
SimpleHTTPRequestHandler = SimpleHTTPServer.SimpleHTTPRequestHandler
urlopen = urllib.urlopen
decode = lambda s: s.decode('string_escape')
else:
from http.server import SimpleHTTPRequestHandler, HTTPServer # pylint: disable=E0401
Server = HTTPServer # pylint: disable=C0103
import urllib.request
urlopen = urllib.request.urlopen
decode = lambda s: bytes(s, 'utf-8').decode('unicode-escape')
class InterruptibleServer(Server):
def __init__(self, server_address, handler):
if sys.version_info.major < 3:
# Python 2's TCPServer is an old style class
Server.__init__(self, server_address, handler)
else:
super().__init__(server_address, handler)
def serve_until_shutdown(self):
global killed
while not killed:
self.handle_request()
class PostCommandsRequestHandler(SimpleHTTPRequestHandler): # pylint: disable=R0903
"""Serves files over GET and handles commands send over POST."""
def do_POST(self): # pylint: disable=C0103
"""Handles POST requests."""
if not self.path.endswith('/'):
# Redirect browser - doing basically what Apache does
self.send_response(301)
self.send_header('Location', self.path + '/')
self.end_headers()
elif self.path == '/command/':
# Forward this request on to the C server, because doing SSL in C
# sounds hard
content_length = int(self.headers.get('Content-Length'))
post_data = self.rfile.read(content_length)
print(post_data)
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', 12345))
sock.sendall(post_data)
except Exception as exc:
print('{}, sending 500'.format(exc))
self.send_response(500)
self.send_header('Content-type', 'text/plain; charset=utf-8')
self.end_headers()
# Firefox keeps expecting to get XML back. If we send back
# plain text, it doesn't error out, but it generates a console
# warning, so let's just play nice
self.wfile.write('<p>Unable to contact pi_pcm; is it running?</p>')
return
finally:
sock.close()
self.send_response(200)
self.end_headers()
elif self.path == '/save/':
content_length = int(self.headers.get('Content-Length'))
post_data = decode(self.rfile.read(content_length))
with open('parameters.json', 'w') as parameters_file:
parameters_file.write(post_data)
self.send_response(200)
self.end_headers()
else:
self.send_response(404)
self.end_headers()
def kill_servers(*_):
global killed
killed = True
def main():
"""Main."""
signal.signal(signal.SIGINT, kill_servers)
# The URL fetching stuff inherits this timeout
socket.setdefaulttimeout(0.25)
# Prevent "address already in use" errors
Server.allow_reuse_address = True
base_cert_file_name = 'www.pi-rc.com'
try:
with open(base_cert_file_name + '.cert'):
pass
except IOError:
print(
'''Chrome requires HTTPS to access the webcam. This script can serve HTTPS
requests, but requires that a self-signed certificate be generated first. When
you access this page, you will get a warning - just click through it. This
script will now generate a self-signed certificate.'''
)
subprocess.call((
'openssl',
'req',
'-new',
'-newkey',
'rsa:4096',
'-days',
'365',
'-nodes',
'-x509',
'-subj',
'/C=US/ST=Denial/L=Springfield/O=Dis/CN={}'.format(base_cert_file_name),
'-keyout',
'{}.key'.format(base_cert_file_name),
'-out',
'{}.cert'.format(base_cert_file_name)
))
print('Starting servers')
secure_port = 4443
server_address = ('0.0.0.0', secure_port)
secure_httpd = InterruptibleServer(server_address, PostCommandsRequestHandler)
secure_httpd.socket = ssl.wrap_socket(
secure_httpd.socket,
server_side=True,
certfile='{}.cert'.format(base_cert_file_name),
keyfile='{}.key'.format(base_cert_file_name),
ssl_version=ssl.PROTOCOL_TLSv1
)
insecure_port = 8080
server_address = ('0.0.0.0', insecure_port)
insecure_httpd = InterruptibleServer(server_address, PostCommandsRequestHandler)
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
skari_org = '149.154.158.78'
# This won't actually make a connection
sock.connect((skari_org, 1))
ip = sock.getsockname()[0]
except socket.gaierror:
ip = 'localhost'
finally:
sock.close()
print(
'Running server on https://{ip}:{secure_port}/ and http://{ip}:{insecure_port}/'.format(
ip=ip,
secure_port=secure_port,
insecure_port=insecure_port
)
)
secure_thread = threading.Thread(target=lambda: secure_httpd.serve_until_shutdown())
secure_thread.start()
insecure_httpd.serve_until_shutdown()
if __name__ == '__main__':
main()