Esempio n. 1
0
    def openSession(self):
        # Create connection
        self.connect = SmartHTTPConnection(self.server, self.port, self.ssl,
                                           self.afunix)

        # Write to log file
        if self.loghttp and self.log:
            self.log.write(
                "\n        <-------- BEGIN HTTP CONNECTION -------->\n")
            self.log.write("Server: %s\n" % (self.server, ))
    def openSession(self):
        # Create connection
        self.connect = SmartHTTPConnection(self.server, self.port, self.ssl)

        # Write to log file
        if self.loghttp and self.log:
            self.log.write("\n        <-------- BEGIN HTTP CONNECTION -------->\n")
            self.log.write("Server: %s\n" % (self.server,))
Esempio n. 3
0
def httploop(ctr, config, complete):

    # Random time delay
    time.sleep(random.randint(0, config["interval"]) / 1000.0)

    headers = {}
    headers["User-Agent"] = "httploop/1"
    headers["Depth"] = "1"
    headers["Authorization"] = "Basic " + "admin:admin".encode("base64")[:-1]
    headers["Content-Type"] = "application/json"

    host, port = config["server"].split(":")
    port = int(port)
    interval = config["interval"] / 1000.0
    total = config["limit"] / config["numProcesses"]

    count = 0

    jstr = json.dumps(
        {
            "action": "testwork",
            "when": config["when"],
            "delay": config["delay"],
            "jobs": config["jobs"],
            "priority": PRIORITY[config["priority"]],
            "weight": config["weight"],
        }
    )

    base_time = time.time()
    while not complete.value:
        http = SmartHTTPConnection(host, port, True, False)

        try:
            count += 1
            headers["User-Agent"] = "httploop-{}/{}".format(ctr, count)
            http.request("POST", "/control", jstr, headers)

            response = http.getresponse()
            response.read()

        except Exception as e:
            print("Count: {}".format(count))
            print(repr(e))
            raise

        finally:
            http.close()

        if total != 0 and count >= total:
            break

        base_time += interval
        sleep_time = base_time - time.time()
        if sleep_time < 0:
            print("Interval less than zero: process #{}".format(ctr))
            base_time = time.time()
        else:
            time.sleep(sleep_time)
class CalDAVSession(Session):

    class logger(object):

        def write(self, data):
            print data.replace("\r\n", "\n"),


    def __init__(self, server, port=None, ssl=False, user="", pswd="", principal=None, root=None, logging=False):
        super(CalDAVSession, self).__init__(server, port, ssl, log=CalDAVSession.logger())

        self.loghttp = logging

        self.user = user
        self.pswd = pswd

        # Initialize state
        self.connect = None

        # Paths
        self.rootPath = URL(url=root)
        self.principalPath = URL(url=principal) if principal else None

        self._initCalDAVState()


    def _initCalDAVState(self):

        # We need to cache the server capabilities and properties
        if not self.principalPath:
            self._discoverPrincipal()


    def _discoverPrincipal(self):

        current = self.getCurrentPrincipalResource(self.rootPath)
        if current:
            self.principalPath = current
            if self.log:
                self.log.write("Found current principal path: %s\n" % (self.principalPath.absoluteURL(),))
            return

        hrefs = self.getHrefListProperty(self.rootPath, davxml.principal_collection_set)
        if not hrefs:
            return

        # For each principal collection find current principal
        for href in hrefs:
            current = self.getCurrentPrincipalResource(href)
            if current:
                self.principalPath = current
                if self.log:
                    self.log.write("Found current principal path: %s\n" % (self.principalPath.absoluteURL(),))
                return


    def setUserPswd(self, user, pswd):

        self.user = user
        self.pswd = pswd
        self.authorization = None
        self._discoverPrincipal()


    def testResource(self, rurl):

        assert(isinstance(rurl, URL))

        request = PropFind(self, rurl.relativeURL(), headers.Depth0, (davxml.resourcetype,))

        # Process it
        self.runSession(request)

        return request.getStatusCode() == statuscodes.MultiStatus


    def getPropertyNames(self, rurl):

        assert(isinstance(rurl, URL))

        results = ()

        # Create WebDAV propfind
        request = PropNames(self, rurl.relativeURL(), headers.Depth0)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    results = tuple([name for name in item.getNodeProperties().iterkeys()])

        else:
            self.handleHTTPError(request)

        return results


    def getProperties(self, rurl, props, xmldata=False):

        assert(isinstance(rurl, URL))

        results = {}
        bad = None

        # Create WebDAV propfind
        if props:
            request = PropFind(self, rurl.relativeURL(), headers.Depth0, props)
        else:
            request = PropAll(self, rurl.relativeURL(), headers.Depth0)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):
                    for name, value in item.getTextProperties().iteritems():
                        results[name] = value
                    for name, value in item.getHrefProperties().iteritems():
                        if name not in results:
                            results[name] = value
                    for name, value in item.getNodeProperties().iteritems():
                        if name not in results:
                            results[name] = tostring(value) if xmldata else value
                    bad = item.getBadProperties()
        else:
            self.handleHTTPError(request)

        return results, bad


    def getPropertiesOnHierarchy(self, rurl, props):

        assert(isinstance(rurl, URL))

        results = {}

        # Create WebDAV propfind
        request = PropFind(self, rurl.relativeURL(), headers.Depth1, props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                propresults = {}
                results[name.relativeURL()] = propresults

                for prop in props:

                    if str(prop) in item.getTextProperties():
                        propresults[prop] = item.getTextProperties().get(str(prop))

                    elif str(prop) in item.getNodeProperties():
                        propresults[prop] = item.getNodeProperties()[str(prop)]
        else:
            self.handleHTTPError(request)

        return results


    def getHrefListProperty(self, rurl, propname):

        assert(isinstance(rurl, URL))

        results = ()

        # Create WebDAV propfind
        request = PropFind(self, rurl.relativeURL(), headers.Depth0, (propname,))
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result and extract any Hrefs
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    if str(propname) in item.getNodeProperties():

                        propnode = item.getNodeProperties()[str(propname)]
                        results += tuple([URL(url=href.text, decode=True) for href in propnode.findall(str(davxml.href)) if href.text])
        else:
            self.handleHTTPError(request)

        return results


    # Do principal-match report with self on the passed in url
    def getSelfProperties(self, rurl, props):

        assert(isinstance(rurl, URL))

        results = {}

        # Create WebDAV principal-match
        request = PrincipalMatch(self, rurl.relativeURL(), props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each principal-match result and return first one that is appropriate
            for item in parser.getResults().itervalues():

                for prop in props:

                    if str(prop) in item.getNodeProperties():

                        href = item.getNodeProperties()[str(prop)].find(str(davxml.href))

                        if href is not None:
                            results[prop] = URL(url=href.text, decode=True)

                # We'll take the first one, whatever that is
                break

        else:
            self.handleHTTPError(request)
            return None

        return results


    # Do principal-match report with self on the passed in url
    def getSelfHrefs(self, rurl):

        assert(isinstance(rurl, URL))

        results = ()

        # Create WebDAV principal-match
        request = PrincipalMatch(self, rurl.relativeURL(), (davxml.principal_URL,))
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result and extract any Hrefs
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                results += (name,)

        else:
            self.handleHTTPError(request)
            return None

        return results


    # Do principal-match report with self on the passed in url
    def getSelfPrincipalResource(self, rurl):

        assert(isinstance(rurl, URL))

        hrefs = self.getHrefListProperty(rurl, davxml.principal_collection_set)
        if not hrefs:
            return None

        # For each principal collection find one that matches self
        for href in hrefs:

            results = self.getSelfHrefs(href)
            if results:
                return results[0]

        return None


    # Do current-user-principal property on the passed in url
    def getCurrentPrincipalResource(self, rurl):

        assert(isinstance(rurl, URL))

        hrefs = self.getHrefListProperty(rurl, davxml.current_user_principal)
        return hrefs[0] if hrefs else None


    def setProperties(self, rurl, props):

        assert(isinstance(rurl, URL))

        results = ()

        # Convert property data into something sensible
        converted = []
        for name, value in props:
            node = None
            if isinstance(value, types.StringType):
                node = Element(name)
                node.text = value
            elif isinstance(value, URL):
                node = Element(davxml.href)
                node.text = value.absoluteURL()
            elif isinstance(value, types.ListType) or isinstance(value, types.TupleType):
                hrefs = []
                for item in value:
                    if isinstance(item, URL):
                        href = Element(davxml.href)
                        href.text = item.relativeURL()
                        hrefs.append(href)
                    else:
                        break
                else:
                    node = Element(name)
                    map(node.append, hrefs)

            if node is not None:
                converted.append(node)

        # Create WebDAV propfind
        request = PropPatch(self, rurl.relativeURL(), converted)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    for prop in item.getNodeProperties():
                        results += (prop,)

        else:
            self.handleHTTPError(request)

        return results


    def setACL(self, rurl, aces):

        assert(isinstance(rurl, URL))

        # Create WebDAV ACL
        request = ACL(self, rurl.relativeURL(), aces)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent):
            self.handleHTTPError(request)


    def makeCollection(self, rurl):

        assert(isinstance(rurl, URL))

        # Create WebDAV MKCOL
        request = MakeCollection(self, rurl.relativeURL())

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent):
            self.handleHTTPError(request)


    def makeCalendar(self, rurl, displayname=None, description=None):

        assert(isinstance(rurl, URL))

        # Create WebDAV MKCALENDAR
        request = MakeCalendar(self, rurl.relativeURL(), displayname, description)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent):
            self.handleHTTPError(request)


    def makeAddressBook(self, rurl, displayname=None, description=None):

        assert(isinstance(rurl, URL))

        # Create WebDAV extended MKCOL
        request = MakeAddressBook(self, rurl.relativeURL(), displayname, description)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent):
            self.handleHTTPError(request)


    def syncCollection(self, rurl, synctoken, props=()):

        assert(isinstance(rurl, URL))

        newsynctoken = ""
        changed = set()
        removed = set()
        other = set()

        # Create WebDAV sync REPORT
        request = SyncCollection(self, rurl.relativeURL(), davxml.sync_level_1, synctoken, props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                if item.status == 404:
                    removed.add(name)
                elif item.status / 100 != 2:
                    other.add(name)
                else:
                    changed.add(name)

            # Get the new token
            for node in parser.getOthers():
                if node.tag == davxml.sync_token:
                    newsynctoken = node.text
                    break

        else:
            self.handleHTTPError(request)

        return (newsynctoken, changed, removed, other,)


    def queryCollection(self, rurl, timerange, start, end, expand, props=()):

        assert(isinstance(rurl, URL))

        hrefs = set()

        # Create CalDAV query REPORT
        if timerange:
            request = QueryVEVENTTimeRange(self, rurl.relativeURL(), start, end, expand, props=props)
        else:
            raise NotImplementedError
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                hrefs.add(name)

        else:
            self.handleHTTPError(request)

        return hrefs


    def deleteResource(self, rurl):

        assert(isinstance(rurl, URL))

        # Create WebDAV DELETE
        request = Delete(self, rurl.relativeURL())

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.NoContent):
            self.handleHTTPError(request)


    def moveResource(self, rurlFrom, rurlTo):

        assert(isinstance(rurlFrom, URL))
        assert(isinstance(rurlTo, URL))

        # Create WebDAV MOVE
        request = Move(self, rurlFrom.relativeURL(), rurlTo.absoluteURL())

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent):
            self.handleHTTPError(request)


    def readData(self, rurl):

        assert(isinstance(rurl, URL))

        # Create WebDAV GET
        request = Get(self, rurl.relativeURL())
        dout = ResponseDataString()
        request.setData(dout)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() != statuscodes.OK:
            self.handleHTTPError(request)
            return None

        # Look for ETag
        if request.getNewETag() is not None:

            etag = request.getNewETag()

            # Handle server bug: ETag value MUST be quoted per HTTP/1.1 S3.11
            if not etag.startswith('"'):
                etag = "\"%s\"" % (etag,)
        else:
            etag = None

        # Return data as a string and etag
        return dout.getData(), etag


    def writeData(self, rurl, data, contentType):

        assert(isinstance(rurl, URL))

        # Create WebDAV PUT
        request = Put(self, rurl.relativeURL())
        dout = RequestDataString(data, contentType)
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent,):
            self.handleHTTPError(request)


    def importData(self, rurl, data, contentType):

        assert(isinstance(rurl, URL))

        # Create WebDAV POST
        request = Post(self, rurl.relativeURL())
        dout = RequestDataString(data, contentType)
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (statuscodes.OK, statuscodes.MultiStatus, statuscodes.NoContent,):
            self.handleHTTPError(request)


    def addAttachment(self, rurl, filename, data, contentType, return_representation):

        assert(isinstance(rurl, URL))

        # Create WebDAV POST
        rurl.extended = "?action=attachment-add"
        request = Post(self, rurl.relativeURL())
        dout = RequestDataString(data, contentType)
        request.setRequestHeader("Content-Disposition", "attachment;filename=%s" % (filename,))
        if return_representation:
            request.setRequestHeader("Prefer", "return-representation")
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent,):
            self.handleHTTPError(request)


    def updateAttachment(self, rurl, managed_id, filename, data, contentType, return_representation):

        assert(isinstance(rurl, URL))

        # Create WebDAV POST
        rurl.extended = "?action=attachment-update&managed-id=%s" % (managed_id,)
        request = Post(self, rurl.relativeURL())
        request.setRequestHeader("Content-Disposition", "attachment;filename=%s" % (filename,))
        if return_representation:
            request.setRequestHeader("Prefer", "return-representation")
        dout = RequestDataString(data, contentType)
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent,):
            self.handleHTTPError(request)


    def removeAttachment(self, rurl, managed_id):

        assert(isinstance(rurl, URL))

        # Create WebDAV POST
        rurl.extended = "?action=attachment-remove&managed-id=%s" % (managed_id,)
        request = Post(self, rurl.relativeURL())

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (statuscodes.OK, statuscodes.NoContent,):
            self.handleHTTPError(request)


    def displayHTTPError(self, request):
        print request.status_code


    def openSession(self):
        # Create connection
        self.connect = SmartHTTPConnection(self.server, self.port, self.ssl)

        # Write to log file
        if self.loghttp and self.log:
            self.log.write("\n        <-------- BEGIN HTTP CONNECTION -------->\n")
            self.log.write("Server: %s\n" % (self.server,))


    def closeSession(self):
        if self.connect:
            self.connect.close()
            self.connect = None

            # Write to log file
            if self.loghttp and self.log:
                self.log.write("\n        <-------- END HTTP CONNECTION -------->\n")


    def runSession(self, request):

        ctr = 5
        while ctr:
            ctr -= 1

            self.doSession(request)

            if request and request.isRedirect():
                location = request.getResponseHeader(headers.Location)
                if location:
                    u = URL(location)
                    if not u.scheme or u.scheme in ("http", "https",):
                        # Get new server and base RURL
                        different_server = (self.server != u.server) if u.server else False

                        # Use new host in this session
                        if different_server:
                            self.setServer(u.server)

                        # Reset the request with new info
                        request.setURL(u.relativeURL())
                        request.clearResponse()

                        # Write to log file
                        if self.loghttp and self.log:
                            self.log.write("\n        <-------- HTTP REDIRECT -------->\n")
                            self.log.write("Location: %s\n" % (location,))

                        # Recyle through loop
                        continue

            # Exit when redirect does not occur
            break


    def doSession(self, request):
        # Do initialisation if not already done
        if not self.initialised:

            if not self.initialise(self.server, self.rootPath.relativeURL()):

                # Break connection with server
                self.closeConnection()
                return

        # Do the request if present
        if request:

            # Handle delayed authorization
            first_time = True
            while True:

                # Run the request actions - this will make any connection that is needed
                self.sendRequest(request)

                # Check for auth failure if none before
                if request.getStatusCode() == statuscodes.Unauthorized:

                    # If we had authorization before, then chances are auth details are wrong - so delete and try again with new auth
                    if self.hasAuthorization():

                        self.authorization = None

                        # Display error so user knows why the prompt occurs again - but not the first time
                        # as we might have a digest re-auth.
                        if not first_time:
                            self.displayHTTPError(request)

                    # Get authorization object (prompt the user) and redo the request
                    self.authorization, cancelled = self.getAuthorizor(first_time, request.getResponseHeaders(headers.WWWAuthenticate))

                    # Check for auth cancellation
                    if cancelled:
                        self.authorization = None

                    else:
                        first_time = False

                        request.clearResponse()

                        # Repeat the request loop with new authorization
                        continue

                # If we get here we are complete with auth loop
                break

        # Now close it - eventually we will do keep-alive support

        # Break connection with server
        self.closeConnection()


    def doRequest(self, request):

        # Write request headers
        self.connect.putrequest(request.method, request.url, skip_host=True, skip_accept_encoding=True)
        hdrs = request.getRequestHeaders()
        for header, value in hdrs:
            self.connect.putheader(header, value)
        self.connect.endheaders()

        # Write to log file
        if self.loghttp and self.log:
            self.log.write("\n        <-------- BEGIN HTTP REQUEST -------->\n")
            self.log.write("%s\n" % (request.getRequestStartLine(),))
            for header, value in hdrs:
                self.log.write("%s: %s\n" % (header, value))
            self.log.write("\n")

        # Write the data
        self.writeRequestData(request)

        # Blank line in log between
        if self.loghttp and self.log:
            self.log.write("\n        <-------- BEGIN HTTP RESPONSE -------->\n")

        # Get response
        response = self.connect.getresponse()

        # Get response headers
        request.setResponseStatus(response.version, response.status, response.reason)
        request.setResponseHeaders(response.msg.headers)
        if self.loghttp and self.log:
            self.log.write("HTTP/%s %s %s\r\n" % (
                {11: "1.1", 10: "1.0", 9: "0.9"}.get(response.version, "?"),
                response.status,
                response.reason
            ))
            for hdr in response.msg.headers:
                self.log.write(hdr)
            self.log.write("\n")

        # Now get the data
        self.readResponseData(request, response)

        # Trailer in log
        if self.loghttp and self.log:
            self.log.write("\n        <-------- END HTTP RESPONSE -------->\n")


    def handleHTTPError(self, request):
        print "Ignoring error: %d" % (request.getStatusCode(),)


    def getAuthorizor(self, first_time, wwwhdrs):

        for witem in wwwhdrs:
            for item in witem.split(","):
                item = item.strip()
                if item.lower().startswith("basic"):
                    return Basic(self.user, self.pswd), False
                elif item.lower().startswith("digest"):
                    return Digest(self.user, self.pswd, wwwhdrs), False
                elif item.lower().startswith("negotiate") and Kerberos is not None:
                    return Kerberos(self.user), False
        else:
            return None, True


    def writeRequestData(self, request):

        # Write the data if any present
        if request.hasRequestData():

            stream = request.getRequestData()
            if stream:
                # Tell data we are using it
                stream.start()

                # Buffered write from stream
                more = True
                while more:
                    data, more = stream.read()
                    if data:
                        self.connect.send(data)

                        if self.loghttp and self.log:
                            self.log.write(data)

                # Tell data we are done using it
                stream.stop()


    def readResponseData(self, request, response):

        # Check for data and write it
        data = response.read()

        if request.hasResponseData():
            stream = request.getResponseData()
            stream.start()
            stream.write(data)
            stream.stop()
        else:
            response.read()

        if self.loghttp and self.log:
            self.log.write(data)


    def setServerType(self, type):
        self.type = type


    def setServerDescriptor(self, txt):
        self.descriptor = txt


    def setServerCapability(self, txt):
        self.capability = txt
Esempio n. 5
0
class CalDAVSession(Session):
    class logger(object):
        def write(self, data):
            print data.replace("\r\n", "\n"),

    def __init__(self,
                 server,
                 port=None,
                 ssl=False,
                 afunix=None,
                 user="",
                 pswd="",
                 principal=None,
                 root=None,
                 logging=False,
                 noHostRedirect=False):
        super(CalDAVSession, self).__init__(server,
                                            port,
                                            ssl,
                                            afunix,
                                            log=CalDAVSession.logger())

        self.loghttp = logging

        self.user = user
        self.pswd = pswd

        self.noHostRedirect = noHostRedirect

        # Initialize state
        self.connect = None

        # Paths
        self.rootPath = URL(url=root)
        self.principalPath = URL(url=principal) if principal else None

        self._initCalDAVState()

    def _initCalDAVState(self):

        # We need to cache the server capabilities and properties
        if not self.principalPath:
            self._discoverPrincipal()

    def _discoverPrincipal(self):

        current = self.getCurrentPrincipalResource(self.rootPath)
        if current:
            self.principalPath = current
            return
        current = self.getCurrentPrincipalResource(
            URL(url="/.well-known/caldav"))
        if current:
            self.principalPath = current
            return

        hrefs = self.getHrefListProperty(self.rootPath,
                                         davxml.principal_collection_set)
        if not hrefs:
            return
        hrefs = self.getHrefListProperty(URL(url="/.well-known/caldav"),
                                         davxml.principal_collection_set)
        if not hrefs:
            return

        # For each principal collection find current principal
        for href in hrefs:
            current = self.getCurrentPrincipalResource(href)
            if current:
                self.principalPath = current
                return

    def setUserPswd(self, user, pswd):

        self.user = user
        self.pswd = pswd
        self.authorization = None
        self._discoverPrincipal()

    def testResource(self, rurl):

        assert (isinstance(rurl, URL))

        request = PropFind(self, rurl.relativeURL(), headers.Depth0,
                           (davxml.resourcetype, ))

        # Process it
        self.runSession(request)

        return request.getStatusCode() == statuscodes.MultiStatus

    def getPropertyNames(self, rurl):

        assert (isinstance(rurl, URL))

        results = ()

        # Create WebDAV propfind
        request = PropNames(self, rurl.relativeURL(), headers.Depth0)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    results = tuple(
                        [name for name in item.getNodeProperties().iterkeys()])

        else:
            self.handleHTTPError(request)

        return results

    def getProperties(self, rurl, props, xmldata=False):

        assert (isinstance(rurl, URL))

        results = {}
        bad = None

        # Create WebDAV propfind
        if props:
            request = PropFind(self, rurl.relativeURL(), headers.Depth0, props)
        else:
            request = PropAll(self, rurl.relativeURL(), headers.Depth0)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):
                    for name, value in item.getTextProperties().iteritems():
                        results[name] = value
                    for name, value in item.getHrefProperties().iteritems():
                        if name not in results:
                            results[name] = value
                    for name, value in item.getNodeProperties().iteritems():
                        if name not in results:
                            results[name] = tostring(
                                value) if xmldata else value
                    bad = item.getBadProperties()
        else:
            self.handleHTTPError(request)

        return results, bad

    def getPropertiesOnHierarchy(self, rurl, props):

        assert (isinstance(rurl, URL))

        results = {}

        # Create WebDAV propfind
        request = PropFind(self, rurl.relativeURL(), headers.Depth1, props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                propresults = {}
                results[name.relativeURL()] = propresults

                for prop in props:

                    if str(prop) in item.getTextProperties():
                        propresults[prop] = item.getTextProperties().get(
                            str(prop))

                    elif str(prop) in item.getNodeProperties():
                        propresults[prop] = item.getNodeProperties()[str(prop)]
        else:
            self.handleHTTPError(request)

        return results

    def getHrefListProperty(self, rurl, propname):

        assert (isinstance(rurl, URL))

        results = ()

        # Create WebDAV propfind
        request = PropFind(self, rurl.relativeURL(), headers.Depth0,
                           (propname, ))
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result and extract any Hrefs
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match the URL the request was actually targeted at
                if name.equalRelative(URL(url=request.url)):

                    if str(propname) in item.getNodeProperties():

                        propnode = item.getNodeProperties()[str(propname)]
                        results += tuple([
                            URL(url=href.text, decode=True)
                            for href in propnode.findall(str(davxml.href))
                            if href.text
                        ])
        else:
            self.handleHTTPError(request)

        return results

    # Do principal-match report with self on the passed in url
    def getSelfProperties(self, rurl, props):

        assert (isinstance(rurl, URL))

        results = {}

        # Create WebDAV principal-match
        request = PrincipalMatch(self, rurl.relativeURL(), props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each principal-match result and return first one that is appropriate
            for item in parser.getResults().itervalues():

                for prop in props:

                    if str(prop) in item.getNodeProperties():

                        href = item.getNodeProperties()[str(prop)].find(
                            str(davxml.href))

                        if href is not None:
                            results[prop] = URL(url=href.text, decode=True)

                # We'll take the first one, whatever that is
                break

        else:
            self.handleHTTPError(request)
            return None

        return results

    # Do principal-match report with self on the passed in url
    def getSelfHrefs(self, rurl):

        assert (isinstance(rurl, URL))

        results = ()

        # Create WebDAV principal-match
        request = PrincipalMatch(self, rurl.relativeURL(),
                                 (davxml.principal_URL, ))
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result and extract any Hrefs
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                results += (name, )

        else:
            self.handleHTTPError(request)
            return None

        return results

    # Do principal-match report with self on the passed in url
    def getSelfPrincipalResource(self, rurl):

        assert (isinstance(rurl, URL))

        hrefs = self.getHrefListProperty(rurl, davxml.principal_collection_set)
        if not hrefs:
            return None

        # For each principal collection find one that matches self
        for href in hrefs:

            results = self.getSelfHrefs(href)
            if results:
                return results[0]

        return None

    # Do current-user-principal property on the passed in url
    def getCurrentPrincipalResource(self, rurl):

        assert (isinstance(rurl, URL))

        hrefs = self.getHrefListProperty(rurl, davxml.current_user_principal)
        return hrefs[0] if hrefs else None

    def setProperties(self, rurl, props):

        assert (isinstance(rurl, URL))

        results = ()

        # Convert property data into something sensible
        converted = []
        for name, value in props:
            node = None
            if isinstance(value, types.StringType):
                node = Element(name)
                node.text = value
            elif isinstance(value, URL):
                node = Element(davxml.href)
                node.text = value.absoluteURL()
            elif isinstance(value, types.ListType) or isinstance(
                    value, types.TupleType):
                hrefs = []
                for item in value:
                    if isinstance(item, URL):
                        href = Element(davxml.href)
                        href.text = item.relativeURL()
                        hrefs.append(href)
                    else:
                        break
                else:
                    node = Element(name)
                    map(node.append, hrefs)

            if node is not None:
                converted.append(node)

        # Create WebDAV propfind
        request = PropPatch(self, rurl.relativeURL(), converted)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    for prop in item.getNodeProperties():
                        results += (prop, )

        else:
            self.handleHTTPError(request)

        return results

    def setACL(self, rurl, aces):

        assert (isinstance(rurl, URL))

        # Create WebDAV ACL
        request = ACL(self, rurl.relativeURL(), aces)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created,
                                           statuscodes.NoContent):
            self.handleHTTPError(request)

    def makeCollection(self, rurl):

        assert (isinstance(rurl, URL))

        # Create WebDAV MKCOL
        request = MakeCollection(self, rurl.relativeURL())

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created,
                                           statuscodes.NoContent):
            self.handleHTTPError(request)

    def makeCalendar(self, rurl, displayname=None, description=None):

        assert (isinstance(rurl, URL))

        # Create WebDAV MKCALENDAR
        request = MakeCalendar(self, rurl.relativeURL(), displayname,
                               description)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created,
                                           statuscodes.NoContent):
            self.handleHTTPError(request)

    def makeAddressBook(self, rurl, displayname=None, description=None):

        assert (isinstance(rurl, URL))

        # Create WebDAV extended MKCOL
        request = MakeAddressBook(self, rurl.relativeURL(), displayname,
                                  description)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created,
                                           statuscodes.NoContent):
            self.handleHTTPError(request)

    def calendarMultiGet(self, rurl, hrefs, props):
        """
        Fetches the specified props for the specified hrefs using a single
        multiget call. The return value is a dictionary where the keys are the
        hrefs and the values are PropFindResult objects containing results for
        the requested props.
        """

        assert (isinstance(rurl, URL))

        request = CalMultiget(self,
                              rurl.relativeURL(),
                              hrefs=hrefs,
                              props=props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If it's a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())
            return parser.getResults()

        else:
            self.handleHTTPError(request)
            return None

    def addressbookMultiGet(self, rurl, hrefs, props):
        """
        Fetches the specified props for the specified hrefs using a single
        multiget call. The return value is a dictionary where the keys are the
        hrefs and the values are PropFindResult objects containing results for
        the requested props.
        """

        assert (isinstance(rurl, URL))

        request = AdbkMultiget(self,
                               rurl.relativeURL(),
                               hrefs=hrefs,
                               props=props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If it's a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())
            return parser.getResults()

        else:
            self.handleHTTPError(request)
            return None

    def syncCollection(self, rurl, synctoken, props=(), infinite=False):

        assert (isinstance(rurl, URL))

        newsynctoken = ""
        changed = set()
        removed = set()
        other = set()

        # Create WebDAV sync REPORT
        request = SyncCollection(
            self, rurl.relativeURL(),
            davxml.sync_level_infinite if infinite else davxml.sync_level_1,
            synctoken, props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                if int(item.status) == 404:
                    removed.add(name)
                elif int(item.status) / 100 != 2:
                    other.add(name)
                else:
                    changed.add(name)

            # Get the new token
            for node in parser.getOthers():
                if node.tag == davxml.sync_token:
                    newsynctoken = node.text
                    break

        else:
            self.handleHTTPError(request)

        return (
            newsynctoken,
            changed,
            removed,
            other,
        )

    def queryCollection(self, rurl, timerange, start, end, expand, props=()):

        assert (isinstance(rurl, URL))

        hrefs = set()

        # Create CalDAV query REPORT
        if timerange:
            request = QueryVEVENTTimeRange(self,
                                           rurl.relativeURL(),
                                           start,
                                           end,
                                           expand,
                                           props=props)
        else:
            raise NotImplementedError
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                hrefs.add(name)

        else:
            self.handleHTTPError(request)

        return hrefs

    def deleteResource(self, rurl):

        assert (isinstance(rurl, URL))

        # Create WebDAV DELETE
        request = Delete(self, rurl.relativeURL())

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK,
                                           statuscodes.NoContent):
            self.handleHTTPError(request)

    def moveResource(self, rurlFrom, rurlTo):

        assert (isinstance(rurlFrom, URL))
        assert (isinstance(rurlTo, URL))

        # Create WebDAV MOVE
        request = Move(self, rurlFrom.relativeURL(), rurlTo.absoluteURL())

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created,
                                           statuscodes.NoContent):
            self.handleHTTPError(request)

    def readData(self, rurl):

        assert (isinstance(rurl, URL))

        # Create WebDAV GET
        request = Get(self, rurl.relativeURL())
        dout = ResponseDataString()
        request.setData(dout)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() != statuscodes.OK:
            self.handleHTTPError(request)
            return None

        # Look for ETag
        if request.getNewETag() is not None:

            etag = request.getNewETag()

            # Handle server bug: ETag value MUST be quoted per HTTP/1.1 S3.11
            if not etag.startswith('"'):
                etag = "\"%s\"" % (etag, )
        else:
            etag = None

        # Return data as a string and etag
        return dout.getData(), etag

    def writeData(self, rurl, data, contentType, etag=None, method="PUT"):

        assert (isinstance(rurl, URL))

        # Create WebDAV PUT
        if method == "PUT":
            request = Put(self, rurl.relativeURL())
        elif method == "POST":
            request = Post(self, rurl.relativeURL())
        elif method == "OPTIONS":
            request = Options(self, rurl.relativeURL())

        dout = ResponseDataString()

        if data is not None:
            din = RequestDataString(data, contentType)
            if method == "PUT":
                request.setData(din, dout, etag=etag)
            elif method == "POST":
                request.setData(din, dout)
        else:
            request.setData(None, dout)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (
                statuscodes.OK,
                statuscodes.Created,
                statuscodes.NoContent,
        ):
            self.handleHTTPError(request)

        # Return data as a string
        return dout.getData()

    def importData(self, rurl, data, contentType):

        assert (isinstance(rurl, URL))

        # Create WebDAV POST
        request = Post(self, rurl.relativeURL())
        dout = RequestDataString(data, contentType)
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (
                statuscodes.OK,
                statuscodes.MultiStatus,
                statuscodes.NoContent,
        ):
            self.handleHTTPError(request)

    def getInvites(self, rurl):
        """
        Get the invitation details for the specified resource by reading and parsing the CS:invite WebDAV property.

        @param rurl: the resource whose property is to be read
        @type rurl: L{URL}
        """

        assert (isinstance(rurl, URL))

        results, bad = self.getProperties(rurl, (csxml.invite, ))
        if csxml.invite in bad:
            return Invites()
        else:
            return Invites().parseFromInvite(results.get(csxml.invite))

    def addInvitees(self, rurl, user_uids, read_write, summary=None):
        """
        Add a sharing invite for the specified resource.

        @param rurl: the resource to share
        @type rurl: L{URL}
        @param user_uids: short name or full principal path of user to share with
        @type user_uids: C{str}
        @param read_write: whether to share read-only C{False} or read-write C{True}
        @type read_write: C{bool}
        @param summary: summary description for the share
        @type summary: C{str}
        """

        assert (isinstance(rurl, URL))

        # Add invitation POST
        request = AddInvitees(self, rurl.relativeURL(), user_uids, read_write,
                              summary)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (
                statuscodes.OK,
                statuscodes.NoContent,
        ):
            self.handleHTTPError(request)

    def removeInvitee(self, rurl, invitee):
        """
        Remove an invite from a shared resource.

        @param rurl: the resource currently being shared
        @type rurl: L{URL}
        @param invitee: invite DAV:href for the user being removed
        @type invitee: C{str}
        """

        assert (isinstance(rurl, URL))

        # Remove invitation POST
        request = RemoveInvitee(self, rurl.relativeURL(), invitee)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (
                statuscodes.OK,
                statuscodes.NoContent,
        ):
            self.handleHTTPError(request)

    def getNotifications(self, rurl):
        """
        Get a list of L{Notification} objects for the specified notification collection.

        @param rurl: a user's notification collection URL
        @type rurl: L{URL}
        """

        assert (isinstance(rurl, URL))

        # List all children of the notification collection
        results = self.getPropertiesOnHierarchy(rurl,
                                                (davxml.getcontenttype, ))
        items = results.keys()
        items.sort()
        notifications = []
        for path in items:
            path = urllib.unquote(path)
            nurl = URL(url=path)
            if rurl == nurl:
                continue
            props = results[path]
            if props.get(davxml.getcontenttype,
                         "none").split(";")[0] in ("text/xml",
                                                   "application/xml"):
                data, _ignore_etag = self.readData(URL(url=path))
                node = XML(data)
                if node.tag == str(csxml.notification):
                    for child in node.getchildren():
                        if child.tag == str(csxml.invite_notification):
                            notifications.append(
                                InviteNotification().parseFromNotification(
                                    nurl, child))
                        elif child.tag == str(csxml.invite_reply):
                            notifications.append(
                                InviteReply().parseFromNotification(
                                    nurl, child))

        return notifications

    def processNotification(self, principal, notification, accept):
        """
        Accept or decline a sharing invite in the specified notification.

        @param principal: the principal acting on the notification
        @type principal: L{CalDAVPrincipal}
        @param notification: the notification
        @type notification: L{InviteNotification}
        @param accept: whether to accept C{True} or decline C{False} the invite
        @type accept: C{bool}
        """

        assert (isinstance(notification.url, URL))

        # POST goes to home and we need to figure that out from the notification
        rurl = principal.homeset[
            0] if notification.shared_type == "calendar" else principal.adbkhomeset[
                0]

        # Add invitation POST
        request = ProcessNotification(self, rurl.relativeURL(), notification,
                                      accept)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (
                statuscodes.OK,
                statuscodes.NoContent,
        ):
            self.handleHTTPError(request)
            return False
        else:
            return True

    def addAttachment(self, rurl, filename, data, contentType,
                      return_representation):

        assert (isinstance(rurl, URL))

        # Create WebDAV POST
        rurl.extended = "?action=attachment-add"
        request = Post(self, rurl.relativeURL())
        dout = RequestDataString(data, contentType)
        request.setRequestHeader("Content-Disposition",
                                 "attachment;filename=%s" % (filename, ))
        if return_representation:
            request.setRequestHeader("Prefer", "return-representation")
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (
                statuscodes.OK,
                statuscodes.Created,
                statuscodes.NoContent,
        ):
            self.handleHTTPError(request)

    def updateAttachment(self, rurl, managed_id, filename, data, contentType,
                         return_representation):

        assert (isinstance(rurl, URL))

        # Create WebDAV POST
        rurl.extended = "?action=attachment-update&managed-id=%s" % (
            managed_id, )
        request = Post(self, rurl.relativeURL())
        request.setRequestHeader("Content-Disposition",
                                 "attachment;filename=%s" % (filename, ))
        if return_representation:
            request.setRequestHeader("Prefer", "return-representation")
        dout = RequestDataString(data, contentType)
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (
                statuscodes.OK,
                statuscodes.Created,
                statuscodes.NoContent,
        ):
            self.handleHTTPError(request)

    def removeAttachment(self, rurl, managed_id):

        assert (isinstance(rurl, URL))

        # Create WebDAV POST
        rurl.extended = "?action=attachment-remove&managed-id=%s" % (
            managed_id, )
        request = Post(self, rurl.relativeURL())

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (
                statuscodes.OK,
                statuscodes.NoContent,
        ):
            self.handleHTTPError(request)

    def displayHTTPError(self, request):
        print request.status_code

    def openSession(self):
        # Create connection
        self.connect = SmartHTTPConnection(self.server, self.port, self.ssl,
                                           self.afunix)

        # Write to log file
        if self.loghttp and self.log:
            self.log.write(
                "\n        <-------- BEGIN HTTP CONNECTION -------->\n")
            self.log.write("Server: %s\n" % (self.server, ))

    def closeSession(self):
        if self.connect:
            self.connect.close()
            self.connect = None

            # Write to log file
            if self.loghttp and self.log:
                self.log.write(
                    "\n        <-------- END HTTP CONNECTION -------->\n")

    def runSession(self, request):

        ctr = 5
        while ctr:
            ctr -= 1

            self.doSession(request)

            if request and request.isRedirect():
                location = request.getResponseHeader(headers.Location)
                if location:
                    u = URL(location)
                    if not u.scheme or u.scheme in (
                            "http",
                            "https",
                    ):
                        # Get new server and base RURL
                        different_server = (
                            self.server != u.server) if u.server else False

                        # Use new host in this session
                        if different_server and not self.noHostRedirect:
                            self.setServer(u.server)

                        # Reset the request with new info
                        request.setURL(u.relativeURL())
                        request.clearResponse()

                        # Write to log file
                        if self.loghttp and self.log:
                            self.log.write(
                                "\n        <-------- HTTP REDIRECT -------->\n"
                            )
                            self.log.write("Location: %s\n" % (location, ))

                        # Recyle through loop
                        continue

            # Exit when redirect does not occur
            break

    def doSession(self, request):
        # Do initialisation if not already done
        if not self.initialised:

            if not self.initialise(self.server, self.rootPath.relativeURL()):

                # Break connection with server
                self.closeConnection()
                return

        # Do the request if present
        if request:

            # Handle delayed authorization
            first_time = True
            while True:

                # Run the request actions - this will make any connection that is needed
                self.sendRequest(request)

                # Check for auth failure if none before
                if request.getStatusCode() == statuscodes.Unauthorized:

                    # If we had authorization before, then chances are auth details are wrong - so delete and try again with new auth
                    if self.hasAuthorization():

                        self.authorization = None

                        # Display error so user knows why the prompt occurs again - but not the first time
                        # as we might have a digest re-auth.
                        if not first_time:
                            self.displayHTTPError(request)

                    # Get authorization object (prompt the user) and redo the request
                    self.authorization, cancelled = self.getAuthorizor(
                        first_time,
                        request.getResponseHeaders(headers.WWWAuthenticate))

                    # Check for auth cancellation
                    if cancelled:
                        self.authorization = None

                    else:
                        first_time = False

                        request.clearResponse()

                        # Repeat the request loop with new authorization
                        continue

                # If we get here we are complete with auth loop
                break

        # Now close it - eventually we will do keep-alive support

        # Break connection with server
        self.closeConnection()

    def doRequest(self, request):

        # Write request headers
        self.connect.putrequest(request.method,
                                request.url,
                                skip_host=True,
                                skip_accept_encoding=True)
        hdrs = request.getRequestHeaders()
        for header, value in hdrs:
            self.connect.putheader(header, value)
        self.connect.endheaders()

        # Write to log file
        if self.loghttp and self.log:
            self.log.write(
                "\n        <-------- BEGIN HTTP REQUEST -------->\n")
            self.log.write("%s\n" % (request.getRequestStartLine(), ))
            for header, value in hdrs:
                self.log.write("%s: %s\n" % (header, value))
            self.log.write("\n")

        # Write the data
        self.writeRequestData(request)

        # Blank line in log between
        if self.loghttp and self.log:
            self.log.write(
                "\n        <-------- BEGIN HTTP RESPONSE -------->\n")

        # Get response
        response = self.connect.getresponse()

        # Get response headers
        request.setResponseStatus(response.version, response.status,
                                  response.reason)
        request.setResponseHeaders(response.msg.headers)
        if self.loghttp and self.log:
            self.log.write("HTTP/%s %s %s\r\n" % ({
                11: "1.1",
                10: "1.0",
                9: "0.9"
            }.get(response.version, "?"), response.status, response.reason))
            for hdr in response.msg.headers:
                self.log.write(hdr)
            self.log.write("\n")

        # Now get the data
        self.readResponseData(request, response)

        # Trailer in log
        if self.loghttp and self.log:
            self.log.write("\n        <-------- END HTTP RESPONSE -------->\n")

    def handleHTTPError(self, request):
        print "Ignoring error: %d" % (request.getStatusCode(), )

    def getAuthorizor(self, first_time, wwwhdrs):

        for witem in wwwhdrs:
            for item in witem.split(","):
                item = item.strip()
                if item.lower().startswith("basic"):
                    return Basic(self.user, self.pswd), False
                elif item.lower().startswith("digest"):
                    return Digest(self.user, self.pswd, wwwhdrs), False
                elif item.lower().startswith(
                        "negotiate") and Kerberos is not None:
                    return Kerberos(self.user), False
        else:
            return None, True

    def writeRequestData(self, request):

        # Write the data if any present
        if request.hasRequestData():

            stream = request.getRequestData()
            if stream:
                # Tell data we are using it
                stream.start()

                # Buffered write from stream
                more = True
                while more:
                    data, more = stream.read()
                    if data:
                        self.connect.send(data)

                        if self.loghttp and self.log:
                            self.log.write(data)

                # Tell data we are done using it
                stream.stop()

    def readResponseData(self, request, response):

        # Check for data and write it
        data = response.read()

        if request.hasResponseData():
            stream = request.getResponseData()
            stream.start()
            stream.write(data)
            stream.stop()
        else:
            response.read()

        if self.loghttp and self.log:
            self.log.write(data)

    def setServerType(self, type):
        self.type = type

    def setServerDescriptor(self, txt):
        self.descriptor = txt

    def setServerCapability(self, txt):
        self.capability = txt
Esempio n. 6
0
def httploop(ctr, config, complete):

    # Random time delay
    time.sleep(random.randint(0, config["interval"]) / 1000.0)

    ServerDetail = collections.namedtuple("ServerDetails", (
        "host",
        "port",
        "use_ssl",
        "headers",
    ))
    server_details = []
    for server in config["server"].split(","):
        url = urlparse(server)
        use_ssl = url[0] == "https"
        if "@" in url[1]:
            auth, net_loc = url[1].split("@")
        else:
            auth = "admin:admin"
            net_loc = url[1]
        host, port = net_loc.split(":")
        port = int(port)
        user, pswd = auth.split(":")

        headers = {}
        headers["User-Agent"] = "httploop/1"
        headers["Depth"] = "1"
        headers["Authorization"] = "Basic " + "{}:{}".format(
            user, pswd).encode("base64")[:-1]
        headers["Content-Type"] = "application/json"

        server_details.append(ServerDetail(host, port, use_ssl, headers))

    random.shuffle(server_details)

    interval = config["interval"] / 1000.0
    total = config["limit"] / config["numProcesses"]

    count = 0

    jstr = json.dumps({
        "action": "testwork",
        "when": config["when"],
        "delay": config["delay"],
        "jobs": config["jobs"],
        "priority": PRIORITY[config["priority"]],
        "weight": config["weight"],
    })

    base_time = time.time()
    iter = itertools.cycle(server_details)
    while not complete.value:

        server = iter.next()
        count += 1

        http = SmartHTTPConnection(server.host, server.port, server.use_ssl,
                                   False)

        try:
            server.headers["User-Agent"] = "httploop-{}/{}".format(
                ctr,
                count,
            )
            http.request("POST", "/control", jstr, server.headers)

            response = http.getresponse()
            response.read()

        except Exception as e:
            print("Count: {}".format(count, ))
            print(repr(e))
            raise

        finally:
            http.close()

        if total != 0 and count >= total:
            break

        base_time += interval
        sleep_time = base_time - time.time()
        if sleep_time < 0:
            print("Interval less than zero: process #{}".format(ctr))
            base_time = time.time()
        else:
            time.sleep(sleep_time)
Esempio n. 7
0
def run(session, request):

    # Create connection
    connect = SmartHTTPConnection(session.server, session.port, session.ssl)
    connect.set_debuglevel(1)

    # Do headers
    connect.putrequest(request.method, request.url, skip_host=True, skip_accept_encoding=True)
    hdrs = request.getRequestHeaders()
    for header, value in hdrs.iteritems():
        connect.putheader(header, value)
    connect.endheaders()

    # Do request body
    stream = request.getRequestDataStream()
    if stream:
        stream.start()
        more = True
        while more:
            data, more = stream.read()
            if data:
                connect.send(data)
        stream.stop()

    # Get response
    response = connect.getresponse()

    # Get response headers
    request.setResponseStatus(response.version, response.status, response.reason)
    request.setResponseHeaders(response.getheaders())
def run(session, request):

    # Create connection
    connect = SmartHTTPConnection(session.server, session.port, session.ssl, session.afunix)
    connect.set_debuglevel(1)

    # Do headers
    connect.putrequest(request.method, request.url, skip_host=True, skip_accept_encoding=True)
    hdrs = request.getRequestHeaders()
    for header, value in hdrs.iteritems():
        connect.putheader(header, value)
    connect.endheaders()

    # Do request body
    stream = request.getRequestDataStream()
    if stream:
        stream.start()
        more = True
        while more:
            data, more = stream.read()
            if data:
                connect.send(data)
        stream.stop()

    # Get response
    response = connect.getresponse()

    # Get response headers
    request.setResponseStatus(response.version, response.status, response.reason)
    request.setResponseHeaders(response.getheaders())