From 790f7df27b6b4a4a701eecf530b66e0f5a53bdb5 Mon Sep 17 00:00:00 2001 From: Ivan Puchalka Date: Thu, 2 May 2024 21:07:58 -0300 Subject: [PATCH] Fix payload string generation --- har2locust/__main__.py | 8 ++ har2locust/locust.jinja2 | 2 +- .../inputs/string-problematic-characters.har | 115 ++++++++++++++++++ tests/outputs/apple-buy-a-mac.py | 4 +- .../outputs/string-problematic-characters.py | 19 +++ 5 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 tests/inputs/string-problematic-characters.har create mode 100644 tests/outputs/string-problematic-characters.py diff --git a/har2locust/__main__.py b/har2locust/__main__.py index d1e056d..a572d64 100644 --- a/har2locust/__main__.py +++ b/har2locust/__main__.py @@ -124,6 +124,14 @@ def render(name: str, values: dict) -> str: return py +@entriesprocessor_with_args +def transform_payload_strings(entries: list[dict], args): + for entry in entries: + request = entry["request"] + if "postData" in request and "text" in request["postData"] and request["fname"] != "rest": + request["postData"]["text"] = ast.unparse(ast.Constant(value=request["postData"]["text"])) + + # Generate a valid identifier (https://docs.python.org/3.8/reference/lexical_analysis.html#identifiers) by replacing # invalid characters with "_". def generate_class_name(file_name: str) -> str: diff --git a/har2locust/locust.jinja2 b/har2locust/locust.jinja2 index 122ad31..87c5a1a 100644 --- a/har2locust/locust.jinja2 +++ b/har2locust/locust.jinja2 @@ -33,7 +33,7 @@ class {{class_name}}(FastHttpUser): {%- endfor %}} {%- endif -%} {%- if request.postData -%} - , data='{{ request.postData.text }}' + , data={{ request.postData.text }} {%- endif -%} {%- for (key, value) in request.extraparams -%} ,{{ key }}={{ value }} diff --git a/tests/inputs/string-problematic-characters.har b/tests/inputs/string-problematic-characters.har new file mode 100644 index 0000000..2a99084 --- /dev/null +++ b/tests/inputs/string-problematic-characters.har @@ -0,0 +1,115 @@ +{ + "log": { + "creator": { + "name": "Advanced REST Client", + "version": "Unknown" + }, + "version": "1.2", + "entries": [ + { + "startedDateTime": "2024-05-01T01:13:50.911Z", + "time": 601, + "cache": { + "afterRequest": null, + "beforeRequest": null, + "comment": "This application does not support caching." + }, + "timings": { + "blocked": 0, + "connect": 42, + "receive": 5, + "send": 1, + "wait": 514, + "dns": 38, + "ssl": 1 + }, + "request": { + "method": "PATCH", + "url": "https://reqres.in/api/users/2", + "httpVersion": "HTTP/1.1", + "headers": [], + "bodySize": 145, + "headersSize": 0, + "cookies": [], + "queryString": [], + "postData": { + "mimeType": null, + "text": "------WebKitFormBoundaryaVpJHMwCHF5PHRS7\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n'\\'\\r\\n\"\\\"\r\n------WebKitFormBoundaryaVpJHMwCHF5PHRS7--\r\n" + } + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { + "name": "Date", + "value": "Wed, 01 May 2024 01:13:51 GMT" + }, + { + "name": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "name": "Content-Length", + "value": "40" + }, + { + "name": "Connection", + "value": "keep-alive" + }, + { + "name": "Report-To", + "value": "{\"group\":\"heroku-nel\",\"max_age\":3600,\"endpoints\":[{\"url\":\"https://nel.heroku.com/reports?ts=1714526031&sid=c4c9725f-1ab0-44d8-820f-430df2718e11&s=5TBzx4koRZlKOSEOrxvEEhkMCohSUw2t1EzIbUtg7WI%3D\"}]}" + }, + { + "name": "Reporting-Endpoints", + "value": "heroku-nel=https://nel.heroku.com/reports?ts=1714526031&sid=c4c9725f-1ab0-44d8-820f-430df2718e11&s=5TBzx4koRZlKOSEOrxvEEhkMCohSUw2t1EzIbUtg7WI%3D" + }, + { + "name": "Nel", + "value": "{\"report_to\":\"heroku-nel\",\"max_age\":3600,\"success_fraction\":0.005,\"failure_fraction\":0.05,\"response_headers\":[\"Via\"]}" + }, + { + "name": "X-Powered-By", + "value": "Express" + }, + { + "name": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "name": "Etag", + "value": "W/\"28-BR3knLS0fufDvS4u4ZiopG530R8\"" + }, + { + "name": "Via", + "value": "1.1 vegur" + }, + { + "name": "CF-Cache-Status", + "value": "DYNAMIC" + }, + { + "name": "Server", + "value": "cloudflare" + }, + { + "name": "CF-RAY", + "value": "87cbe94d3f921ea4-EZE" + } + ], + "headersSize": 820, + "bodySize": 40, + "content": { + "mimeType": "application/json", + "text": "{\"updatedAt\":\"2024-05-01T01:13:51.297Z\"}", + "size": 40, + "encoding": "utf-8" + } + } + } + ] + } +} \ No newline at end of file diff --git a/tests/outputs/apple-buy-a-mac.py b/tests/outputs/apple-buy-a-mac.py index 7794e0e..012f536 100644 --- a/tests/outputs/apple-buy-a-mac.py +++ b/tests/outputs/apple-buy-a-mac.py @@ -1855,7 +1855,7 @@ def t(self): "scnt": "", "x-csrf-token": "", }, - data='{"type":"INFO","title":"AppleAuthDebug","message":"APPLE ID : Launching AppleAuth application.{"data":{"initApp":{"startTime":1400.0300000188872}},"order":["initApp"]}","iframeId":"auth-bbfc2b43-ol01-rowz-a4jz-l79n3zhj","details":"{"pageVisibilityState":"visible"}"}', + data='{"type":"INFO","title":"AppleAuthDebug","message":"APPLE ID : Launching AppleAuth application.{\\"data\\":{\\"initApp\\":{\\"startTime\\":1400.0300000188872}},\\"order\\":[\\"initApp\\"]}","iframeId":"auth-bbfc2b43-ol01-rowz-a4jz-l79n3zhj","details":"{\\"pageVisibilityState\\":\\"visible\\"}"}', catch_response=True, ) as resp: pass @@ -1903,7 +1903,7 @@ def t(self): "scnt": "", "x-csrf-token": "", }, - data='{"type":"INFO","title":"AppleAuthPerf","message":"APPLE ID : TTI {"data":{"initApp":{"startTime":1400.0300000188872},"loadAuthComponent":{"startTime":2087.4300000141375},"startAppToTTI":{"duration":686.1000000208151}},"order":["initApp","loadAuthComponent","startAppToTTI"]}","iframeId":"auth-bbfc2b43-ol01-rowz-a4jz-l79n3zhj","details":"{"pageVisibilityState":"visible"}"}', + data='{"type":"INFO","title":"AppleAuthPerf","message":"APPLE ID : TTI {\\"data\\":{\\"initApp\\":{\\"startTime\\":1400.0300000188872},\\"loadAuthComponent\\":{\\"startTime\\":2087.4300000141375},\\"startAppToTTI\\":{\\"duration\\":686.1000000208151}},\\"order\\":[\\"initApp\\",\\"loadAuthComponent\\",\\"startAppToTTI\\"]}","iframeId":"auth-bbfc2b43-ol01-rowz-a4jz-l79n3zhj","details":"{\\"pageVisibilityState\\":\\"visible\\"}"}', catch_response=True, ) as resp: pass diff --git a/tests/outputs/string-problematic-characters.py b/tests/outputs/string-problematic-characters.py new file mode 100644 index 0000000..bf0f0df --- /dev/null +++ b/tests/outputs/string-problematic-characters.py @@ -0,0 +1,19 @@ +from locust import FastHttpUser, run_single_user, task + + +class string_problematic_characters(FastHttpUser): + host = "https://reqres.in" + + @task + def t(self): + with self.client.request( + "PATCH", + "/api/users/2", + data='------WebKitFormBoundaryaVpJHMwCHF5PHRS7\r\nContent-Disposition: form-data; name="name"\r\n\r\n\'\\\'\\r\\n"\\"\r\n------WebKitFormBoundaryaVpJHMwCHF5PHRS7--\r\n', + catch_response=True, + ) as resp: + pass + + +if __name__ == "__main__": + run_single_user(string_problematic_characters)