Skip to content

Commit e62485b

Browse files
committed
update learning.py
1 parent e72864f commit e62485b

File tree

1 file changed

+199
-57
lines changed

1 file changed

+199
-57
lines changed

teach/learning.py

Lines changed: 199 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,121 @@
44
r'''
55
learning.py
66
7-
A Python 3 tutorial from http://www.liaoxuefeng.com
7+
A Python 3 tutorial from https://www.liaoxuefeng.com
88
99
Usage:
1010
1111
python3 learning.py
1212
'''
1313

14+
# check #######################################################################
15+
1416
import sys
17+
from datetime import datetime
18+
19+
CERT_EXPIRES = '2018-07-01'
1520

1621
def check_version():
1722
v = sys.version_info
18-
if v.major == 3 and v.minor >= 4:
19-
return True
20-
print('Your current python is %d.%d. Please use Python 3.4.' % (v.major, v.minor))
21-
return False
22-
23-
if not check_version():
23+
if v.major == 3 and v.minor >= 5:
24+
return
25+
print('Your current python is %d.%d. Please use Python 3.6.' % (v.major, v.minor))
2426
exit(1)
2527

26-
import os, io, json, subprocess, tempfile
28+
def check_cert():
29+
today = datetime.now().strftime('%Y-%m-%d')
30+
if today >= CERT_EXPIRES:
31+
print('This learning.py is expired. Please download a newer version.')
32+
exit(1)
33+
34+
check_version()
35+
check_cert()
36+
37+
# start server ################################################################
38+
39+
import os, io, json, subprocess, tempfile, ssl
2740
from urllib import parse
28-
from wsgiref.simple_server import make_server
41+
from http.server import HTTPServer, BaseHTTPRequestHandler, SimpleHTTPRequestHandler
2942

3043
EXEC = sys.executable
3144
PORT = 39093
32-
HOST = 'local.liaoxuefeng.com:%d' % PORT
3345
TEMP = tempfile.mkdtemp(suffix='_py', prefix='learn_python_')
34-
INDEX = 0
46+
47+
HTML_INDEX = r'''
48+
<html>
49+
<head><title>Learning Python</title></head>
50+
<body>
51+
<form method="post" action="/run">
52+
<textarea name="code" style="width:90%;height: 600px"></textarea>
53+
<p><button type="submit">Run</button></p>
54+
</form>
55+
</body>
56+
</html>
57+
'''
58+
59+
class LearningHTTPRequestHandler(BaseHTTPRequestHandler):
60+
61+
def do_GET(self):
62+
if self.path != '/':
63+
return self.send_error(404)
64+
self._sendHttpHeader('text/html')
65+
self._sendHttpBody(HTML_INDEX)
66+
67+
def do_POST(self):
68+
if self.path != '/run':
69+
return self.send_error(400)
70+
print('Prepare code...')
71+
body = self.rfile.read(int(self.headers['Content-length']))
72+
qs = parse.parse_qs(body.decode('utf-8'))
73+
if not 'code' in qs:
74+
return self.send_error(400)
75+
code = qs['code'][0]
76+
r = dict()
77+
try:
78+
fpath = write_py(get_name(), code)
79+
print('Execute: %s %s' % (EXEC, fpath))
80+
r['output'] = decode(subprocess.check_output([EXEC, fpath], stderr=subprocess.STDOUT, timeout=5))
81+
except subprocess.CalledProcessError as e:
82+
r = dict(error='Exception', output=decode(e.output))
83+
except subprocess.TimeoutExpired as e:
84+
r = dict(error='Timeout', output='执行超时')
85+
except subprocess.CalledProcessError as e:
86+
r = dict(error='Error', output='执行错误')
87+
print('Execute done.')
88+
self._sendHttpHeader()
89+
self._sendHttpBody(r)
90+
91+
def _sendHttpHeader(self, contentType='application/json'):
92+
origin = self.headers['Origin'] or 'https://www.liaoxuefeng.com'
93+
self.send_response(200)
94+
self.send_header('Content-Type', contentType)
95+
self.send_header('Access-Control-Allow-Origin', origin)
96+
self.send_header('Access-Control-Allow-Methods', 'GET,POST')
97+
self.send_header('Access-Control-Max-Age', '86400')
98+
self.end_headers()
99+
100+
def _sendHttpBody(self, data):
101+
body = b''
102+
if isinstance(data, bytes):
103+
body = data
104+
elif isinstance(data, str):
105+
body = data.encode('utf-8', errors='ignore')
106+
else:
107+
body = json.dumps(data).encode('utf-8', errors='ignore')
108+
self.wfile.write(body)
35109

36110
def main():
37-
httpd = make_server('127.0.0.1', PORT, application)
111+
certfile = write_cert()
112+
httpd = HTTPServer(('127.0.0.1', PORT), LearningHTTPRequestHandler)
113+
httpd.socket = ssl.wrap_socket(httpd.socket, certfile=certfile, server_side=True)
38114
print('Ready for Python code on port %d...' % PORT)
115+
print('Press Ctrl + C to exit...')
39116
httpd.serve_forever()
40117

118+
# functions ###################################################################
119+
120+
INDEX = 0
121+
41122
def get_name():
42123
global INDEX
43124
INDEX = INDEX + 1
@@ -56,51 +137,112 @@ def decode(s):
56137
except UnicodeDecodeError:
57138
return s.decode('gbk')
58139

59-
def application(environ, start_response):
60-
host = environ.get('HTTP_HOST')
61-
method = environ.get('REQUEST_METHOD')
62-
path = environ.get('PATH_INFO')
63-
if method == 'GET' and path == '/':
64-
start_response('200 OK', [('Content-Type', 'text/html')])
65-
return [b'<html><head><title>Learning Python</title></head><body><form method="post" action="/run"><textarea name="code" style="width:90%;height: 600px"></textarea><p><button type="submit">Run</button></p></form></body></html>']
66-
if method == 'GET' and path == '/env':
67-
start_response('200 OK', [('Content-Type', 'text/html')])
68-
L = [b'<html><head><title>ENV</title></head><body>']
69-
for k, v in environ.items():
70-
p = '<p>%s = %s' % (k, str(v))
71-
L.append(p.encode('utf-8'))
72-
L.append(b'</html>')
73-
return L
74-
if host != HOST or method != 'POST' or path != '/run' or not environ.get('CONTENT_TYPE', '').lower().startswith('application/x-www-form-urlencoded'):
75-
start_response('400 Bad Request', [('Content-Type', 'application/json')])
76-
return [b'{"error":"bad_request"}']
77-
s = environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))
78-
qs = parse.parse_qs(s.decode('utf-8'))
79-
if not 'code' in qs:
80-
start_response('400 Bad Request', [('Content-Type', 'application/json')])
81-
return [b'{"error":"invalid_params"}']
82-
name = qs['name'][0] if 'name' in qs else get_name()
83-
code = qs['code'][0]
84-
headers = [('Content-Type', 'application/json')]
85-
origin = environ.get('HTTP_ORIGIN', '')
86-
if origin.find('.liaoxuefeng.com') == -1:
87-
start_response('400 Bad Request', [('Content-Type', 'application/json')])
88-
return [b'{"error":"invalid_origin"}']
89-
headers.append(('Access-Control-Allow-Origin', origin))
90-
start_response('200 OK', headers)
91-
r = dict()
92-
try:
93-
fpath = write_py(name, code)
94-
print('Execute: %s %s' % (EXEC, fpath))
95-
r['output'] = decode(subprocess.check_output([EXEC, fpath], stderr=subprocess.STDOUT, timeout=5))
96-
except subprocess.CalledProcessError as e:
97-
r = dict(error='Exception', output=decode(e.output))
98-
except subprocess.TimeoutExpired as e:
99-
r = dict(error='Timeout', output='执行超时')
100-
except subprocess.CalledProcessError as e:
101-
r = dict(error='Error', output='执行错误')
102-
print('Execute done.')
103-
return [json.dumps(r).encode('utf-8')]
140+
# certificate #################################################################
141+
142+
def write_cert():
143+
fpath = os.path.join(TEMP, 'local.liaoxuefeng.com.pem')
144+
with open(fpath, 'w', encoding='utf-8') as f:
145+
f.write(CERT_DATA)
146+
return fpath
147+
148+
CERT_DATA = r'''
149+
-----BEGIN RSA PRIVATE KEY-----
150+
MIIEpAIBAAKCAQEA5b3zv77bzN8JShoXkVjXFG9NK342wnfgye+NmuSoRfCMPrwL
151+
GToJZiwxokXGyVY8obmQA69WUgonpuotp0AhDK8bOvykKuX+7MyE36sh9TUVOiIw
152+
6D3ODG2E1K5IIEytfGhuPmeJe3OapnL/lJytlLhonu63VEf+jpYh6I/gXD4hZu1N
153+
tx4rOeJLl3qSFgRgX4oBZtO0d4aHop/XW5XcdaeuJxIW5qw7PxXqlch4h9TUs0Og
154+
udko380DrO9pmTuVXr2rtk6Jy96wDAVwsAiSX85FF59Q3QmjDzM+fx8a/vyWkxOw
155+
9dT0DzfZBJ9g/tPk13ir14U1vPpDMO1lIXjKZQIDAQABAoIBAEp+FwT7W8XII/j1
156+
EOM+DS9BD6KkoBjaSfbwR9gLgEx9PNwymN6rJNUOS2G0gkpSPgKqannnZnPfew/y
157+
Kq9qacz1Ej1EIe8O+GPLxOHJWY9qkOFyqK0FLUR2VnWntRdUBYSrT+PIKpnu2BxU
158+
eW60hswMJ1AxUxxu46lUINaJoFQH7ANHzpCxXFiWDiVK8VCCFS3MaJfqz945zLdg
159+
orHMty+gCcaWRX9wanZ5k9RmX2qzqLAAhlnKIfmItpel8HTppOk1taVDopUgPGd+
160+
8IG7IANbRlykkeBvlA5soSk7RNM2+crHcdCz5ehoSjMHsY3e99EPoPjKQmb3Ak0p
161+
zgtjPpkCgYEA8p+eULq0OM2anLQeOqQe2QNxkTuriOI2qyobOnCYAJRFlxCLJ8K8
162+
OIf+srIJUYzJsGmPSqo8iizM5V9bmBRihYnPwePUJS0af8G2vdeJARoAFBo4LZNi
163+
YBN3Gi6hKo8hDgOPQ6D2a25NXYua4z5HlOb8PU6JhX1/6O6yv4ScZh8CgYEA8miG
164+
QxHbx3a7Zfy3/QCQrEwmbp9k49ex/DZvh50N5MqG9h6lb6+ct+qUT7HkvcXUrBxL
165+
6HP7aLVUTTvo9z10sBh1Kt1UQP/57JbKQNMCYKUbMxZH59XdFPzVwkbyDE7Z29tf
166+
8QEMnk9CM6HbvbQDSvOZ04IsfSEstMEPKqVmFvsCgYEAsOSborRdTcTp4zKXj521
167+
N/gAxyjAKe70eNscOwF4cYOpMTjInFaosHbGxjZ0ANcq/coYxRFVTlDXmqxptXm3
168+
UzFlHjIjrG80EM2FlOgeZYU1ZXKwXtpEMVQ/1AEHVGZCbVs/CsnCoBUtpvRwGxp/
169+
ShsW8QPf1EnqBkRyYpwnA3UCgYA5nrLbWnFddlGRKoMpdmrtKaSxAt5ecjTyeJYG
170+
LETTL3jpI9u7MokUBoR+dRCkM1QcHRXGCVunRgLl4Om9azRDb2zaZYXTdYUYwbcN
171+
tZqJEnXmrNMmvmUwyfCdn3OFjXCnm/uwM8mmD7zyvPSYoSNvO3xDFFwy2iHgTUun
172+
nW0o5QKBgQCF/mCu/z1+CsddcHu1RYjnG08uVk0ErjTLB5Qy0YI2NWVE2zdV9fi9
173+
MWn7S+oEcmjaMdXdF0W/MDyB8TLUSdsXGHPl/vRizK3vhDQGxQ+y3ru8GEVq8BjX
174+
YePMDifbgHDXrCeBeb7TypefD/ScxdVJdI9sPSno20AehzDkXcAssQ==
175+
-----END RSA PRIVATE KEY-----
176+
177+
-----BEGIN CERTIFICATE-----
178+
MIIFzTCCBLWgAwIBAgIQB594sjWBo6qup5zlKa2F7zANBgkqhkiG9w0BAQsFADCB
179+
lzELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs
180+
IEluYy4xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxHTAbBgNVBAsT
181+
FERvbWFpbiBWYWxpZGF0ZWQgU1NMMSEwHwYDVQQDExhUcnVzdEFzaWEgRFYgU1NM
182+
IENBIC0gRzUwHhcNMTcwNzA1MDAwMDAwWhcNMTgwNzA1MjM1OTU5WjAgMR4wHAYD
183+
VQQDDBVsb2NhbC5saWFveHVlZmVuZy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
184+
DwAwggEKAoIBAQDlvfO/vtvM3wlKGheRWNcUb00rfjbCd+DJ742a5KhF8Iw+vAsZ
185+
OglmLDGiRcbJVjyhuZADr1ZSCiem6i2nQCEMrxs6/KQq5f7szITfqyH1NRU6IjDo
186+
Pc4MbYTUrkggTK18aG4+Z4l7c5qmcv+UnK2UuGie7rdUR/6OliHoj+BcPiFm7U23
187+
His54kuXepIWBGBfigFm07R3hoein9dbldx1p64nEhbmrDs/FeqVyHiH1NSzQ6C5
188+
2SjfzQOs72mZO5Vevau2TonL3rAMBXCwCJJfzkUXn1DdCaMPMz5/Hxr+/JaTE7D1
189+
1PQPN9kEn2D+0+TXeKvXhTW8+kMw7WUheMplAgMBAAGjggKJMIIChTAgBgNVHREE
190+
GTAXghVsb2NhbC5saWFveHVlZmVuZy5jb20wCQYDVR0TBAIwADBhBgNVHSAEWjBY
191+
MFYGBmeBDAECATBMMCMGCCsGAQUFBwIBFhdodHRwczovL2Quc3ltY2IuY29tL2Nw
192+
czAlBggrBgEFBQcCAjAZDBdodHRwczovL2Quc3ltY2IuY29tL3JwYTAfBgNVHSME
193+
GDAWgBRtWMd/GufhPy6mjJc1Qrv00zisPzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0l
194+
BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGbBggrBgEFBQcBAQSBjjCBizA8Bggr
195+
BgEFBQcwAYYwaHR0cDovL3RydXN0YXNpYTItb2NzcC5kaWdpdGFsY2VydHZhbGlk
196+
YXRpb24uY29tMEsGCCsGAQUFBzAChj9odHRwOi8vdHJ1c3Rhc2lhMi1haWEuZGln
197+
aXRhbGNlcnR2YWxpZGF0aW9uLmNvbS90cnVzdGFzaWFnNS5jcnQwggEDBgorBgEE
198+
AdZ5AgQCBIH0BIHxAO8AdQDd6x0reg1PpiCLga2BaHB+Lo6dAdVciI09EcTNtuy+
199+
zAAAAV0QuhtTAAAEAwBGMEQCIERpJLcXX4eFEW02eZMh6EYFW236foQrCsakOgQQ
200+
NW96AiBCE6/7vrUxWKf964i4D9z2NA0TCuXm9giVgQaFju0XXQB2AKS5CZC0GFgU
201+
h7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABXRC6G5MAAAQDAEcwRQIhAK4GeiTU
202+
OQcjGFvLAugOMIEKCEuiJsEu0t+f1ql5Edn2AiAUqqLMw87IkjMnJsbEUGsHkng0
203+
KL6MLDC3BaHVcH6HsjANBgkqhkiG9w0BAQsFAAOCAQEAYDU2DSBh/63brAW/VWlQ
204+
PQIZzWhji6209MG5hg/RN3Zo9uoz2GodNWwOSkvcFVUz9oBExLfcfhZAsBz26dgs
205+
abWstAje63oduhXU9MR1LDFfG6GLit0Pou0yiS0hfg3jpxpYCIo97QAe8bkuMdRQ
206+
7V09yKKo44M+iXbkIUivnM1ckYJHU9xQ3y8/q/DQajUmVIEPRzmyz6B3tP4WA11T
207+
X5T89OK6osvLcYSJXvxOeR3J8Ohxdwi+PRX4BCgXgTseOj+biwJuCo9z7uwvCoXG
208+
fdilj1tXNa5eDtSRplqbFB+kPGkP/NZ5b1+huarDqE/aeNpmREqONhxi49KB1/9u
209+
1w==
210+
-----END CERTIFICATE-----
211+
212+
-----BEGIN CERTIFICATE-----
213+
MIIFZTCCBE2gAwIBAgIQOhAOfxCeGsWcxf/2QNXkQjANBgkqhkiG9w0BAQsFADCB
214+
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
215+
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
216+
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
217+
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
218+
aG9yaXR5IC0gRzUwHhcNMTYwODExMDAwMDAwWhcNMjYwODEwMjM1OTU5WjCBlzEL
219+
MAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIElu
220+
Yy4xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxHTAbBgNVBAsTFERv
221+
bWFpbiBWYWxpZGF0ZWQgU1NMMSEwHwYDVQQDExhUcnVzdEFzaWEgRFYgU1NMIENB
222+
IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC39aSJZG/97x3a
223+
6Qmuc9+MubagegRAVUmFYHTYTs8IKB2pM7wXN7W8mekdZaEgUjDFxvRBK/DhTb7U
224+
8ONLsKKdT86aOhzbz2noCTn9wPWnGwkg+/4YKg/dPQQdV9tMsSu0cwqInWHxSAkm
225+
AI1hYFC9D7Sf7Hp/5cRcD+dK454YMRzNOGLQnCVI8JEqrz6o9SOvQNTqTcfqt6DC
226+
0UlXG+MPD1eNPjlzf1Vwaab+VSTgySoC+Ikbq2VsdykeOiGXW/OIiASH7+2LcR05
227+
PmQ7GEOlM8yzoVojFpM8sHz+WxI05ZOPri5+vX3HhHHjWr5432G0dVmgohnZvlVZ
228+
oy8XrlbpAgMBAAGjggF2MIIBcjASBgNVHRMBAf8ECDAGAQH/AgEAMC8GA1UdHwQo
229+
MCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNvbS9wY2EzLWc1LmNybDAOBgNVHQ8B
230+
Af8EBAMCAQYwLgYIKwYBBQUHAQEEIjAgMB4GCCsGAQUFBzABhhJodHRwOi8vcy5z
231+
eW1jZC5jb20wYQYDVR0gBFowWDBWBgZngQwBAgEwTDAjBggrBgEFBQcCARYXaHR0
232+
cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGRoXaHR0cHM6Ly9kLnN5
233+
bWNiLmNvbS9ycGEwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCkGA1Ud
234+
EQQiMCCkHjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0yLTYwMTAdBgNVHQ4EFgQU
235+
bVjHfxrn4T8upoyXNUK79NM4rD8wHwYDVR0jBBgwFoAUf9Nlp8Ld7LvwMAnzQzn6
236+
Aq8zMTMwDQYJKoZIhvcNAQELBQADggEBABUphhBbeG7scE3EveIN0dOjXPgwgQi8
237+
I2ZAKYm6DawoGz1lEJVdvFmkyMbP973X80b7mKmn0nNbe1kjA4M0O0hHaMM1ZaEv
238+
7e9vHEAoGyysMO6HzPWYMkyNxcCV7Nos2Uv4RvLDpQHh7P4Kt6fUU13ipcynrtQD
239+
1lFUM0yoTzwwFsPu3Pk+94hL58ErqwqJQwxoHMgLIQeMVHeNKcWFy1bddSbIbCWU
240+
Zs6cMxhrra062ZCpDCbxyEaFNGAtYQMqNz55Z/14XgSUONZ/cJTns6QKhpcgTOwB
241+
fnNzRnk+aWreP7osKhXlz4zs+llP7goBDKFOMMtoEXx3YjJCKgpqmBU=
242+
-----END CERTIFICATE-----
243+
'''
244+
245+
# start main at last ##########################################################
104246

105247
if __name__ == '__main__':
106248
main()

0 commit comments

Comments
 (0)