{"""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