CoAP/coapthon/layers/forwardLayer.py
Giacomo Tanganelli 7987ac9f4b
Merge pull request #14 from hahahannes/own_well_known_endpoint
added possibility to define own .well-known-core endpoint
2021-01-17 11:56:34 +01:00

173 lines
6.9 KiB
Python

import copy
import logging
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'
logger = logging.getLogger(__name__)
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
"""
wkc_resource_is_defined = defines.DISCOVERY_URL in self._server.root
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 and not wkc_resource_is_defined:
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
logger.info("forward_request - " + str(request))
response = client.send_request(request)
client.stop()
logger.info("forward_response - " + str(response))
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