4
4
r'''
5
5
learning.py
6
6
7
- A Python 3 tutorial from http ://www.liaoxuefeng.com
7
+ A Python 3 tutorial from https ://www.liaoxuefeng.com
8
8
9
9
Usage:
10
10
11
11
python3 learning.py
12
12
'''
13
13
14
+ # check #######################################################################
15
+
14
16
import sys
17
+ from datetime import datetime
18
+
19
+ CERT_EXPIRES = '2018-07-01'
15
20
16
21
def check_version ():
17
22
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 ))
24
26
exit (1 )
25
27
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
27
40
from urllib import parse
28
- from wsgiref . simple_server import make_server
41
+ from http . server import HTTPServer , BaseHTTPRequestHandler , SimpleHTTPRequestHandler
29
42
30
43
EXEC = sys .executable
31
44
PORT = 39093
32
- HOST = 'local.liaoxuefeng.com:%d' % PORT
33
45
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 )
35
109
36
110
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 )
38
114
print ('Ready for Python code on port %d...' % PORT )
115
+ print ('Press Ctrl + C to exit...' )
39
116
httpd .serve_forever ()
40
117
118
+ # functions ###################################################################
119
+
120
+ INDEX = 0
121
+
41
122
def get_name ():
42
123
global INDEX
43
124
INDEX = INDEX + 1
@@ -56,51 +137,112 @@ def decode(s):
56
137
except UnicodeDecodeError :
57
138
return s .decode ('gbk' )
58
139
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 ##########################################################
104
246
105
247
if __name__ == '__main__' :
106
248
main ()
0 commit comments