forked from Tanganelli/CoAPthon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp_coap_proxy.py
275 lines (234 loc) · 9.08 KB
/
http_coap_proxy.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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
import argparse
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from coapthon.client.helperclient import HelperClient
from coapthon.utils import parse_uri
from coapthon.defines import Codes, DEFAULT_HC_PATH, HC_PROXY_DEFAULT_PORT, COAP_DEFAULT_PORT, LOCALHOST, BAD_REQUEST, \
NOT_IMPLEMENTED, CoAP_HTTP
from coapthon.defines import COAP_PREFACE
from urlparse import urlparse
__author__ = "Marco Ieni, Davide Foti"
__email__ = "[email protected], [email protected]"
hc_path = DEFAULT_HC_PATH
""" the class that realizes the HTTP-CoAP Proxy """
class HCProxy:
"""
This program implements an HTTP-CoAP Proxy without using external libraries.
It is assumed that URI is formatted like this:
http://hc_proxy_ip:proxy_port/hc/coap://server_coap_ip:server_coap_port/resource
You can run this program passing the parameters from the command line or you can use the HCProxy class in your own
project.
"""
def __init__(self, path=DEFAULT_HC_PATH, hc_port=HC_PROXY_DEFAULT_PORT, ip=LOCALHOST,
coap_port=COAP_DEFAULT_PORT):
"""
Initialize the HC proxy.
:param path: the path of the hc_proxy server
:param hc_port: the port of the hc_proxy server
:param ip: the ip of the hc_proxy server
:param coap_port: the coap server port you want to reach
"""
global hc_path
hc_path = HCProxy.get_formatted_path(path)
self.hc_port = hc_port
self.ip = ip
self.coap_port = coap_port
def run(self):
"""
Start the proxy.
"""
server_address = (self.ip, self.hc_port)
hc_proxy = HTTPServer(server_address, HCProxyHandler)
print 'Starting HTTP-CoAP Proxy...'
hc_proxy.serve_forever() # the server listen to http://ip:hc_port/path
@staticmethod
def get_formatted_path(path):
"""
Uniform the path string
:param path: the path
:return: the uniform path
"""
if path[0] != '/':
path = '/' + path
if path[-1] != '/':
path = '{0}/'.format(path)
return path
class CoapUri: # this class takes the URI from the HTTP URI
""" Class that can manage and inbox the CoAP URI """
def __init__(self, coap_uri):
self.uri = coap_uri
self.host, self.port, self.path = parse_uri(coap_uri)
def get_uri_as_list(self):
"""
Split the uri into <scheme>://<netloc>/<path>;<params>?<query>#<fragment>
:return: the split uri
"""
return urlparse(self.uri)
def get_payload(self):
"""
Return the query string of the uri.
:return: the query string as a list
"""
temp = self.get_uri_as_list()
query_string = temp[4]
if query_string == "":
return None # Bad request error code
query_string_as_list = str.split(query_string, "=")
return query_string_as_list[1]
def __str__(self):
return self.uri
class HCProxyHandler(BaseHTTPRequestHandler):
""" It maps the requests from HTTP to CoAP """
coap_uri = None
client = None
def set_coap_uri(self):
"""
Create a CoAP Uri
"""
self.coap_uri = CoapUri(self.path[len(hc_path):])
def do_initial_operations(self):
"""
Setup the client for interact with remote server
"""
if not self.request_hc_path_corresponds():
# the http URI of the request is not the same of the one specified by the admin for the hc proxy,
# so I do not answer
# For example the admin setup the http proxy URI like: "http://127.0.0.1:8080:/my_hc_path/" and the URI of
# the requests asks for "http://127.0.0.1:8080:/another_hc_path/"
return
self.set_coap_uri()
self.client = HelperClient(server=(self.coap_uri.host, self.coap_uri.port))
def do_GET(self):
"""
Perform a GET request
"""
self.do_initial_operations()
coap_response = self.client.get(self.coap_uri.path)
self.client.stop()
print "Server response: ", coap_response.pretty_print()
self.set_http_response(coap_response)
def do_HEAD(self):
"""
Perform a HEAD request
"""
self.do_initial_operations()
# the HEAD method is not present in CoAP, so we treat it
# like if it was a GET and then we exclude the body from the response
# with send_body=False we say that we do not need the body, because it is a HEAD request
coap_response = self.client.get(self.coap_uri.path)
self.client.stop()
print "Server response: ", coap_response.pretty_print()
self.set_http_header(coap_response)
def do_POST(self):
"""
Perform a POST request
"""
# Doesn't do anything with posted data
# print "uri: ", self.client_address, self.path
self.do_initial_operations()
payload = self.coap_uri.get_payload()
if payload is None:
print "BAD POST REQUEST"
self.send_error(BAD_REQUEST)
return
coap_response = self.client.post(self.coap_uri.path, payload)
self.client.stop()
print "Server response: ", coap_response.pretty_print()
self.set_http_response(coap_response)
def do_PUT(self):
"""
Perform a PUT request
"""
self.do_initial_operations()
payload = self.coap_uri.get_payload()
if payload is None:
print "BAD PUT REQUEST"
self.send_error(BAD_REQUEST)
return
print payload
coap_response = self.client.put(self.coap_uri.path, payload)
self.client.stop()
print "Server response: ", coap_response.pretty_print()
self.set_http_response(coap_response)
def do_DELETE(self):
"""
Perform a DELETE request
"""
self.do_initial_operations()
coap_response = self.client.delete(self.coap_uri.path)
self.client.stop()
print "Server response: ", coap_response.pretty_print()
self.set_http_response(coap_response)
def do_CONNECT(self):
"""
Perform a CONNECT request. Reply with error, not implemented in CoAP
"""
self.send_error(NOT_IMPLEMENTED)
def do_OPTIONS(self):
"""
Perform a OPTIONS request. Reply with error, not implemented in CoAP
"""
self.send_error(NOT_IMPLEMENTED)
def do_TRACE(self):
"""
Perform a TRACE request. Reply with error, not implemented in CoAP
"""
self.send_error(NOT_IMPLEMENTED)
def request_hc_path_corresponds(self):
"""
Tells if the hc path of the request corresponds to that specified by the admin
:return: a boolean that says if it corresponds or not
"""
uri_path = self.path.split(COAP_PREFACE)
request_hc_path = uri_path[0]
print "HCPATH: ", hc_path
# print HC_PATH
print "URI: ", request_hc_path
if hc_path != request_hc_path:
return False
else:
return True
def set_http_header(self, coap_response):
"""
Sets http headers.
:param coap_response: the coap response
"""
print "Server: ", coap_response.source
print "codice risposta: ", coap_response.code
print "PROXED: ", CoAP_HTTP[Codes.LIST[coap_response.code].name]
print "payload risposta: ", coap_response.payload
self.send_response(int(CoAP_HTTP[Codes.LIST[coap_response.code].name]))
self.send_header('Content-type', 'text/html')
self.end_headers()
def set_http_body(self, coap_response):
"""
Set http body.
:param coap_response: the coap response
"""
if coap_response.payload is not None:
body = "<html><body><h1>", coap_response.payload, "</h1></body></html>"
self.wfile.write("".join(body))
else:
self.wfile.write("<html><body><h1>None</h1></body></html>")
def set_http_response(self, coap_response):
"""
Set http response.
:param coap_response: the coap response
"""
self.set_http_header(coap_response)
self.set_http_body(coap_response)
return
def get_command_line_args():
parser = argparse.ArgumentParser(description='Run the HTTP-CoAP Proxy.')
parser.add_argument('-p', dest='path', default=DEFAULT_HC_PATH,
help='the path of the hc_proxy server')
parser.add_argument('-hp', dest='hc_port', default=HC_PROXY_DEFAULT_PORT,
help='the port of the hc_proxy server')
parser.add_argument('-ip', dest='ip', default=LOCALHOST,
help='the ip of the hc_proxy server')
parser.add_argument('-cp', dest='coap_port', default=COAP_DEFAULT_PORT,
help='the coap server port you want to reach')
return parser.parse_args()
if __name__ == "__main__":
args = get_command_line_args()
hc_proxy = HCProxy(args.path, int(args.hc_port), args.ip, args.coap_port)
hc_proxy.run()