Files
curl-converter-cli/curlconverter/parser.py
7000pctAUTO 13968ae8ad
Some checks failed
CI / test (push) Has been cancelled
Fix CI issues: add workflow file and fix lint errors
2026-03-22 10:53:54 +00:00

137 lines
3.7 KiB
Python

{"""Parser module for curl commands."""
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class ParsedCurl:
"""Represents a parsed curl command."""
url: str = ""
method: str = "GET"
headers: dict = field(default_factory=dict)
data: Optional[str] = None
auth: Optional[tuple] = None
cookies: Optional[str] = None
user_agent: Optional[str] = None
def tokenize_command(cmd: str) -> list:
"""Tokenize a curl command into arguments."""
tokens = []
current = ""
in_single_quote = False
in_double_quote = False
escape_next = False
for char in cmd:
if escape_next:
current += char
escape_next = False
continue
if char == '\\' and not in_single_quote:
escape_next = True
continue
if char == "'" and not in_double_quote:
in_single_quote = not in_single_quote
current += char
continue
if char == '"' and not in_single_quote:
in_double_quote = not in_double_quote
current += char
continue
if char == ' ' and not in_single_quote and not in_double_quote:
if current:
tokens.append(current)
current = ""
continue
current += char
if current:
tokens.append(current)
return tokens
def parse_curl(command: str) -> ParsedCurl:
"""Parse a curl command string into a ParsedCurl object."""
if not command:
raise ValueError("Empty curl command")
command = command.strip()
if command.startswith("curl "):
command = command[5:]
tokens = tokenize_command(command)
if not tokens:
raise ValueError("No URL found in curl command")
parsed = ParsedCurl()
i = 0
while i < len(tokens):
token = tokens[i]
if not token.startswith("-"):
if not parsed.url:
parsed.url = token
i += 1
continue
if token in ("-X", "--request"):
if i + 1 < len(tokens):
parsed.method = tokens[i + 1].upper()
i += 2
continue
if token in ("-H", "--header"):
if i + 1 < len(tokens):
header = tokens[i + 1]
if ":" in header:
key, value = header.split(":", 1)
parsed.headers[key.strip()] = value.strip()
i += 2
continue
if token in ("-d", "--data", "--data-raw", "--data-binary"):
if i + 1 < len(tokens):
parsed.data = tokens[i + 1]
if parsed.method == "GET":
parsed.method = "POST"
i += 2
continue
if token in ("-u", "--user"):
if i + 1 < len(tokens):
auth = tokens[i + 1]
if ":" in auth:
parsed.auth = auth.split(":", 1)
else:
parsed.auth = (auth, "")
i += 2
continue
if token in ("-b", "--cookie"):
if i + 1 < len(tokens):
parsed.cookies = tokens[i + 1]
i += 2
continue
if token in ("-A", "--user-agent"):
if i + 1 < len(tokens):
parsed.user_agent = tokens[i + 1]
i += 2
continue
i += 1
if not parsed.url:
raise ValueError("No URL found in curl command")
return parsed