################################################################################ # Copyright (C) 2013-2014 by gempa GmbH # # HTTP -- Utility methods which generate HTTP result strings # # Author: Stephan Herrnkind # Email: herrnkind@gempa.de ################################################################################ from twisted.web import http, resource, server, static, util import seiscomp.core import seiscomp.logging from .utils import accessLog, b_str, u_str, writeTSBin VERSION = "1.2.5" ################################################################################ class HTTP: # --------------------------------------------------------------------------- @staticmethod def renderErrorPage(request, code, msg, version=VERSION, ro=None): resp = b"""\ Error %i: %s %s Usage details are available from %s Request: %s Request Submitted: %s Service Version: %s """ noContent = code == http.NO_CONTENT # rewrite response code if requested and no data was found if noContent and ro is not None: code = ro.noData # set response code request.setResponseCode(code) # status code 204 requires no message body if code == http.NO_CONTENT: response = b"" else: request.setHeader("Content-Type", "text/plain; charset=utf-8") reference = b"%s/" % request.path.rpartition(b"/")[0] codeStr = http.RESPONSES[code] date = b_str(seiscomp.core.Time.GMT().toString("%FT%T.%f")) response = resp % ( code, codeStr, b_str(msg), reference, request.uri, date, b_str(version), ) if not noContent: seiscomp.logging.warning( f"responding with error: {code} ({u_str(codeStr)})" ) accessLog(request, ro, code, len(response), msg) return response # --------------------------------------------------------------------------- @staticmethod def renderNotFound(request, version=VERSION): msg = "The requested resource does not exist on this server." return HTTP.renderErrorPage(request, http.NOT_FOUND, msg, version) # --------------------------------------------------------------------------- @staticmethod def renderNotModified(request, ro=None): code = http.NOT_MODIFIED request.setResponseCode(code) request.responseHeaders.removeHeader("Content-Type") accessLog(request, ro, code, 0, None) ################################################################################ class ServiceVersion(resource.Resource): isLeaf = True # --------------------------------------------------------------------------- def __init__(self, version): super().__init__() self.version = version self.type = "text/plain" # --------------------------------------------------------------------------- def render(self, request): request.setHeader("Content-Type", "text/plain; charset=utf-8") return b_str(self.version) ################################################################################ class WADLFilter(static.Data): # --------------------------------------------------------------------------- def __init__(self, path, paramNameFilterList): data = "" removeParam = False with open(path, "r", encoding="utf-8") as fp: for line in fp: lineStripped = line.strip().replace(" ", "") if removeParam: if "" in lineStripped: removeParam = False continue valid = True if " SeisComP FDSNWS Implementation

Parent Directory

SeisComP FDSNWS Web Service

Index of %s

""" # --------------------------------------------------------------------------- def render(self, request): lis = "" if request.path[-1:] != b"/": return util.redirectTo(request.path + b"/", request) for k, v in self.children.items(): if v.isLeaf: continue if hasattr(v, "hideInListing") and v.hideInListing: continue name = u_str(k) lis += f'
  • {name}/
  • \n' return b_str(ListingResource.html % (u_str(request.path), lis)) # --------------------------------------------------------------------------- def getChild(self, path, _request): if not path: return self return NoResource(self.version) ################################################################################ class DirectoryResource(static.File): # --------------------------------------------------------------------------- def __init__(self, fileName, version=VERSION): super().__init__(fileName) self.version = version self.childNotFound = NoResource(self.version) # --------------------------------------------------------------------------- def render(self, request): if request.path[-1:] != b"/": return util.redirectTo(request.path + b"/", request) return static.File.render(self, request) # --------------------------------------------------------------------------- def getChild(self, path, _request): if not path: return self return NoResource(self.version) ################################################################################ class Site(server.Site): def __init__(self, res, corsOrigins): super().__init__(res) self._corsOrigins = corsOrigins # --------------------------------------------------------------------------- def getResourceFor(self, request): seiscomp.logging.debug( f"request ({request.getClientIP()}): {u_str(request.uri)}" ) request.setHeader("Server", f"SeisComP-FDSNWS/{VERSION}") request.setHeader("Access-Control-Allow-Headers", "Authorization") request.setHeader("Access-Control-Expose-Headers", "WWW-Authenticate") self.setAllowOrigin(request) return server.Site.getResourceFor(self, request) # --------------------------------------------------------------------------- def setAllowOrigin(self, req): # no allowed origin: no response header lenOrigins = len(self._corsOrigins) if lenOrigins == 0: return # one origin: add header if lenOrigins == 1: req.setHeader("Access-Control-Allow-Origin", self._corsOrigins[0]) return # more than one origin: check current origin against allowed origins # and return the current origin on match. origin = req.getHeader("Origin") if origin in self._corsOrigins: req.setHeader("Access-Control-Allow-Origin", origin) # Set Vary header to let the browser know that the response depends # on the request. Certain cache strategies should be disabled. req.setHeader("Vary", "Origin")