def __init__(self, method, uri, headers, stream): """ @param method: The HTTP method to for this request, ex: 'GET', 'HEAD', 'POST', etc. @type method: C{str} @param uri: The URI of the resource to request, this may be absolute or relative, however the interpretation of this URI is left up to the remote server. @type uri: C{str} @param headers: Headers to be sent to the server. It is important to note that this object does not create any implicit headers. So it is up to the HTTP Client to add required headers such as 'Host'. @type headers: C{dict}, L{twisted.web2.http_headers.Headers}, or C{None} @param stream: Content body to send to the remote HTTP server. @type stream: L{twisted.web2.stream.IByteStream} """ self.method = method self.uri = uri if isinstance(headers, Headers): self.headers = headers else: self.headers = Headers(headers or {}) if stream is not None: self.stream = IByteStream(stream) else: self.stream = None
def __init__(self, channel, request, closeAfter): HTTPParser.__init__(self, channel) self.request = request self.closeAfter = closeAfter self.transport = self.channel.transport self.outHeaders = Headers({})
class HTTPClientChannelRequest(HTTPParser): parseCloseAsEnd = True outgoing_version = "HTTP/1.1" chunkedOut = False finished = False autoRedirect = True closeAfter = False userAgent = 'TwistedClient' code = 0 def __init__(self, channel, request, closeAfter): HTTPParser.__init__(self, channel) self.request = request self.closeAfter = closeAfter self.transport = self.channel.transport self.outHeaders = Headers({}) def submit(self): request = self.request if request.method == "HEAD": # No incoming data will arrive. self.length = 0 path = request.uri.getRequestLocation() l = '%s %s %s\r\n' % (request.method, path, self.outgoing_version) self.transport.write(l) self.sendHeader('Host', request.uri.netloc) self.sendHeader('User-Agent', self.userAgent) if request.headers is not None: for name, valuelist in request.headers.getAllRawHeaders(): for value in valuelist: self.sendHeader(name, value) if hasattr(request, 'contentLength'): if request.protocol.contentLength() is not None: self.sendHeader('Content-Length', request.protocol.contentLength()) # l.append("%s: %s\r\n" % ('Content-Length', request.protocol.contentLength())) else: # Got a stream with no length. Send as chunked and hope, against # the odds, that the server actually supports chunked uploads. self.sendHeader('Transfer-Encoding', 'chunked') # l.append("%s: %s\r\n" % ('Transfer-Encoding', 'chunked')) self.chunkedOut = True if self.closeAfter: self.sendHeader('Connection', 'close') # l.append("%s: %s\r\n" % ('Connection', 'close')) else: self.sendHeader('Connection', 'Keep-Alive') # l.append("%s: %s\r\n" % ('Connection', 'Keep-Alive')) self.sendHeader('Accept','text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8') self.sendHeader('Accept-charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7') self.sendHeader('Cache-Control', 'max-age=0') self.transport.write("\r\n") request.protocol.makeConnection(self) def sendHeader(self, name, value): self.outHeaders.addRawHeader(name, value) self.transport.write('%s: %s\r\n' % (name, value)) def registerProducer(self, producer, streaming): """ Register a producer. """ self.transport.registerProducer(producer, streaming) def unregisterProducer(self): self.transport.unregisterProducer() def write(self, data): if not data: return elif self.chunkedOut: self.transport.writeSequence(("%X\r\n" % len(data), data, "\r\n")) else: self.transport.write(data) def loseConnection(self): """ We are finished writing data. """ if self.chunkedOut: # write last chunk and closing CRLF self.transport.write("0\r\n\r\n") self.finished = True self.channel.requestWriteFinished(self) del self.transport def _error(self, err): """ Abort parsing, and depending of the status of the request, either fire the C{responseDefer} if no response has been sent yet, or close the stream. """ self.abortParse() if hasattr(self, 'request') and self.request.protocol is not None: self.request.protocol.connectionLost(Failure(CONNECTION_LOST)) else: self.responseDefer.errback(err) def _abortWithError(self, errcode, text): """ Abort parsing by forwarding a C{ProtocolError} to C{_error}. """ self._error(ProtocolError(text)) def connectionLost(self, reason): self._error(reason) def gotInitialLine(self, initialLine): parts = initialLine.split(' ', 2) # Parse the initial request line if len(parts) != 3: self._abortWithError(BAD_REQUEST, "Bad response line: %s" % (initialLine,)) return strversion, self.code, message = parts try: protovers = parseVersion(strversion) if protovers[0] != 'http': raise ValueError() except ValueError: self._abortWithError(BAD_REQUEST, "Unknown protocol: %s" % (strversion,)) return self.version = protovers[1:3] # Ensure HTTP 0 or HTTP 1. if self.version[0] != 1: self._abortWithError(HTTP_VERSION_NOT_SUPPORTED, 'Only HTTP 1.x is supported.') return ## FIXME: Actually creates Response, function is badly named! def createRequest(self): pass def createResponse(self, data): r = Response(code=self.code, headers=self.getHeaders(), data=data) r.request = self.request return r ## FIXME: Actually processes Response, function is badly named! def processRequest(self): pass def handleContentChunk(self, data): self.request.protocol.dataReceived(data) def handleContentComplete(self): self.request.protocol.connectionLost(Failure(CONNECTION_DONE)) def getHeaders(self): return self.inHeaders