-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathdemo_server.py
More file actions
160 lines (136 loc) · 6.91 KB
/
demo_server.py
File metadata and controls
160 lines (136 loc) · 6.91 KB
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
# Helios Burn demo server, implemented with RPCFU, original RPCFU license below:
# "RPCFU", a WSGI compliant application, developed with RPC in mind
#############################################################################
# Copyright 2012-2015 Hunter Grubbs <hgrubbs@grubbslab.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#############################################################################
def method_test(**request):
"""
Method is expected to be mangled based on HB rules in this example.
"""
return {"original_request": request}
def header_test(**request):
"""
Headers expected to be mangled based on HB rules in this example.
"""
return {"original_request": request}
def query_string_param_test(**request):
"""
Query string parameters are expected to be mangled based on HB rules in this example.
"""
return {"original_request": request}
url_map = [
{'url': r'^/method_test/{0,1}$', 'function': method_test, 'methods': ('GET', 'PUT', 'POST', 'DELETE')},
{'url': r'^/header_test/{0,1}$', 'function': header_test, 'methods': ('GET', 'PUT', 'POST', 'DELETE')},
{'url': r'^/query_string_param_test/{0,1}$', 'function': query_string_param_test, 'methods': ('GET', 'PUT', 'POST', 'DELETE')},
]
class ExplicitMapper(object):
def __init__(self, url_map):
self.url_map = url_map
def __call__(self, url, **args):
import re
target_function = None
for mapping in self.url_map:
# If method(s) specified in the mapping, skip any requests not matching method(s)
if ('methods' in mapping) and (args['REQUEST_METHOD'] not in mapping['methods']):
continue
m = re.search(mapping['url'], url)
if m is not None:
args.update(m.groupdict())
target_function = mapping['function']
break
if target_function is None:
return {"_status_code": 404, "_status_message": "NOT FOUND"}
try:
return target_function(**args)
except TypeError as e:
return {"error": e.args}
def application(environ, start_response):
import sys
import os
import json
from cgi import FieldStorage
##########################################################################
# Set your script_path first or imports will fail when deployed via WSGI
script_path = os.path.dirname(os.path.realpath(__file__))
##########################################################################
if script_path not in sys.path:
sys.path.append(script_path) # Set path for WSGI
rpc_handler = ExplicitMapper(url_map)
fs_http_args = FieldStorage(fp=environ['wsgi.input'], environ=environ, keep_blank_values=True).list # get GET/POST
http_args = dict() # dict to hold combination of environ & query-string fields
# This var must be checked as not being None type. A POST with no data attached will return None from FieldStorage()
# However, a GET with no data attached will return an iterable with no values.
if fs_http_args is not None:
for arg in fs_http_args: # copy fieldstorage key:value pairs into http_args
http_args[arg.name] = arg.value
for k in environ: # merge environ with http_args
if not k.startswith("wsgi"): # skip the wsgi-prefixed data to keep http_args concise
http_args[k] = environ[k]
rpc_name = environ['PATH_INFO']
response_dict = rpc_handler(rpc_name, **http_args)
# Check for specified status codes, otherwise '200 OK'
if '_status_code' in response_dict:
status_code = response_dict['_status_code']
del response_dict['_status_code']
else:
status_code = '200'
if '_status_message' in response_dict:
status_message = response_dict['_status_message']
del response_dict['_status_message']
else:
status_message = "OK"
return_status = "%s %s" % (status_code, status_message)
# Handle return values that return raw data(eg images and other binary data)
if '_content_type' in response_dict and '_raw_content' in response_dict:
response_headers = [('Content-Type', response_dict['_content_type']),
('Content-Length', str(len(response_dict['_raw_content']))),
('Access-Control-Allow-Methods', 'POST,GET,PUT', 'DELETE'),
('Access-Control-Allow-Origin', '*')
]
if '_content_disposition' in response_dict:
response_headers.append(('Content-Disposition', response_dict['_content_disposition']))
start_response(return_status, response_headers)
return [response_dict['_raw_content']]
# Handle return values that return non-binary, non-json replies (eg a HTML view)
elif '_content_type' in response_dict and '_content' in response_dict:
response_headers = [('Content-Type', response_dict['_content_type']),
('Content-Length', str(len(response_dict['_content'])))]
start_response(return_status, response_headers)
return [response_dict['_content'].encode('utf-8')]
# Handle all other return values as JSON replies
else:
response_dict = json.dumps(response_dict)
response_headers = [('Content-Type', 'application/json'),
('Content-Length', str(len(response_dict))),
('Access-Control-Allow-Methods', 'POST,GET,PUT'),
('Access-Control-Allow-Origin', '*')
]
start_response(return_status, response_headers)
return [response_dict.encode('utf-8')]
# Start debug_server if invoked directly, this is NOT run if loaded by WSGI
if __name__ == "__main__":
debug_server_bind = "0.0.0.0"
debug_server_port = 8080
import sys
try:
from wsgiref.simple_server import make_server
print("Creating debug server on %s:%d" % (debug_server_bind, debug_server_port))
httpd = make_server(debug_server_bind, debug_server_port, application)
print("Server bound, access the debug server at http://%s:%d/<call_name>" %
(debug_server_bind, debug_server_port))
httpd.serve_forever()
except Exception as e:
print("Couldn't bind server to %s:%d - ERROR: %s" % (debug_server_bind, debug_server_port, e))
sys.exit(1)