def _do_read(self, length=None, use_readline=False): if use_readline: reader = self.rfile.readline else: reader = self.rfile.read content_length = self.content_length if content_length is None: # Either Content-Length or "Transfer-Encoding: chunked" must be present in a request with a body # if it was chunked, then this function would have not been called return '' self._send_100_continue() left = content_length - self.position if length is None: length = left elif length > left: length = left if not length: return b('') read = reader(length) self.position += len(read) if len(read) < length: if (use_readline and not read.endswith(b("\n"))) or not use_readline: raise IOError( "unexpected end of file while reading request at position %s" % (self.position, )) return read
def _do_read(self, length=None, use_readline=False): if use_readline: reader = self.rfile.readline else: reader = self.rfile.read content_length = self.content_length if content_length is None: # Either Content-Length or "Transfer-Encoding: chunked" must be present in a request with a body # if it was chunked, then this function would have not been called return '' self._send_100_continue() left = content_length - self.position if length is None: length = left elif length > left: length = left if not length: return b('') read = reader(length) self.position += len(read) if len(read) < length: if (use_readline and not read.endswith(b("\n"))) or not use_readline: raise IOError("unexpected end of file while reading request at position %s" % (self.position,)) return read
def _write(self, data): if not data: return if self.response_use_chunked: ## Write the chunked encoding data = b('\r\n').join((b('%x' % len(data)), data, b(''))) self._sendall(data)
def _chunked_read(self, length=None, use_readline=False): rfile = self.rfile self._send_100_continue() if length == 0: return b("") if length is not None and length < 0: length = None if use_readline: reader = self.rfile.readline else: reader = self.rfile.read response = [] while self.chunk_length != 0: maxreadlen = self.chunk_length - self.position if length is not None and length < maxreadlen: maxreadlen = length if maxreadlen > 0: data = reader(maxreadlen) if not data: self.chunk_length = 0 raise IOError( "unexpected end of file while parsing chunked data") datalen = len(data) response.append(data) self.position += datalen if self.chunk_length == self.position: rfile.readline() if length is not None: length -= datalen if length == 0: break if use_readline and data[-1:] == b("\n"): break else: line = rfile.readline() if not line.endswith(b("\n")): self.chunk_length = 0 raise IOError( "unexpected end of file while reading chunked data header" ) self.chunk_length = int(line.split(b(";"), 1)[0], 16) self.position = 0 if self.chunk_length == 0: rfile.readline() return b('').join(response)
def _chunked_read(self, length=None, use_readline=False): rfile = self.rfile self._send_100_continue() if length == 0: return b("") if length is not None and length < 0: length = None if use_readline: reader = self.rfile.readline else: reader = self.rfile.read response = [] while self.chunk_length != 0: maxreadlen = self.chunk_length - self.position if length is not None and length < maxreadlen: maxreadlen = length if maxreadlen > 0: data = reader(maxreadlen) if not data: self.chunk_length = 0 raise IOError("unexpected end of file while parsing chunked data") datalen = len(data) response.append(data) self.position += datalen if self.chunk_length == self.position: rfile.readline() if length is not None: length -= datalen if length == 0: break if use_readline and data[-1:] == b("\n"): break else: line = rfile.readline() if not line.endswith(b("\n")): self.chunk_length = 0 raise IOError("unexpected end of file while reading chunked data header") self.chunk_length = int(line.split(b(";"), 1)[0], 16) self.position = 0 if self.chunk_length == 0: rfile.readline() return b('').join(response)
def read(self, len=1024): """Read up to LEN bytes and return them. Return zero-length string on EOF.""" while True: try: return self._sslobj.read(len) except SSLError: ex = sys.exc_info()[1] if ex.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs: return b('') elif ex.args[0] == SSL_ERROR_WANT_READ: if self.timeout == 0.0: raise if PY3: ex = None del ex else: sys.exc_clear() self._wait(self._read_event, timeout_exc=_SSLErrorReadTimeout) elif ex.args[0] == SSL_ERROR_WANT_WRITE: if self.timeout == 0.0: raise if PY3: ex = None del ex else: sys.exc_clear() # note: using _SSLErrorReadTimeout rather than _SSLErrorWriteTimeout below is intentional self._wait(self._write_event, timeout_exc=_SSLErrorReadTimeout) else: raise
def _write_with_headers(self, data): towrite = bytearray() self.headers_sent = True self.finalize_headers() towrite.extend(b('%s %s\r\n' % (self.request_version, self.status))) for header in self.response_headers: towrite.extend(b('%s: %s\r\n' % header)) towrite.extend(b('\r\n')) if data: if self.response_use_chunked: ## Write the chunked encoding towrite.extend(b("%x\r\n" % (len(data),))) towrite.extend(data) towrite.extend(b("\r\n")) else: towrite.extend(data) self._sendall(towrite)
def _write_with_headers(self, data): towrite = bytearray() self.headers_sent = True self.finalize_headers() towrite.extend(b('%s %s\r\n' % (self.request_version, self.status))) for header in self.response_headers: towrite.extend(b('%s: %s\r\n' % header)) towrite.extend(b('\r\n')) if data: if self.response_use_chunked: ## Write the chunked encoding towrite.extend(b("%x\r\n" % (len(data), ))) towrite.extend(data) towrite.extend(b("\r\n")) else: towrite.extend(data) self._sendall(towrite)
def recv(self, size): while True: try: data = _read(self.fileno(), size) except (IOError, OSError): code = sys.exc_info()[1].args[0] if code not in ignored_errors: raise if not PY3: sys.exc_clear() else: if not self._translate or not data: return data if self._eat_newline: self._eat_newline = False if data.startswith(b('\n')): data = data[1:] if not data: return self.recv(size) if data.endswith(b('\r')): self._eat_newline = True return self._translate_newlines(data) self.hub.wait(self._read_event)
def recv(self, size): while True: try: data = _read(self.fileno(), size) except (IOError, OSError): code = sys.exc_info()[1].args[0] if code not in ignored_errors: raise if not PY3: sys.exc_clear() else: if not self._translate or not data: return data if self._eat_newline: self._eat_newline = False if data.startswith(b("\n")): data = data[1:] if not data: return self.recv(size) if data.endswith(b("\r")): self._eat_newline = True return self._translate_newlines(data) self.hub.wait(self._read_event)
import gevent from gevent.server import StreamServer from gevent.hub import GreenletExit, reraise, PY3, b, string_types __all__ = ['WSGIHandler', 'WSGIServer'] MAX_REQUEST_LINE = 8192 # Weekday and month names for HTTP date/time formatting; always English! _WEEKDAYNAME = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] _MONTHNAME = [None, # Dummy so we can use 1-based month numbers "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] _INTERNAL_ERROR_STATUS = '500 Internal Server Error' _INTERNAL_ERROR_BODY = b('Internal Server Error') _INTERNAL_ERROR_HEADERS = [('Content-Type', 'text/plain'), ('Connection', 'close'), ('Content-Length', str(len(_INTERNAL_ERROR_BODY)))] _REQUEST_TOO_LONG_RESPONSE = b("HTTP/1.0 414 Request URI Too Long\r\nConnection: close\r\nContent-length: 0\r\n\r\n") _BAD_REQUEST_RESPONSE = b("HTTP/1.0 400 Bad Request\r\nConnection: close\r\nContent-length: 0\r\n\r\n") _CONTINUE_RESPONSE = b("HTTP/1.1 100 Continue\r\n\r\n") def format_date_time(timestamp): year, month, day, hh, mm, ss, wd, _y, _z = time.gmtime(timestamp) return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (_WEEKDAYNAME[wd], day, _MONTHNAME[month], year, hh, mm, ss) class Input(object):
def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite): """Execute program (POSIX version)""" if isinstance(args, string_types): args = [args] else: args = list(args) if shell: args = ["/bin/sh", "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork() except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child try: # Close parent's pipe ends if p2cwrite is not None: os.close(p2cwrite) if c2pread is not None: os.close(c2pread) if errread is not None: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) if errwrite == 0 or errwrite == 1: errwrite = os.dup(errwrite) # Dup fds for child def _dup2(a, b): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if a == b: self._set_cloexec_flag(a, False) elif a is not None: os.dup2(a, b) self._remove_nonblock_flag(b) _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. closed = set([None]) for fd in [p2cread, c2pwrite, errwrite]: if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Close all other fds, if asked for if close_fds: self._close_fds(but=errpipe_write) if cwd is not None: os.chdir(cwd) if preexec_fn: preexec_fn() if env is None: os.execvp(executable, args) else: os.execvpe(executable, args, env) except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception( exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._watcher = self._loop.child(self.pid) self._watcher.start(self._on_child, self._watcher) if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) if p2cread is not None and p2cwrite is not None: os.close(p2cread) if c2pwrite is not None and c2pread is not None: os.close(c2pwrite) if errwrite is not None and errread is not None: os.close(errwrite) # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) if data != b(""): self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None: os.close(fd) raise child_exception
def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite): """Execute program (POSIX version)""" if isinstance(args, string_types): args = [args] else: args = list(args) if shell: args = ["/bin/sh", "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork() except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child try: # Close parent's pipe ends if p2cwrite is not None: os.close(p2cwrite) if c2pread is not None: os.close(c2pread) if errread is not None: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) if errwrite == 0 or errwrite == 1: errwrite = os.dup(errwrite) # Dup fds for child def _dup2(a, b): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if a == b: self._set_cloexec_flag(a, False) elif a is not None: os.dup2(a, b) self._remove_nonblock_flag(b) _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. closed = set([None]) for fd in [p2cread, c2pwrite, errwrite]: if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Close all other fds, if asked for if close_fds: self._close_fds(but=errpipe_write) if cwd is not None: os.chdir(cwd) if preexec_fn: preexec_fn() if env is None: os.execvp(executable, args) else: os.execvpe(executable, args, env) except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._watcher = self._loop.child(self.pid) self._watcher.start(self._on_child, self._watcher) if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) if p2cread is not None and p2cwrite is not None: os.close(p2cread) if c2pwrite is not None and c2pread is not None: os.close(c2pwrite) if errwrite is not None and errread is not None: os.close(errwrite) # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) if data != b(""): self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None: os.close(fd) raise child_exception
None, # Dummy so we can use 1-based month numbers "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ] _INTERNAL_ERROR_STATUS = '500 Internal Server Error' _INTERNAL_ERROR_BODY = b('Internal Server Error') _INTERNAL_ERROR_HEADERS = [('Content-Type', 'text/plain'), ('Connection', 'close'), ('Content-Length', str(len(_INTERNAL_ERROR_BODY)))] _REQUEST_TOO_LONG_RESPONSE = b( "HTTP/1.0 414 Request URI Too Long\r\nConnection: close\r\nContent-length: 0\r\n\r\n" ) _BAD_REQUEST_RESPONSE = b( "HTTP/1.0 400 Bad Request\r\nConnection: close\r\nContent-length: 0\r\n\r\n" ) _CONTINUE_RESPONSE = b("HTTP/1.1 100 Continue\r\n\r\n") def format_date_time(timestamp): year, month, day, hh, mm, ss, wd, _y, _z = time.gmtime(timestamp) return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (