示例#1
0
class Request(object):
    def __init__(self, method="GET", target="/", version=(1,1), headers=(), body=None):
        self.method = method
        self.target = target
        self.version = version
        self.headers = Headers(headers)
        self.body = body
        self.__parserState = 'COMMAND'
    
    def toLines(self, lines=None):
        if lines is None:
            lines = []
        target = self.target
        target = re.sub(r"\s", "+", target)
        if isinstance(target, unicode):
            target = target.encode('utf-8')
        lines.append("%s %s HTTP/%d.%d\r\n" % (self.method, target, self.version[0], self.version[1]))
        self.headers.toLines(lines)
        lines.append("\r\n")
        return lines
    
    def toString(self):
        return ''.join(self.toLines())
    
    def __str__(self):
        return self.toString()
    
    def __parseCommand(self, line):
        parts = line.split(None, 2)
        if len(parts) != 3:
            raise HTTPDataError("request must be in 'METHOD target HTTP/n.n' format: %r" % (line,))
        method, target, version = parts
        if not version.startswith('HTTP/'):
            raise HTTPDataError("protocol must be HTTP: %r" % (line,))
        version = version[5:].split('.')
        if len(version) != 2:
            raise HTTPDataError("invalid version: %r" % (line,))
        try:
            version = (int(version[0]), int(version[1]))
        except ValueError:
            raise HTTPDataError("invalid version: %r" % (line,))
        self.method = method
        self.target = target
        self.version = version
    
    def parseLine(self, line):
        if self.__parserState == 'COMMAND':
            if not line:
                # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
                # Just ignore all empty lines for maximum compatibility
                return True
            self.__parseCommand(line)
            self.__parserState = 'HEADERS'
            return True
        elif self.__parserState == 'HEADERS':
            if not self.headers.parseLine(line):
                self.__parserState = 'DONE'
                return False
            return True
        return False
示例#2
0
class Response(object):
    def __init__(self, version=(1,1), code=200, phrase='OK', headers=(), body=None):
        self.version = version
        self.code = code
        self.phrase = phrase
        self.headers = Headers(headers)
        self.body = body
        self.__parserState = 'STATUS'
    
    def toLines(self, lines=None):
        if lines is None:
            lines = []
        lines.append("HTTP/%d.%d %d %s\r\n" % (self.version[0], self.version[1], self.code, self.phrase))
        self.headers.toLines(lines)
        lines.append("\r\n")
        return lines
    
    def toString(self):
        return ''.join(self.toLines())
    
    def __str__(self):
        return self.toString()
    
    def __parseStatus(self, line):
        parts = line.split(None, 2)
        if len(parts) not in (2, 3):
            raise HTTPDataError("response must be in 'HTTP/n.n status message' format: %r" % (line,))
        version = parts[0]
        code = parts[1]
        phrase = len(parts) >= 3 and parts[2] or ""
        if not version.startswith('HTTP/'):
            raise HTTPDataError("protocol must be HTTP: %r" % (line,))
        version = version[5:].split('.')
        if len(version) != 2:
            raise HTTPDataError("invalid version: %r" % (line,))
        try:
            version = (int(version[0]), int(version[1]))
        except ValueError:
            raise HTTPDataError("invalid version: %r" % (line,))
        try:
            code = int(code)
        except ValueError:
            raise HTTPDataError("status code must be a number: %r" % (line,))
        self.version = version
        self.code = code
        self.phrase = phrase
    
    def parseLine(self, line):
        if self.__parserState == 'STATUS':
            if not line:
                # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
                # Just ignore all empty lines for maximum compatibility
                return True
            self.__parseStatus(line)
            self.__parserState = 'HEADERS'
            return True
        elif self.__parserState == 'HEADERS':
            if not self.headers.parseLine(line):
                self.__parserState = 'DONE'
                return False
            return True
        return False