CoAP/coapthon/layers/forwardLayer.py
giacomo.tanganelli@for.unipi.it 4db21cd7e7 Porting to Python3
2018-01-23 11:31:46 +01:00

167 lines
6.6 KiB
Python

import copy
from coapthon.messages.request import Request
from coapclient import HelperClient
from coapthon.messages.response import Response
from coapthon import defines
from coapthon.resources.remoteResource import RemoteResource
from coapthon.utils import parse_uri
__author__ = 'Giacomo Tanganelli'
class ForwardLayer(object):
"""
Class used by Proxies to forward messages.
"""
def __init__(self, server):
self._server = server
def receive_request(self, transaction):
"""
Setup the transaction for forwarding purposes on Forward Proxies.
:type transaction: Transaction
:param transaction: the transaction that owns the request
:rtype : Transaction
:return: the edited transaction
"""
uri = transaction.request.proxy_uri
if uri is None:
transaction.response = Response()
transaction.response.destination = transaction.request.source
transaction.response.token = transaction.request.token
transaction.response.type = defines.Types["RST"]
transaction.response.code = defines.Codes.BAD_REQUEST.number
return transaction
host, port, path = parse_uri(uri)
path = str("/" + path)
transaction.response = Response()
transaction.response.destination = transaction.request.source
transaction.response.token = transaction.request.token
return self._forward_request(transaction, (host, port), path)
def receive_request_reverse(self, transaction):
"""
Setup the transaction for forwarding purposes on Reverse Proxies.
:type transaction: Transaction
:param transaction: the transaction that owns the request
:rtype : Transaction
:return: the edited transaction
"""
path = str("/" + transaction.request.uri_path)
transaction.response = Response()
transaction.response.destination = transaction.request.source
transaction.response.token = transaction.request.token
if path == defines.DISCOVERY_URL:
transaction = self._server.resourceLayer.discover(transaction)
else:
new = False
if transaction.request.code == defines.Codes.POST.number:
new_paths = self._server.root.with_prefix(path)
new_path = "/"
for tmp in new_paths:
if len(tmp) > len(new_path):
new_path = tmp
if path != new_path:
new = True
path = new_path
try:
resource = self._server.root[path]
except KeyError:
resource = None
if resource is None or path == '/':
# Not Found
transaction.response.code = defines.Codes.NOT_FOUND.number
else:
transaction.resource = resource
transaction = self._handle_request(transaction, new)
return transaction
@staticmethod
def _forward_request(transaction, destination, path):
"""
Forward requests.
:type transaction: Transaction
:param transaction: the transaction that owns the request
:param destination: the destination of the request (IP, port)
:param path: the path of the request.
:rtype : Transaction
:return: the edited transaction
"""
client = HelperClient(destination)
request = Request()
request.options = copy.deepcopy(transaction.request.options)
del request.block2
del request.block1
del request.uri_path
del request.proxy_uri
del request.proxy_schema
# TODO handle observing
del request.observe
# request.observe = transaction.request.observe
request.uri_path = path
request.destination = destination
request.payload = transaction.request.payload
request.code = transaction.request.code
response = client.send_request(request)
client.stop()
if response is not None:
transaction.response.payload = response.payload
transaction.response.code = response.code
transaction.response.options = response.options
else:
transaction.response.code = defines.Codes.SERVICE_UNAVAILABLE.number
return transaction
def _handle_request(self, transaction, new_resource):
"""
Forward requests. Used by reverse proxies to also create new virtual resources on the proxy
in case of created resources
:type new_resource: bool
:type transaction: Transaction
:param transaction: the transaction that owns the request
:rtype : Transaction
:param new_resource: if the request will generate a new resource
:return: the edited transaction
"""
client = HelperClient(transaction.resource.remote_server)
request = Request()
request.options = copy.deepcopy(transaction.request.options)
del request.block2
del request.block1
del request.uri_path
del request.proxy_uri
del request.proxy_schema
# TODO handle observing
del request.observe
# request.observe = transaction.request.observe
request.uri_path = "/".join(transaction.request.uri_path.split("/")[1:])
request.destination = transaction.resource.remote_server
request.payload = transaction.request.payload
request.code = transaction.request.code
response = client.send_request(request)
client.stop()
transaction.response.payload = response.payload
transaction.response.code = response.code
transaction.response.options = response.options
if response.code == defines.Codes.CREATED.number:
lp = transaction.response.location_path
del transaction.response.location_path
transaction.response.location_path = transaction.request.uri_path.split("/")[0] + "/" + lp
# TODO handle observing
if new_resource:
resource = RemoteResource('server', transaction.resource.remote_server, lp, coap_server=self,
visible=True,
observable=False,
allow_children=True)
self._server.add_resource(transaction.response.location_path, resource)
if response.code == defines.Codes.DELETED.number:
del self._server.root["/" + transaction.request.uri_path]
return transaction