Skip to content

Commit

Permalink
add configuration option for web interface address (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
cle-b authored Sep 28, 2024
1 parent cfb3608 commit e7387ce
Show file tree
Hide file tree
Showing 13 changed files with 124 additions and 63 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ httdbg - a very simple tool to debug HTTP(S) client requests

options:
-h, --help show this help message and exit
--host HOST the web interface host IP address
--port PORT, -p PORT the web interface port
--version, -v print the httpdbg version
--initiator INITIATOR, -i INITIATOR
Expand Down
2 changes: 1 addition & 1 deletion httpdbg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
from httpdbg.records import HTTPRecords


__version__ = "0.22.0"
__version__ = "0.23.0"

__all__ = ["httprecord", "HTTPRecords"]
4 changes: 2 additions & 2 deletions httpdbg/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ def print_msg(msg):


def pyhttpdbg(params, subparams, test_mode=False):
url = f"http://localhost:{params.port}/{'?hi=on' if params.console else ''}"
url = f"http://{params.host}:{params.port}/{'?hi=on' if params.console else ''}"

print_msg(f" httpdbg - HTTP(S) requests available at {url}")

sys.path.insert(0, "") # to mimic the default python command behavior

with httpdbg_srv(params.port) as records:
with httpdbg_srv(params.host, params.port) as records:
with httprecord(records, params.initiator):
if params.module:
run_module(subparams)
Expand Down
6 changes: 6 additions & 0 deletions httpdbg/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ def read_args(args: List[str]) -> Tuple[argparse.Namespace, List[str]]:
parser = argparse.ArgumentParser(
description="httdbg - a very simple tool to debug HTTP(S) client requests"
)
parser.add_argument(
"--host",
type=str,
default="localhost",
help="the web interface host IP address",
)
parser.add_argument(
"--port", "-p", type=int, default=4909, help="the web interface port"
)
Expand Down
7 changes: 7 additions & 0 deletions httpdbg/exception.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-


class HttpdbgException(Exception):
"""An issue occurred in httpdbg."""

pass
16 changes: 11 additions & 5 deletions httpdbg/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@
import threading
from typing import Generator

from httpdbg.exception import HttpdbgException
from httpdbg.records import HTTPRecords
from httpdbg.webapp import HttpbgHTTPRequestHandler


@contextmanager
def httpdbg_srv(port: int) -> Generator[HTTPRecords, None, None]:
def httpdbg_srv(host: str, port: int) -> Generator[HTTPRecords, None, None]:
server = None
records = HTTPRecords()
try:
server = ServerThread(port, records)
server.start()
try:
server = ServerThread(host, port, records)
server.start()
except Exception as ex_server_start:
raise HttpdbgException(
f"An issue occurred while starting the httpdbg web interface: [{str(ex_server_start)}]"
)

yield records

Expand All @@ -26,14 +32,14 @@ def httpdbg_srv(port: int) -> Generator[HTTPRecords, None, None]:


class ServerThread(threading.Thread):
def __init__(self, port: int, records: HTTPRecords) -> None:
def __init__(self, host: str, port: int, records: HTTPRecords) -> None:
threading.Thread.__init__(self)
self.port = port

def http_request_handler(*args, **kwargs):
HttpbgHTTPRequestHandler(records, *args, **kwargs)

self.srv = HTTPServer(("localhost", port), http_request_handler)
self.srv = HTTPServer((host, port), http_request_handler)

def run(self):
self.srv.serve_forever()
Expand Down
1 change: 1 addition & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ markers =
urllib3: the hook for the "urllib3" package
initiator: all tests related to the initiator
ui: the web UI
server: the web server
filterwarnings =
ignore::DeprecationWarning:pytest_selenium.*:
ignore::DeprecationWarning::
Expand Down
62 changes: 31 additions & 31 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@


@pytest.mark.api
def test_api_requests_one_request(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_api_requests_one_request(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
requests.get(httpbin.url + "/get")

ret = requests.get(f"http://127.0.0.1:{httpdbg_port}/requests")
ret = requests.get(f"http://{httpdbg_host}:{httpdbg_port}/requests")

reqs = ret.json()["requests"]

Expand All @@ -25,13 +25,13 @@ def test_api_requests_one_request(httpbin, httpdbg_port):


@pytest.mark.api
def test_api_requests_two_requests(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_api_requests_two_requests(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
requests.get(httpbin.url + "/get?abc")
requests.get(httpbin.url + "/get?def")

ret = requests.get(f"http://127.0.0.1:{httpdbg_port}/requests")
ret = requests.get(f"http://{httpdbg_host}:{httpdbg_port}/requests")

reqs = ret.json()["requests"]

Expand All @@ -41,11 +41,11 @@ def test_api_requests_two_requests(httpbin, httpdbg_port):


@pytest.mark.api
def test_api_requests_netloc(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_api_requests_netloc(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
requests.get(httpbin.url + "/get?abc")
ret = requests.get(f"http://127.0.0.1:{httpdbg_port}/requests")
ret = requests.get(f"http://{httpdbg_host}:{httpdbg_port}/requests")

reqs = ret.json()["requests"]

Expand All @@ -56,8 +56,8 @@ def test_api_requests_netloc(httpbin, httpdbg_port):


@pytest.mark.api
def test_api_request_by_id(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_api_request_by_id(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
requests.get(httpbin.url + "/get?abc")
requests.get(httpbin.url + "/get?def")
Expand All @@ -73,20 +73,20 @@ def test_api_request_by_id(httpbin, httpdbg_port):


@pytest.mark.api
def test_api_request_by_id_not_exists(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_api_request_by_id_not_exists(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
requests.get(httpbin.url + "/get?abc")
requests.get(httpbin.url + "/get?def")

ret = requests.get(f"http://127.0.0.1:{httpdbg_port}/request/999")
ret = requests.get(f"http://{httpdbg_host}:{httpdbg_port}/request/999")

assert ret.status_code == 404


@pytest.mark.api
def test_api_get_request_get(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_api_get_request_get(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
requests.get(httpbin.url + "/")
requests.get(httpbin.url + "/get")
Expand All @@ -95,7 +95,7 @@ def test_api_get_request_get(httpbin, httpdbg_port):

path_to_content = ret.json()["response"]["body"]["path"]
req_response_content = requests.get(
f"http://127.0.0.1:{httpdbg_port}{path_to_content}"
f"http://{httpdbg_host}:{httpdbg_port}{path_to_content}"
)

# headers
Expand All @@ -122,8 +122,8 @@ def test_api_get_request_get(httpbin, httpdbg_port):


@pytest.mark.api
def test_api_get_request_post(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_api_get_request_post(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
requests.get(httpbin.url + "/")
requests.post(httpbin.url + "/post", data=b"data to post")
Expand All @@ -132,12 +132,12 @@ def test_api_get_request_post(httpbin, httpdbg_port):

path_to_content = ret.json()["request"]["body"]["path"]
req_request_content = requests.get(
f"http://127.0.0.1:{httpdbg_port}{path_to_content}"
f"http://{httpdbg_host}:{httpdbg_port}{path_to_content}"
)

path_to_content = ret.json()["response"]["body"]["path"]
req_response_content = requests.get(
f"http://127.0.0.1:{httpdbg_port}{path_to_content}"
f"http://{httpdbg_host}:{httpdbg_port}{path_to_content}"
)

# headers
Expand Down Expand Up @@ -167,8 +167,8 @@ def test_api_get_request_post(httpbin, httpdbg_port):


@pytest.mark.api
def test_api_get_request_get_status_404(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_api_get_request_get_status_404(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
ret = requests.get(httpbin.url + "/abc")
assert ret.status_code == 404
Expand All @@ -181,10 +181,10 @@ def test_api_get_request_get_status_404(httpbin, httpdbg_port):


@pytest.mark.api
def test_api_get_request_connection_error(httpbin, httpdbg_port):
def test_api_get_request_connection_error(httpbin, httpdbg_host, httpdbg_port):
url_with_unknown_host = "http://f.q.d.1234.n.t.n.e/hello?a=b"

with httpdbg_srv(httpdbg_port) as records:
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
with pytest.raises(requests.exceptions.ConnectionError):
requests.get(url_with_unknown_host)
Expand All @@ -197,8 +197,8 @@ def test_api_get_request_connection_error(httpbin, httpdbg_port):


@pytest.mark.api
def test_api_get_request_content_up_text(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_api_get_request_content_up_text(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
requests.post(httpbin.url + "/post", data={"a": 1, "b": 2})
requests.post(httpbin.url + "/post", data="hello")
Expand All @@ -215,8 +215,8 @@ def test_api_get_request_content_up_text(httpbin, httpdbg_port):

@pytest.mark.api
@pytest.mark.cookies
def test_cookies_request(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_cookies_request(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
session = requests.session()
session.cookies.set("COOKIE_NAME", "the-cookie-works")
Expand All @@ -232,8 +232,8 @@ def test_cookies_request(httpbin, httpdbg_port):

@pytest.mark.api
@pytest.mark.cookies
def test_cookies_response(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_cookies_response(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
session = requests.session()
session.get(
Expand Down
6 changes: 3 additions & 3 deletions tests/test_mode_console.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ def test_run_console_from_pyhttpdbg_entry_point_default(
assert "test_mode is on" in capsys.readouterr().out


def test_run_console(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_run_console(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
new_console = run_console(test_mode=True)
new_console.push("import requests")
new_console.push(f"requests.get('{httpbin.url}/get')")
with pytest.raises(SystemExit):
new_console.push("exit()")

ret = requests.get(f"http://127.0.0.1:{httpdbg_port}/requests")
ret = requests.get(f"http://{httpdbg_host}:{httpdbg_port}/requests")

reqs = ret.json()["requests"]

Expand Down
20 changes: 10 additions & 10 deletions tests/test_mode_module_pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


@pytest.mark.pytest
def test_run_pytest_from_pyhttpdbg_entry_point(httpbin, httpdbg_port, monkeypatch):
def test_run_pytest_from_pyhttpdbg_entry_point(httpbin, monkeypatch):
os.environ["HTTPDBG_TEST_PYTEST_BASE_URL"] = httpbin.url
script_to_run = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "demo_run_pytest.py"
Expand All @@ -29,16 +29,16 @@ def test_run_pytest_from_pyhttpdbg_entry_point(httpbin, httpdbg_port, monkeypatc


@pytest.mark.pytest
def test_run_pytest(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_run_pytest(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
os.environ["HTTPDBG_TEST_PYTEST_BASE_URL"] = httpbin.url
script_to_run = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "demo_run_pytest.py"
)
run_module(["pytest", f"{script_to_run}::test_demo_pytest"])

ret = requests.get(f"http://127.0.0.1:{httpdbg_port}/requests")
ret = requests.get(f"http://{httpdbg_host}:{httpdbg_port}/requests")

reqs = ret.json()["requests"]

Expand All @@ -49,15 +49,15 @@ def test_run_pytest(httpbin, httpdbg_port):


@pytest.mark.pytest
def test_run_pytest_with_exception(httpdbg_port, capsys):
with httpdbg_srv(httpdbg_port) as records:
def test_run_pytest_with_exception(httpdbg_host, httpdbg_port, capsys):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
script_to_run = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "demo_run_pytest.py"
)
run_module(["pytest", f"{script_to_run}::test_demo_raise_exception"])

ret = requests.get(f"http://127.0.0.1:{httpdbg_port}/requests")
ret = requests.get(f"http://{httpdbg_host}:{httpdbg_port}/requests")

reqs = ret.json()["requests"]

Expand All @@ -68,16 +68,16 @@ def test_run_pytest_with_exception(httpdbg_port, capsys):

@pytest.mark.api
@pytest.mark.pytest
def test_run_pytest_initiator(httpbin, httpdbg_port):
with httpdbg_srv(httpdbg_port) as records:
def test_run_pytest_initiator(httpbin, httpdbg_host, httpdbg_port):
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
with httprecord(records):
os.environ["HTTPDBG_TEST_PYTEST_BASE_URL"] = httpbin.url
script_to_run = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "demo_run_pytest.py"
)
run_module(["pytest", f"{script_to_run}::test_demo_pytest"])

ret = requests.get(f"http://127.0.0.1:{httpdbg_port}/requests")
ret = requests.get(f"http://{httpdbg_host}:{httpdbg_port}/requests")

reqs = ret.json()["requests"]

Expand Down
Loading

0 comments on commit e7387ce

Please sign in to comment.