httpdbg 0.13.2__tar.gz → 0.13.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. {httpdbg-0.13.2 → httpdbg-0.13.4}/PKG-INFO +1 -1
  2. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/__init__.py +1 -1
  3. httpdbg-0.13.4/httpdbg/preview.py +53 -0
  4. httpdbg-0.13.4/httpdbg/webapp/static/filter.js +29 -0
  5. httpdbg-0.13.4/httpdbg/webapp/static/icons/filter-outline-icon.svg +1 -0
  6. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/index.htm +2 -2
  7. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/render.js +43 -1
  8. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/table.css +8 -0
  9. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg.egg-info/PKG-INFO +1 -1
  10. httpdbg-0.13.4/tests/test_preview.py +56 -0
  11. httpdbg-0.13.2/httpdbg/preview.py +0 -88
  12. httpdbg-0.13.2/httpdbg/webapp/static/filter.js +0 -18
  13. httpdbg-0.13.2/httpdbg/webapp/static/icons/filter-outline-icon.svg +0 -1
  14. httpdbg-0.13.2/tests/test_preview.py +0 -96
  15. {httpdbg-0.13.2 → httpdbg-0.13.4}/LICENSE +0 -0
  16. {httpdbg-0.13.2 → httpdbg-0.13.4}/README.md +0 -0
  17. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/__main__.py +0 -0
  18. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/args.py +0 -0
  19. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/hooks/__init__.py +0 -0
  20. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/hooks/aiohttp.py +0 -0
  21. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/hooks/all.py +0 -0
  22. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/hooks/generic.py +0 -0
  23. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/hooks/httpx.py +0 -0
  24. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/hooks/requests.py +0 -0
  25. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/hooks/socket.py +0 -0
  26. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/hooks/urllib3.py +0 -0
  27. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/hooks/utils.py +0 -0
  28. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/initiator.py +0 -0
  29. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/mode_console.py +0 -0
  30. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/mode_module.py +0 -0
  31. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/mode_script.py +0 -0
  32. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/records.py +0 -0
  33. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/server.py +0 -0
  34. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/utils.py +0 -0
  35. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/__init__.py +0 -0
  36. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/api.py +0 -0
  37. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/app.py +0 -0
  38. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/api.js +0 -0
  39. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/column.css +0 -0
  40. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/configuration.js +0 -0
  41. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/detail.css +0 -0
  42. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/favicon.ico +0 -0
  43. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/icons/download-install-line-icon.svg +0 -0
  44. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/icons/engine-gears-icon.svg +0 -0
  45. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/icons/files-papers-outline-icon.svg +0 -0
  46. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/icons/information-mark-circle-outline-icon.svg +0 -0
  47. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/icons/math-multiplication-icon.svg +0 -0
  48. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/icons/push-pin-green-icon.svg +0 -0
  49. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/icons/question-mark-round-line-icon.svg +0 -0
  50. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/icons/recycle-bin-line-icon.svg +0 -0
  51. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/icons/wait-sandclock-icon.svg +0 -0
  52. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/main.js +0 -0
  53. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/mustache.min.js +0 -0
  54. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg/webapp/static/style.css +0 -0
  55. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg.egg-info/SOURCES.txt +0 -0
  56. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg.egg-info/dependency_links.txt +0 -0
  57. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg.egg-info/entry_points.txt +0 -0
  58. {httpdbg-0.13.2 → httpdbg-0.13.4}/httpdbg.egg-info/top_level.txt +0 -0
  59. {httpdbg-0.13.2 → httpdbg-0.13.4}/pyproject.toml +0 -0
  60. {httpdbg-0.13.2 → httpdbg-0.13.4}/setup.cfg +0 -0
  61. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_api.py +0 -0
  62. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_cli.py +0 -0
  63. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_context_manager.py +0 -0
  64. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_hook_aiohttp.py +0 -0
  65. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_hook_httpx.py +0 -0
  66. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_hook_requests.py +0 -0
  67. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_hook_urllib3.py +0 -0
  68. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_initiator.py +0 -0
  69. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_mode_console.py +0 -0
  70. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_mode_module_pytest.py +0 -0
  71. {httpdbg-0.13.2 → httpdbg-0.13.4}/tests/test_mode_script.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: httpdbg
3
- Version: 0.13.2
3
+ Version: 0.13.4
4
4
  Summary: A very simple tool to debug HTTP(S) client requests
5
5
  Author-email: cle-b <cle@tictac.pm>
6
6
  License: Apache-2.0
@@ -3,6 +3,6 @@ from httpdbg.hooks.all import httpdbg
3
3
  from httpdbg.records import HTTPRecords
4
4
 
5
5
 
6
- VERSION = "0.13.2"
6
+ VERSION = "0.13.4"
7
7
 
8
8
  __all__ = ["httpdbg", "HTTPRecords"]
@@ -0,0 +1,53 @@
1
+ # -*- coding: utf-8 -*-
2
+ from typing import Tuple, Dict, Union
3
+
4
+
5
+ def parse_content_type(content_type: str) -> Tuple[str, Dict[str, str]]:
6
+ s = content_type.split(";")
7
+ media_type = s[0]
8
+ directives = {}
9
+ for directive in s[1:]:
10
+ sp = directive.split("=")
11
+ if len(sp) == 2:
12
+ directives[sp[0].strip()] = sp[1].strip()
13
+ return media_type, directives
14
+
15
+
16
+ def generate_preview(
17
+ raw_data: bytes, content_type: str, content_encoding: str
18
+ ) -> Dict[str, Union[str, bool]]:
19
+ body: Dict[str, Union[str, bool]] = {}
20
+
21
+ body["content_type"] = content_type
22
+
23
+ if content_encoding.lower() == "br":
24
+ try:
25
+ import brotli # type: ignore
26
+
27
+ raw_data = brotli.decompress(raw_data)
28
+ except Exception:
29
+ # if there is no brotli library available to decompress the data we keep the compressed data
30
+ pass
31
+ elif content_encoding.lower() == "gzip":
32
+ try:
33
+ import zlib
34
+
35
+ raw_data = zlib.decompressobj(16 + zlib.MAX_WBITS).decompress(raw_data)
36
+ except Exception:
37
+ pass
38
+ # TODO deflate
39
+
40
+ if "image/" in content_type.lower():
41
+ body["image"] = True
42
+ else:
43
+ if isinstance(raw_data, str):
44
+ body["text"] = raw_data
45
+ elif isinstance(raw_data, bytes):
46
+ try:
47
+ body["text"] = raw_data.decode(
48
+ parse_content_type(content_type)[1].get("charset", "utf-8")
49
+ )
50
+ except Exception:
51
+ pass
52
+
53
+ return body
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ function update_filter_url() {
4
+ var sheet = document.getElementById("filter").sheet;
5
+
6
+ while (sheet.cssRules.length > 0) {
7
+ sheet.deleteRule(0);
8
+ }
9
+
10
+ var value = document.getElementById("filter-url").value;
11
+
12
+ if (value == "") {
13
+ // if there is no filter, all rows are visible
14
+ sheet.insertRule("[data-filter-url] {display: table-row;}");
15
+ sheet.insertRule(".initiator-header {display: table-row-group;}");
16
+ } else {
17
+ // if there is a filter, only the requests that match the filter are visible
18
+ sheet.insertRule("[data-filter-url*='" + value + "'] {display: table-row;}");
19
+ if (CSS.supports("selector(:has(*))")) {
20
+ // an initiator row is visible only if it contains at least one visible request
21
+ sheet.insertRule(".initiator-header:has([data-filter-url*='" + value + "']) {display: table-row-group;}");
22
+ // if there is a filter and no request visible, the filter icon is red
23
+ sheet.insertRule(".requests-table:not(:has([data-filter-url*='" + value + "'])):has(tbody) .icon-filter {filter: grayscale(0%) !important;}");
24
+ } else {
25
+ // in case :has is not supported, the initiator rows are always visible
26
+ sheet.insertRule(".initiator-header {display: table-row-group;}");
27
+ }
28
+ }
29
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" viewBox="0 0 512 410.73"><path fill="red" stroke="black" fill-rule="nonzero" d="M335.62 410.73H164.96V239.89L13.31 59.96C7.33 52.52 3.19 44.79 1.29 37.65c-1.79-6.72-1.76-13.28.34-19.1 2.3-6.44 6.92-11.63 13.91-14.9C20.35 1.41 26.3.13 33.4.1L472.7.04c7.93-.29 14.95.96 20.74 3.44 7.02 2.97 12.28 7.87 15.44 14.17 3.05 6.1 3.93 13.27 2.34 21.06-1.5 7.24-5.17 15.11-11.32 23.16l-151.94 178.1v170.76h-12.34zm95.61-347.71-69.16 81.05-18.67-16.01 69.16-81.05 18.67 16.01zm-84.8 99.39-24.45 28.66-18.68-16.01 24.45-28.66 18.68 16.01zM189.64 386.06h133.64V235.48l3-8L480.45 46.79c3.77-4.97 5.94-9.39 6.7-13.04.45-2.2.35-3.95-.24-5.12-.49-.97-1.58-1.87-3.19-2.55-2.53-1.13-6.06-1.64-10.44-1.42l-439.84.06c-3.33-.05-5.83.41-7.5 1.18-.68.32-1.09.65-1.18.92-.32.91-.2 2.48.33 4.46 1.05 3.96 3.61 8.57 7.38 13.28L186.7 227.59l2.94 7.89v150.58z"/></svg>
@@ -115,7 +115,7 @@
115
115
  <th class="method" title="method"></th>
116
116
  <th class="url">
117
117
  url
118
- <img class="icon" src="static/icons/filter-outline-icon.svg-+-$**HTTPDBG_VERSION**$"
118
+ <img class="icon icon-filter" src="static/icons/filter-outline-icon.svg-+-$**HTTPDBG_VERSION**$"
119
119
  alt="filter for url" />
120
120
  <label for="filter-url" class="visuallyhidden">
121
121
  filter for url
@@ -128,7 +128,7 @@
128
128
  </thead>
129
129
 
130
130
  <script id="template_initiator" type="x-tmpl-mustache">
131
- <tbody id="initiator-{{initiator.id}}" name="initiator">
131
+ <tbody id="initiator-{{initiator.id}}" name="initiator" class="initiator-header">
132
132
  <tr class="initiator">
133
133
  <td colspan="4" class="initiator-label" title="{{initiator.long_label}}">
134
134
  {{initiator.short_label}}
@@ -127,6 +127,12 @@ function fill_content(request_id, name) {
127
127
 
128
128
  if (request.body && request.body.text) {
129
129
  request.body.raw_text = "global.requests['" + request_id + "'].data.request.body.text";
130
+
131
+ const parsed_text = parse_raw_text(request.body.text, request.body.content_type);
132
+ if (parsed_text) {
133
+ request.body.parsed = parsed_text;
134
+ }
135
+
130
136
  if (request.body.parsed) {
131
137
  request.body.parsed_text = "global.requests['" + request_id + "'].data.request.body.parsed";
132
138
  }
@@ -140,6 +146,12 @@ function fill_content(request_id, name) {
140
146
 
141
147
  if (response.body && response.body.text) {
142
148
  response.body.raw_text = "global.requests['" + request_id + "'].data.response.body.text";
149
+
150
+ const parsed_text = parse_raw_text(response.body.text, response.body.content_type);
151
+ if (parsed_text) {
152
+ response.body.parsed = parsed_text;
153
+ }
154
+
143
155
  if (response.body.parsed) {
144
156
  response.body.parsed_text = "global.requests['" + request_id + "'].data.response.body.parsed";
145
157
  }
@@ -314,7 +326,7 @@ function select_next_request() {
314
326
 
315
327
  if (request == undefined) {
316
328
  // maybe there are some requests under another initiator
317
- var next_initiator = document.querySelector(".active-row").parentElement.nextElementSibling;
329
+ var next_initiator = document.querySelector(".active-row").parentElement.nextElementSibling;
318
330
 
319
331
  if (next_initiator != undefined) {
320
332
  request = next_initiator.querySelector(".request");
@@ -324,4 +336,34 @@ function select_next_request() {
324
336
  if (request != undefined) {
325
337
  request.click();
326
338
  }
339
+ }
340
+
341
+ function parse_raw_text(raw_text, content_type) {
342
+ var parsed_text="";
343
+
344
+ if (content_type.toLowerCase().includes("json")) {
345
+ try {
346
+ parsed_text = JSON.stringify(JSON.parse(raw_text), null, " ");
347
+ } catch {
348
+ return;
349
+ }
350
+ } else if (content_type.toLowerCase().includes("x-www-form-urlencoded")) {
351
+ try {
352
+ var params = new URLSearchParams(raw_text);
353
+
354
+ for (const key of params.keys()) {
355
+ params.getAll(key).forEach((value) => {
356
+ try {
357
+ parsed_text += key + ": " + JSON.stringify(JSON.parse(value), null, " ") + "\n";
358
+ } catch {
359
+ parsed_text += key + ": " + value + "\n";
360
+ }
361
+ });
362
+ }
363
+ } catch {
364
+ return;
365
+ }
366
+ }
367
+
368
+ return parsed_text;
327
369
  }
@@ -70,6 +70,10 @@
70
70
  padding: 6px !important;
71
71
  }
72
72
 
73
+ .initiator-header {
74
+ display: none;
75
+ }
76
+
73
77
  .request {
74
78
  display: none;
75
79
  }
@@ -100,4 +104,8 @@
100
104
  width: 50%;
101
105
  border-width: 0px;
102
106
  padding: 1px 2px;
107
+ }
108
+
109
+ .icon-filter {
110
+ filter: grayscale(100%);
103
111
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: httpdbg
3
- Version: 0.13.2
3
+ Version: 0.13.4
4
4
  Summary: A very simple tool to debug HTTP(S) client requests
5
5
  Author-email: cle-b <cle@tictac.pm>
6
6
  License: Apache-2.0
@@ -0,0 +1,56 @@
1
+ # -*- coding: utf-8 -*-
2
+ import pytest
3
+
4
+ from httpdbg.preview import generate_preview
5
+
6
+
7
+ @pytest.mark.preview
8
+ def test_preview_unknown_type_text():
9
+ body = generate_preview("a text", "unknown/type", "")
10
+ assert body == {"text": "a text", "content_type": "unknown/type"}
11
+
12
+
13
+ @pytest.mark.preview
14
+ def test_preview_unknown_type_bytes():
15
+ body = generate_preview(b"a text", "unknown/type", "")
16
+ assert body == {"text": "a text", "content_type": "unknown/type"}
17
+
18
+
19
+ @pytest.mark.preview
20
+ @pytest.mark.parametrize("content_type", ["text/json", "application/json", "text", ""])
21
+ def test_preview_text(content_type):
22
+ raw_data = '{"a": "1", "b": {"c": 2} }'
23
+ body = generate_preview(raw_data, content_type, "")
24
+
25
+ assert body == {
26
+ "text": raw_data,
27
+ "content_type": content_type,
28
+ }
29
+
30
+
31
+ @pytest.mark.preview
32
+ def test_preview_image():
33
+ body = generate_preview(None, "image/png", "")
34
+
35
+ assert body == {
36
+ "image": True,
37
+ "content_type": "image/png",
38
+ }
39
+
40
+
41
+ def test_preview_application_no_content_type_text():
42
+ body = generate_preview("just text", "", "")
43
+
44
+ assert body == {
45
+ "text": "just text",
46
+ "content_type": "",
47
+ }
48
+
49
+
50
+ def test_preview_application_no_content_type_bytes():
51
+ body = generate_preview("just éà bytes".encode("utf-8"), "", "")
52
+
53
+ assert body == {
54
+ "text": "just éà bytes",
55
+ "content_type": "",
56
+ }
@@ -1,88 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- import json
3
- import urllib
4
- from typing import Tuple, Dict, Union
5
- from xml.dom import minidom
6
-
7
-
8
- def parse_content_type(content_type: str) -> Tuple[str, Dict[str, str]]:
9
- s = content_type.split(";")
10
- media_type = s[0]
11
- directives = {}
12
- for directive in s[1:]:
13
- sp = directive.split("=")
14
- if len(sp) == 2:
15
- directives[sp[0].strip()] = sp[1].strip()
16
- return media_type, directives
17
-
18
-
19
- def generate_preview(
20
- raw_data: bytes, content_type: str, content_encoding: str
21
- ) -> Dict[str, Union[str, bool]]:
22
- body: Dict[str, Union[str, bool]] = {}
23
-
24
- if content_encoding.lower() == "br":
25
- try:
26
- import brotli # type: ignore
27
-
28
- raw_data = brotli.decompress(raw_data)
29
- except Exception:
30
- # if there is no brotli library available to decompress the data we keep the compressed data
31
- pass
32
- elif content_encoding.lower() == "gzip":
33
- try:
34
- import zlib
35
-
36
- raw_data = zlib.decompressobj(16 + zlib.MAX_WBITS).decompress(raw_data)
37
- except Exception:
38
- pass
39
- # TODO deflate
40
-
41
- if "image/" in content_type.lower():
42
- body["image"] = True
43
- else:
44
- if isinstance(raw_data, str):
45
- body["text"] = raw_data
46
- elif isinstance(raw_data, bytes):
47
- try:
48
- body["text"] = raw_data.decode(
49
- parse_content_type(content_type)[1].get("charset", "utf-8")
50
- )
51
- except Exception:
52
- pass
53
-
54
- if body.get("text"):
55
- if isinstance(body["text"], str):
56
- # json
57
- try:
58
- body["parsed"] = json.dumps(
59
- json.loads(body["text"]), sort_keys=True, indent=4
60
- )
61
- except Exception:
62
- # xml, ...
63
- try:
64
- lines = minidom.parseString(body["text"]).toprettyxml(
65
- indent=" "
66
- )
67
- body["parsed"] = "\n".join(
68
- [line for line in lines.split("\n") if line.strip() != ""]
69
- )
70
- except Exception:
71
- # query string
72
- try:
73
- if (
74
- parse_content_type(content_type)[0]
75
- == "application/x-www-form-urlencoded"
76
- ):
77
- qs = []
78
- for key, value in urllib.parse.parse_qsl(
79
- body["text"], strict_parsing=True
80
- ):
81
- if value:
82
- qs.append(f"{key}={value}")
83
- if qs:
84
- body["parsed"] = "\n\n".join(qs)
85
- except Exception:
86
- pass
87
-
88
- return body
@@ -1,18 +0,0 @@
1
- "use strict";
2
-
3
- function update_filter_url() {
4
- var sheet = document.getElementById("filter").sheet;
5
-
6
- while (sheet.cssRules.length > 0) {
7
- sheet.deleteRule(0);
8
- }
9
-
10
- var value = document.getElementById("filter-url").value;
11
- if (value == "") {
12
- new_rule = '[data-filter-url] {display: table-row;}'
13
- } else {
14
- var new_rule = '[data-filter-url*="' + value + '"] {display: table-row;}'
15
- }
16
-
17
- sheet.insertRule(new_rule);
18
- }
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" viewBox="0 0 512 410.73"><path fill-rule="nonzero" d="M335.62 410.73H164.96V239.89L13.31 59.96C7.33 52.52 3.19 44.79 1.29 37.65c-1.79-6.72-1.76-13.28.34-19.1 2.3-6.44 6.92-11.63 13.91-14.9C20.35 1.41 26.3.13 33.4.1L472.7.04c7.93-.29 14.95.96 20.74 3.44 7.02 2.97 12.28 7.87 15.44 14.17 3.05 6.1 3.93 13.27 2.34 21.06-1.5 7.24-5.17 15.11-11.32 23.16l-151.94 178.1v170.76h-12.34zm95.61-347.71-69.16 81.05-18.67-16.01 69.16-81.05 18.67 16.01zm-84.8 99.39-24.45 28.66-18.68-16.01 24.45-28.66 18.68 16.01zM189.64 386.06h133.64V235.48l3-8L480.45 46.79c3.77-4.97 5.94-9.39 6.7-13.04.45-2.2.35-3.95-.24-5.12-.49-.97-1.58-1.87-3.19-2.55-2.53-1.13-6.06-1.64-10.44-1.42l-439.84.06c-3.33-.05-5.83.41-7.5 1.18-.68.32-1.09.65-1.18.92-.32.91-.2 2.48.33 4.46 1.05 3.96 3.61 8.57 7.38 13.28L186.7 227.59l2.94 7.89v150.58z"/></svg>
@@ -1,96 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- import pytest
3
-
4
- from httpdbg.preview import generate_preview
5
-
6
-
7
- @pytest.mark.preview
8
- def test_preview_unknown_type_text():
9
- body = generate_preview("a text", "unknown/type", "")
10
- assert body == {"text": "a text"}
11
-
12
-
13
- @pytest.mark.preview
14
- def test_preview_unknown_type_bytes():
15
- body = generate_preview(b"a text", "unknown/type", "")
16
- assert body == {"text": "a text"}
17
-
18
-
19
- @pytest.mark.preview
20
- @pytest.mark.parametrize(
21
- "content_type",
22
- ["text/html", "application/xhtml+xml", "application/xml", "text", ""],
23
- )
24
- def test_preview_xml(content_type):
25
- raw_data = "<html><head><title>:-)</title></head><body>empty</body></html>"
26
- body = generate_preview(raw_data, content_type, "")
27
- parsed = '<?xml version="1.0" ?>\n<html>\n <head>\n <title>:-)</title>\n </head>\n <body>empty</body>\n</html>'
28
-
29
- assert body == {
30
- "text": raw_data,
31
- "parsed": parsed,
32
- }
33
-
34
-
35
- @pytest.mark.preview
36
- @pytest.mark.parametrize("content_type", ["text/json", "application/json", "text", ""])
37
- def test_preview_json(content_type):
38
- raw_data = '{"a": "1", "b": {"c": 2} }'
39
- body = generate_preview(raw_data, "application/json", "")
40
- parsed = '{\n "a": "1",\n "b": {\n "c": 2\n }\n}'
41
-
42
- assert body == {
43
- "text": raw_data,
44
- "parsed": parsed,
45
- }
46
-
47
-
48
- @pytest.mark.preview
49
- def test_preview_query_string():
50
- raw_data = "a=1&b=2&c=%7B%27er%27%3A+43434%7D"
51
- body = generate_preview(
52
- raw_data,
53
- "application/x-www-form-urlencoded",
54
- "",
55
- )
56
- parsed = "a=1\n\nb=2\n\nc={'er': 43434}"
57
-
58
- assert body == {
59
- "text": raw_data,
60
- "parsed": parsed,
61
- }
62
-
63
-
64
- @pytest.mark.preview
65
- def test_preview_query_string_not_urlencoded_mimetype():
66
- raw_data = "a=1&b=2&c=%7B%27er%27%3A+43434%7D"
67
- body = generate_preview(raw_data, "test/plain", "")
68
-
69
- assert body == {
70
- "text": raw_data,
71
- }
72
-
73
-
74
- @pytest.mark.preview
75
- def test_preview_image():
76
- body = generate_preview(None, "image/png", "")
77
-
78
- assert body == {
79
- "image": True,
80
- }
81
-
82
-
83
- def test_preview_application_no_content_type_text():
84
- body = generate_preview("just text", "", "")
85
-
86
- assert body == {
87
- "text": "just text",
88
- }
89
-
90
-
91
- def test_preview_application_no_content_type_bytes():
92
- body = generate_preview("just éà bytes".encode("utf-8"), "", "")
93
-
94
- assert body == {
95
- "text": "just éà bytes",
96
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes