Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating to Python 3.8 #2

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ codekit-config.json

# Mac Files
**/.DS_Store
**/.vscode
39 changes: 23 additions & 16 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
FROM python:2.7-alpine
FROM alpine:3.14.3

RUN apk update && apk upgrade && \
apk add \
gcc python python-dev py-pip \
# greenlet
musl-dev \
# sys/queue.h
bsd-compat-headers \
# event.h
libevent-dev \
build-base \
py3-pip \
libffi-dev \
# Package for running environment
py3-gevent \
py3-greenlet \
py3-gunicorn \
python3-dbg \
py3-zope-component \
# file
file \
&& rm -rf /var/cache/apk/*

RUN addgroup --gid 1000 -S requestbin && adduser -S requestbin -u 1000 -G requestbin -h /opt/requestbin
USER 1000:1000
# want all dependencies first so that if it's just a code change, don't have to
# rebuild as much of the container
ADD requirements.txt /opt/requestbin/
RUN pip install -r /opt/requestbin/requirements.txt \
&& rm -rf ~/.pip/cache

&& rm -rf ~/.pip/cache
USER root
RUN apk del \
build-base \
py3-pip \
libffi-dev
USER 1000:1000
# the code
ADD requestbin /opt/requestbin/requestbin/
ADD requestbin /opt/requestbin/requestbin/

EXPOSE 8000

WORKDIR /opt/requestbin
CMD gunicorn -b 0.0.0.0:8000 --worker-class gevent --workers 2 --max-requests 1000 requestbin:app


CMD gunicorn -b 0.0.0.0:8000 --worker-class gevent --workers 1 --max-requests 1000 requestbin.app:app
25 changes: 25 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]
gevent = "*"
flake8 = "*"
autopep8 = "*"
gunicorn = "*"

[packages]
nose = "*"
feedparser = "*"
redis = "*"
msgpack-python = "*"
python-dateutil = "*"
gunicorn = "==19.9.0"
bugsnag = "*"
blinker = "*"
ProxyTypes = "*"
Flask-Cors = "*"

[requires]
python_version = "3.8"
363 changes: 363 additions & 0 deletions Pipfile.lock

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions app.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
{
"name": "requestbin",
"description": "Inspect HTTP requests. Debug webhooks.",
"website": "http://requestb.in/",
"repository": "https://github.com/Runscope/requestbin",
"logo": "http://requestb.in/static/img/logo-2x.png",
"repository": "https://github.com/cellebyte/requestbin",
"keywords": ["python"],
"env": {
"REALM": {
Expand Down
107 changes: 52 additions & 55 deletions requestbin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,58 @@
import config
import os
from cStringIO import StringIO

from io import BytesIO
from flask import Flask
from flask_cors import CORS

import requestbin.config as config
from requestbin.filters import (approximate_time, exact_time, friendly_size,
friendly_time, short_date, status_class, to_qs)
from werkzeug.middleware.proxy_fix import ProxyFix


class MyApplication(Flask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.wsgi_app = WSGIRawBody(ProxyFix(self.wsgi_app))
self.add_config()
self.add_filters()

def add_config(self):
self.debug = config.DEBUG
self.secret_key = config.FLASK_SESSION_SECRET_KEY
self.root_path = os.path.abspath(os.path.dirname(__file__))
if config.BUGSNAG_KEY:
import bugsnag
from bugsnag.flask import handle_exceptions
bugsnag.configure(
api_key=config.BUGSNAG_KEY,
project_root=self.root_path,
# 'production' is a magic string for bugsnag, rest are arbitrary
release_stage=config.REALM.replace("prod", "production"),
notify_release_stages=["production", "test"],
use_ssl=True
)
handle_exceptions(self)
if os.environ.get('ENABLE_CORS', config.ENABLE_CORS):
_ = CORS(
self,
resources={
r"*": {
"origins": os.environ.get(
'CORS_ORIGINS', config.CORS_ORIGINS
)
}
}
)

def add_filters(self):
self.jinja_env.filters['status_class'] = status_class
self.jinja_env.filters['friendly_time'] = friendly_time
self.jinja_env.filters['friendly_size'] = friendly_size
self.jinja_env.filters['to_qs'] = to_qs
self.jinja_env.filters['approximate_time'] = approximate_time
self.jinja_env.filters['exact_time'] = exact_time
self.jinja_env.filters['short_date'] = short_date


class WSGIRawBody(object):
def __init__(self, application):
Expand All @@ -17,7 +65,7 @@ def __call__(self, environ, start_response):

body = environ['wsgi.input'].read(length)
environ['raw'] = body
environ['wsgi.input'] = StringIO(body)
environ['wsgi.input'] = BytesIO(body)

# Call the wrapped application
app_iter = self.application(environ, self._sr_callback(start_response))
Expand All @@ -31,54 +79,3 @@ def callback(status, headers, exc_info=None):
# Call upstream start_response
start_response(status, headers, exc_info)
return callback



app = Flask(__name__)

if os.environ.get('ENABLE_CORS', config.ENABLE_CORS):
cors = CORS(app, resources={r"*": {"origins": os.environ.get('CORS_ORIGINS', config.CORS_ORIGINS)}})

from werkzeug.contrib.fixers import ProxyFix
app.wsgi_app = WSGIRawBody(ProxyFix(app.wsgi_app))

app.debug = config.DEBUG
app.secret_key = config.FLASK_SESSION_SECRET_KEY
app.root_path = os.path.abspath(os.path.dirname(__file__))

if config.BUGSNAG_KEY:
import bugsnag
from bugsnag.flask import handle_exceptions
bugsnag.configure(
api_key=config.BUGSNAG_KEY,
project_root=app.root_path,
# 'production' is a magic string for bugsnag, rest are arbitrary
release_stage = config.REALM.replace("prod", "production"),
notify_release_stages=["production", "test"],
use_ssl = True
)
handle_exceptions(app)

from filters import *
app.jinja_env.filters['status_class'] = status_class
app.jinja_env.filters['friendly_time'] = friendly_time
app.jinja_env.filters['friendly_size'] = friendly_size
app.jinja_env.filters['to_qs'] = to_qs
app.jinja_env.filters['approximate_time'] = approximate_time
app.jinja_env.filters['exact_time'] = exact_time
app.jinja_env.filters['short_date'] = short_date

app.add_url_rule('/', 'views.home')
app.add_url_rule('/<path:name>', 'views.bin', methods=['GET', 'POST', 'DELETE', 'PUT', 'OPTIONS', 'HEAD', 'PATCH', 'TRACE'])

app.add_url_rule('/docs/<name>', 'views.docs')
app.add_url_rule('/api/v1/bins', 'api.bins', methods=['POST'])
app.add_url_rule('/api/v1/bins/<name>', 'api.bin', methods=['GET'])
app.add_url_rule('/api/v1/bins/<bin>/requests', 'api.requests', methods=['GET'])
app.add_url_rule('/api/v1/bins/<bin>/requests/<name>', 'api.request', methods=['GET'])

app.add_url_rule('/api/v1/stats', 'api.stats')

# app.add_url_rule('/robots.txt', redirect_to=url_for('static', filename='robots.txt'))

from requestbin import api, views
12 changes: 4 additions & 8 deletions requestbin/api.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import json
import operator

from flask import session, make_response, request, render_template
from requestbin import app, db
from flask import make_response, request, session

from requestbin import db


def _response(object, code=200):
jsonp = request.args.get('jsonp')
Expand All @@ -16,7 +17,6 @@ def _response(object, code=200):
return resp


@app.endpoint('api.bins')
def bins():
private = request.form.get('private') in ['true', 'on']
bin = db.create_bin(private)
Expand All @@ -25,7 +25,6 @@ def bins():
return _response(bin.to_dict())


@app.endpoint('api.bin')
def bin(name):
try:
bin = db.lookup_bin(name)
Expand All @@ -35,7 +34,6 @@ def bin(name):
return _response(bin.to_dict())


@app.endpoint('api.requests')
def requests(bin):
try:
bin = db.lookup_bin(bin)
Expand All @@ -45,7 +43,6 @@ def requests(bin):
return _response([r.to_dict() for r in bin.requests])


@app.endpoint('api.request')
def request_(bin, name):
try:
bin = db.lookup_bin(bin)
Expand All @@ -59,7 +56,6 @@ def request_(bin, name):
return _response({'error': "Request not found"}, 404)


@app.endpoint('api.stats')
def stats():
stats = {
'bin_count': db.count_bins(),
Expand Down
42 changes: 42 additions & 0 deletions requestbin/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from requestbin import MyApplication
import requestbin.views as views
import requestbin.api as api


app = MyApplication(__name__)

app.add_url_rule('/', 'views.home', views.home)
views.bin.methods = [
'GET',
'POST',
'DELETE',
'PUT',
'OPTIONS',
'HEAD',
'PATCH',
'TRACE'
]
app.add_url_rule('/<path:name>', 'views.bin', views.bin)

api.bins.provide_automatic_options = False
api.bins.methods = ['POST']
app.add_url_rule(
'/api/v1/bins', 'api.bins', api.bins)

api.bin.provide_automatic_options = False
api.bin.methods = ['GET']
app.add_url_rule(
'/api/v1/bins/<name>', 'api.bin', api.bin)

api.requests.provide_automatic_options = False
api.requests.methods = ['GET']
app.add_url_rule('/api/v1/bins/<bin>/requests',
'api.requests', api.requests, methods=['GET'])


api.request_.provide_automatic_options = False
api.request_.methods = ['GET']
app.add_url_rule('/api/v1/bins/<bin>/requests/<name>', 'api.request_', api.request_)


app.add_url_rule('/api/v1/stats', 'api.stats', api.stats)
5 changes: 3 additions & 2 deletions requestbin/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os, urlparse
import os
import urllib.parse as urlparse
DEBUG = os.environ.get("DEBUG", True)
REALM = os.environ.get('REALM', 'local')

Expand All @@ -14,7 +15,7 @@
STORAGE_BACKEND = "requestbin.storage.memory.MemoryStorage"
MAX_RAW_SIZE = int(os.environ.get('MAX_RAW_SIZE', 1024*10))
IGNORE_HEADERS = []
MAX_REQUESTS = os.environ.get("MAX_REQUESTS", 20)
MAX_REQUESTS = int(os.environ.get("MAX_REQUESTS", 20))
CLEANUP_INTERVAL = 3600
MAX_JSON_TO_PRETTYPARSE_IN_BYTES = int(os.environ.get('MAX_JSON_TO_PRETTYPARSE_IN_BYTES', 300*1024))

Expand Down
18 changes: 12 additions & 6 deletions requestbin/db.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import feedparser
import time
import re
from requestbin import config

Expand All @@ -9,27 +7,35 @@
storage_module, storage_class = storage_backend.rsplit('.', 1)

try:
klass = getattr(__import__(storage_module, fromlist=[storage_class]), storage_class)
except ImportError, e:
raise ImportError("Unable to load storage backend '{}': {}".format(storage_backend, e))
klass = getattr(__import__(storage_module, fromlist=[
storage_class]), storage_class)
except ImportError as e:
raise ImportError(
"Unable to load storage backend '{}': {}".format(storage_backend, e))

db = klass(bin_ttl)


def create_bin(private=False):
return db.create_bin(private)


def create_request(bin, request):
return db.create_request(bin, request)


def lookup_bin(name):
name=re.split(r"[/.]", name)[0]
name = re.split(r"[/.]", name)[0]
return db.lookup_bin(name)


def count_bins():
return db.count_bins()


def count_requests():
return db.count_requests()


def avg_req_size():
return db.avg_req_size()
Loading