Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
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)
Example #5
0
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('/')
Example #6
0
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
Example #7
0
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
Example #8
0
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