#!/usr/bin/python3
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import requests
import threading
import time
import atheris

with atheris.instrument_imports():
  from flask import Flask
  from flask_cors import CORS
  from flask import request

app = Flask(__name__)
CORS(app)
output = ""

@app.errorhandler(500)
def internal_error(error):
  print(
    "Catching exception error from flask. The exception is likely "
    "printed already right above this message in the log."
  )
  return str(error), 500

@app.route("/")
def fuzz_echo():
  global output
  return output

def shutdown_server():
  func = request.environ.get('werkzeug.server.shutdown')
  if func is None:
    raise RuntimeError('Not running with the Werkzeug Server')
  func()

# We use this to force a shutdown of the app. This is to
# have a clean exit when a crash is found.
@app.route('/shutdown')
def shutdown():
  shutdown_server()
  return "Server shutdown"

class ServerThread(threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)

  def run(self):
    global app
    app.run()

def TestOneInput(data):
  global output
  output = data

  try:
    r = requests.get('http://127.0.0.1:5000', timeout=0.5)
    if r.status_code == 500:
        raise Exception(r.text)
  except requests.exceptions.ConnectionError:
    None
  except Exception as e:
    # Every other exception is raised, but we need to shutdown
    # the server before raising it.
    requests.get('http://127.0.0.1:5000/shutdown', timeout=1.02)
    raise e

def main():
  t1 = ServerThread()
  t1.start()
  atheris.Setup(sys.argv, TestOneInput, enable_python_coverage=True)
  atheris.Fuzz()
  t1.join()

if __name__ == "__main__":
  main()

#!/usr/bin/python3
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import requests
import threading
import time
import atheris

with atheris.instrument_imports():
  from flask import Flask
  from flask_cors import CORS
  from flask import request

app = Flask(__name__)
CORS(app)
output = ""
runs_left = None

@app.errorhandler(500)
def internal_error(error):
  print(
    "Catching exception error from flask. The exception is likely "
    "printed already right above this message in the log."
  )
  return str(error), 500

@app.route("/")
def fuzz_echo():
  global output
  return output

def shutdown_server():
  func = request.environ.get('werkzeug.server.shutdown')
  if func is None:
    raise RuntimeError('Not running with the Werkzeug Server')
  func()

# We use this to force a shutdown of the app. This is to
# have a clean exit when a crash is found.
@app.route('/shutdown')
def shutdown():
  shutdown_server()
  return "Server shutdown"

class ServerThread(threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)

  def run(self):
    global app
    app.run()

def TestOneInput(data):
  global output, runs_left
  output = data

  # We use runs_left to ensure proper exit in coverage.
  if runs_left != None:
      runs_left -= 1
      # 5 may be too much here, as we will cut off some inputs. However,
      # this is to guarantee exit for now.
      if runs_left < 5:
        try:
          requests.get('http://127.0.0.1:5000/shutdown', timeout=1.02)
        except Exception:
          None
        return


  try:
    r = requests.get('http://127.0.0.1:5000', timeout=0.5)
    if r.status_code == 500:
        raise Exception(r.text)
  except requests.exceptions.ConnectionError:
    None
  except Exception as e:
    # Every other exception is raised, but we need to shutdown
    # the server before raising it.
    requests.get('http://127.0.0.1:5000/shutdown', timeout=1.02)
    raise e


def get_run_count_if_there():
  parser = argparse.ArgumentParser()
  parser.add_argument("-atheris_runs", required=False, default=None)
  args, _ = parser.parse_known_args()
  if args.atheris_runs is None:
    print("None args")
    return None
  print(f"Got a fixed set of runs {args.atheris_runs}")
  return args.atheris_runs


def main():
  global runs_left
  max_runs = get_run_count_if_there()
  if max_runs is not None:
    runs_left = int(max_runs)

  t1 = ServerThread()
  t1.start()
  atheris.Setup(sys.argv, TestOneInput, enable_python_coverage=True)
  atheris.Fuzz()

if __name__ == "__main__":
  main()

fix flask_cors coverage (#7710)