class VCRHTTPResponse(object): """ Stub reponse class that gets returned instead of a HTTPResponse """ def __init__(self, recorded_response): self.recorded_response = recorded_response self.reason = recorded_response['status']['message'] self.status = recorded_response['status']['code'] self.version = None self._content = StringIO(self.recorded_response['body']['string']) self.msg = HTTPMessage(StringIO('')) for k, v in self.recorded_response['headers'].iteritems(): self.msg.addheader(k, v) self.length = self.msg.getheader('content-length') or None def read(self, chunked=False): # Note: I'm pretty much ignoring any chunking stuff because # I don't really understand what it is or how it works. return self._content.read() def isclosed(self): # Urllib3 seems to call this because it actually uses # the weird chunking support in httplib return True def getheaders(self): return self.recorded_response['headers'].iteritems()
def datagramReceived(self, data, addr, outip): if outip not in self.interfaces: if self.INADDR_ANY not in self.interfaces: return req_line, data = data.split('\r\n', 1) method, path, version = req_line.split(None, 3) # check method if method != 'M-SEARCH' or path != '*': return # parse header headers = HTTPMessage(StringIO(data)) mx = int(headers.getheader('MX')) # send M-SEARCH response for udn in self.devices: device = self.devices[udn] delay = random() * mx for packet in device.make_msearch_response(headers, (outip, self.port), addr): buff = build_packet('HTTP/1.1 200 OK', packet) self.reactor.callLater(delay, self._send_packet, self.ssdp, buff, addr) delay += self.SSDP_INTERVAL
class VCRHTTPResponse(object): """ Stub reponse class that gets returned instead of a HTTPResponse """ def __init__(self, recorded_response): self.recorded_response = recorded_response self.reason = recorded_response['status']['message'] self.status = recorded_response['status']['code'] self.version = None self._content = StringIO(self.recorded_response['body']['string']) # We are skipping the header parsing (they have already been parsed # at this point) and directly adding the headers to the header # container, so just pass an empty StringIO. self.msg = HTTPMessage(StringIO('')) for key, val in self.recorded_response['headers'].iteritems(): self.msg.addheader(key, val) # msg.addheaders adds the headers to msg.dict, but not to # the msg.headers list representation of headers, so # I have to add it to both. self.msg.headers.append("{0}:{1}".format(key, val)) self.length = self.msg.getheader('content-length') or None def read(self, *args, **kwargs): # Note: I'm pretty much ignoring any chunking stuff because # I don't really understand what it is or how it works. return self._content.read(*args, **kwargs) def close(self): return True def isclosed(self): # Urllib3 seems to call this because it actually uses # the weird chunking support in httplib return True def getheaders(self): return self.recorded_response['headers'].iteritems()
class ReplayHTTPResponse(object): """ A replay response object, with just enough functionality to make the various HTTP/URL libraries out there happy. """ __text_content_types = ( 'text/', 'application/json', ) def __init__(self, replay_response, method=None): self.reason = replay_response['status']['message'] self.status = replay_response['status']['code'] self.version = None if 'body_text' in replay_response: # JSON decoder returns unicode, not str, so this needs to be # encoded to properly reproduce content off the wire. self._content = replay_response['body_text'].encode('utf8') elif 'body_quoted_printable' in replay_response: # quopri.decodestring returns str, which is correct for content off # the wire. self._content = quopri.decodestring(replay_response['body_quoted_printable']) else: # .decode('base64') returns str, which is correct for content off # the wire. self._content = replay_response['body'].decode('base64') self.fp = StringIO(self._content) msg_fp = StringIO('\r\n'.join('{}: {}'.format(h, v) for h, v in replay_response['headers'].iteritems())) self.msg = HTTPMessage(msg_fp) self.msg.fp = None # httplib does this, okay? length = self.msg.getheader('content-length') self.length = int(length) if length else None # Save method to handle HEAD specially as httplib does self._method = method @classmethod def make_replay_response(cls, response): """ Converts real response to replay_response dict which can be saved and/or used to initialize a ReplayHTTPResponse. """ replay_response = {} body = response.read() # undecoded byte string # Add body to replay_response. Try to use simple text, falling back to # quoted printable or base64 as required for binary responses. if response.getheader('content-type', '') \ .startswith(cls.__text_content_types): if response.getheader('content-encoding') in ['gzip', 'deflate']: # http://stackoverflow.com/questions/2695152 body = zlib.decompress(body, 16 + zlib.MAX_WBITS) del response.msg['content-encoding'] # decompression changes the length if 'content-length' in response.msg: response.msg['content-length'] = str(len(body)) try: # Store body directly as text if it will decode properly. body.decode('utf8') replay_response['body_text'] = body except UnicodeDecodeError: # Store body as quoted printable. # Remove unneccessary =\n pairs which make searching hard. # These exist for line-wrapping in email, which is entirely # pointless here. body_quoted_printable = quopri.encodestring(body) body_quoted_printable = body_quoted_printable.replace('=\n', '') replay_response['body_quoted_printable'] = body_quoted_printable else: replay_response['body'] = body.encode('base64') replay_response.update(dict( status=dict(code=response.status, message=response.reason), headers=dict(response.getheaders()))) return replay_response def close(self): self.fp = None def isclosed(self): return self.fp is None def read(self, amt=None): """ The important parts of HTTPResponse.read() """ if self.fp is None: return '' if self._method == 'HEAD': self.close() return '' if self.length is not None: amt = min(amt, self.length) # StringIO doesn't like read(None) s = self.fp.read() if amt is None else self.fp.read(amt) if not s: self.close() if self.length is not None: self.length -= len(s) if not self.length: self.close() return s def getheader(self, name, default=None): return self.msg.getheader(name, default) def getheaders(self): return self.msg.items()
class ReplayHTTPResponse(object): """ A replay response object, with just enough functionality to make the various HTTP/URL libraries out there happy. """ __text_content_types = ( 'text/', 'application/json', ) def __init__(self, replay_response, method=None): self.reason = replay_response['status']['message'] self.status = replay_response['status']['code'] self.version = None if 'body_quoted_printable' in replay_response: self._content = quopri.decodestring(replay_response['body_quoted_printable']) else: self._content = replay_response['body'].decode('base64') self.fp = StringIO(self._content) msg_fp = StringIO('\r\n'.join('{}: {}'.format(h, v) for h, v in replay_response['headers'].iteritems())) self.msg = HTTPMessage(msg_fp) self.msg.fp = None # httplib does this, okay? length = self.msg.getheader('content-length') self.length = int(length) if length else None # Save method to handle HEAD specially as httplib does self._method = method @classmethod def make_replay_response(cls, response): """ Converts real response to replay_response dict which can be saved and/or used to initialize a ReplayHTTPResponse. """ replay_response = {} body = response.read() # undecoded byte string # Add body to replay_response, either as quoted printable for # text responses or base64 for binary responses. if response.getheader('content-type', '') \ .startswith(cls.__text_content_types): if response.getheader('content-encoding') in ['gzip', 'deflate']: # http://stackoverflow.com/questions/2695152 body = zlib.decompress(body, 16 + zlib.MAX_WBITS) del response.msg['content-encoding'] # decompression changes the length if 'content-length' in response.msg: response.msg['content-length'] = str(len(body)) replay_response['body_quoted_printable'] = quopri.encodestring(body) else: replay_response['body'] = body.encode('base64') replay_response.update(dict( status=dict(code=response.status, message=response.reason), headers=dict(response.getheaders()))) return replay_response def close(self): self.fp = None def isclosed(self): return self.fp is None def read(self, amt=None): """ The important parts of HTTPResponse.read() """ if self.fp is None: return '' if self._method == 'HEAD': self.close() return '' if self.length is not None: amt = min(amt, self.length) # StringIO doesn't like read(None) s = self.fp.read() if amt is None else self.fp.read(amt) if not s: self.close() if self.length is not None: self.length -= len(s) if not self.length: self.close() return s def getheader(self, name, default=None): return self.msg.getheader(name, default) def getheaders(self): return self.msg.items()
class ReplayHTTPResponse(object): """ A replay response object, with just enough functionality to make the various HTTP/URL libraries out there happy. """ __text_content_types = ( 'text/', 'application/json', ) def __init__(self, replay_response, method=None): self.reason = replay_response['status']['message'] self.status = replay_response['status']['code'] self.version = None if 'body_quoted_printable' in replay_response: self._content = quopri.decodestring( replay_response['body_quoted_printable']) else: self._content = replay_response['body'].decode('base64') self.fp = StringIO(self._content) msg_fp = StringIO('\r\n'.join( '{}: {}'.format(h, v) for h, v in replay_response['headers'].iteritems())) self.msg = HTTPMessage(msg_fp) self.msg.fp = None # httplib does this, okay? length = self.msg.getheader('content-length') self.length = int(length) if length else None # Save method to handle HEAD specially as httplib does self._method = method @classmethod def make_replay_response(cls, response): """ Converts real response to replay_response dict which can be saved and/or used to initialize a ReplayHTTPResponse. """ replay_response = {} body = response.read() # undecoded byte string # Add body to replay_response, either as quoted printable for # text responses or base64 for binary responses. if response.getheader('content-type', '') \ .startswith(cls.__text_content_types): if response.getheader('content-encoding') in ['gzip', 'deflate']: # http://stackoverflow.com/questions/2695152 body = zlib.decompress(body, 16 + zlib.MAX_WBITS) del response.msg['content-encoding'] # decompression changes the length if 'content-length' in response.msg: response.msg['content-length'] = str(len(body)) replay_response['body_quoted_printable'] = quopri.encodestring( body) else: replay_response['body'] = body.encode('base64') replay_response.update( dict(status=dict(code=response.status, message=response.reason), headers=dict(response.getheaders()))) return replay_response def close(self): self.fp = None def isclosed(self): return self.fp is None def read(self, amt=None): """ The important parts of HTTPResponse.read() """ if self.fp is None: return '' if self._method == 'HEAD': self.close() return '' if self.length is not None: amt = min(amt, self.length) # StringIO doesn't like read(None) s = self.fp.read() if amt is None else self.fp.read(amt) if not s: self.close() if self.length is not None: self.length -= len(s) if not self.length: self.close() return s def getheader(self, name, default=None): return self.msg.getheader(name, default) def getheaders(self): return self.msg.items()