def random_bytes(n): """Returns n random bytes generated with given seed --- tags: - Dynamic data parameters: - in: path name: n type: int produces: - application/octet-stream responses: 200: description: Bytes. """ n = min(n, 100 * 1024) # set 100KB limit params = CaseInsensitiveDict(request.args.items()) if "seed" in params: random.seed(int(params["seed"])) response = make_response() # Note: can't just use os.urandom here because it ignores the seed response.data = bytearray(random.randint(0, 255) for i in range(n)) response.content_type = "application/octet-stream" return response
def redirect_later(): """302 redirect to / after the given delay. If delay is -1, wait until a request on redirect-later-continue is done. """ global _redirect_later_event args = CaseInsensitiveDict(flask.request.args.items()) delay = int(args.get('delay', '1')) if delay == -1: _redirect_later_event = threading.Event() ok = _redirect_later_event.wait(timeout=30 * 1000) assert ok _redirect_later_event = None else: time.sleep(delay) x = flask.redirect('/') return x
def stream_random_bytes(n): """Streams n random bytes generated with given seed, at given chunk size per packet. --- tags: - Dynamic data parameters: - in: path name: n type: int produces: - application/octet-stream responses: 200: description: Bytes. """ n = min(n, 100 * 1024) # set 100KB limit params = CaseInsensitiveDict(request.args.items()) if "seed" in params: random.seed(int(params["seed"])) if "chunk_size" in params: chunk_size = max(1, int(params["chunk_size"])) else: chunk_size = 10 * 1024 def generate_bytes(): chunks = bytearray() for i in xrange(n): chunks.append(random.randint(0, 255)) if len(chunks) == chunk_size: yield (bytes(chunks)) chunks = bytearray() if chunks: yield (bytes(chunks)) headers = {"Content-Type": "application/octet-stream"} return Response(generate_bytes(), headers=headers)
def redirect_later(): """302 redirects to / after the given delay.""" args = CaseInsensitiveDict(flask.request.args.items()) time.sleep(int(args.get('delay', '1'))) return flask.redirect('/')
def redirect_to(): """302/3XX Redirects to the given URL. --- tags: - Redirects produces: - text/html get: parameters: - in: query name: url type: string required: true - in: query name: status_code type: int post: consumes: - application/x-www-form-urlencoded parameters: - in: formData name: url type: string required: true - in: formData name: status_code type: int required: false patch: consumes: - application/x-www-form-urlencoded parameters: - in: formData name: url type: string required: true - in: formData name: status_code type: int required: false put: consumes: - application/x-www-form-urlencoded parameters: - in: formData name: url type: string required: true - in: formData name: status_code type: int required: false responses: 302: description: A redirection. """ args_dict = request.args.items() args = CaseInsensitiveDict(args_dict) # We need to build the response manually and convert to UTF-8 to prevent # werkzeug from "fixing" the URL. This endpoint should set the Location # header to the exact string supplied. response = app.make_response("") response.status_code = 302 if "status_code" in args: status_code = int(args["status_code"]) if status_code >= 300 and status_code < 400: response.status_code = status_code response.headers["Location"] = args["url"].encode("utf-8") return response
def range_request(numbytes): """Streams n random bytes generated with given seed, at given chunk size per packet. --- tags: - Dynamic data parameters: - in: path name: numbytes type: int produces: - application/octet-stream responses: 200: description: Bytes. """ if numbytes <= 0 or numbytes > (100 * 1024): response = Response(headers={ "ETag": "range%d" % numbytes, "Accept-Ranges": "bytes" }) response.status_code = 404 response.data = "number of bytes must be in the range (0, 102400]" return response params = CaseInsensitiveDict(request.args.items()) if "chunk_size" in params: chunk_size = max(1, int(params["chunk_size"])) else: chunk_size = 10 * 1024 duration = float(params.get("duration", 0)) pause_per_byte = duration / numbytes request_headers = get_headers() first_byte_pos, last_byte_pos = get_request_range(request_headers, numbytes) range_length = (last_byte_pos + 1) - first_byte_pos if (first_byte_pos > last_byte_pos or first_byte_pos not in xrange(0, numbytes) or last_byte_pos not in xrange(0, numbytes)): response = Response( headers={ "ETag": "range%d" % numbytes, "Accept-Ranges": "bytes", "Content-Range": "bytes */%d" % numbytes, "Content-Length": "0", }) response.status_code = 416 return response def generate_bytes(): chunks = bytearray() for i in xrange(first_byte_pos, last_byte_pos + 1): # We don't want the resource to change across requests, so we need # to use a predictable data generation function chunks.append(ord("a") + (i % 26)) if len(chunks) == chunk_size: yield (bytes(chunks)) time.sleep(pause_per_byte * chunk_size) chunks = bytearray() if chunks: time.sleep(pause_per_byte * len(chunks)) yield (bytes(chunks)) content_range = "bytes %d-%d/%d" % (first_byte_pos, last_byte_pos, numbytes) response_headers = { "Content-Type": "application/octet-stream", "ETag": "range%d" % numbytes, "Accept-Ranges": "bytes", "Content-Length": str(range_length), "Content-Range": content_range, } response = Response(generate_bytes(), headers=response_headers) if (first_byte_pos == 0) and (last_byte_pos == (numbytes - 1)): response.status_code = 200 else: response.status_code = 206 return response
def drip(): """Drips data over a duration after an optional initial delay. --- tags: - Dynamic data parameters: - in: query name: duration type: number description: The amount of time (in seconds) over which to drip each byte default: 2 required: false - in: query name: numbytes type: integer description: The number of bytes to respond with default: 10 required: false - in: query name: code type: integer description: The response code that will be returned default: 200 required: false - in: query name: delay type: number description: The amount of time (in seconds) to delay before responding default: 2 required: false produces: - application/octet-stream responses: 200: description: A dripped response. """ args = CaseInsensitiveDict(request.args.items()) duration = float(args.get("duration", 2)) numbytes = min(int(args.get("numbytes", 10)), (10 * 1024 * 1024)) # set 10MB limit code = int(args.get("code", 200)) if numbytes <= 0: response = Response("number of bytes must be positive", status=400) return response delay = float(args.get("delay", 0)) if delay > 0: time.sleep(delay) pause = duration / numbytes def generate_bytes(): for i in xrange(numbytes): yield b"*" time.sleep(pause) response = Response( generate_bytes(), headers={ "Content-Type": "application/octet-stream", "Content-Length": str(numbytes), }, ) response.status_code = code return response