Remove duplicate files: root-level copies and subdirectory pyproject.toml
Some checks failed
CI / test (push) Failing after 9s
Some checks failed
CI / test (push) Failing after 9s
This commit is contained in:
10
__init__.py
10
__init__.py
@@ -1,10 +0,0 @@
|
|||||||
"""
|
|
||||||
__init__.py for curl-to-code-converter package.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from .parser import CurlParser, ParsedCurl
|
|
||||||
from .generators import CodeGenerators
|
|
||||||
from .__main__ import main as run
|
|
||||||
|
|
||||||
__version__ = "1.0.0"
|
|
||||||
__all__ = ["CurlParser", "ParsedCurl", "CodeGenerators", "run"]
|
|
||||||
75
__main__.py
75
__main__.py
@@ -1,75 +0,0 @@
|
|||||||
"""
|
|
||||||
cURL to Code Converter
|
|
||||||
|
|
||||||
A CLI tool that converts cURL commands into code snippets in various programming languages.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import sys
|
|
||||||
from curl_to_code_converter.parser import CurlParser
|
|
||||||
from curl_to_code_converter.generators import CodeGenerators
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="Convert cURL commands to code snippets in various languages",
|
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
||||||
epilog="""
|
|
||||||
Examples:
|
|
||||||
%(prog)s 'curl https://api.example.com/data'
|
|
||||||
%(prog)s 'curl -X POST https://api.example.com -d "{\"key\":\"value\"}"' -l python
|
|
||||||
%(prog)s 'curl -H "Authorization: Bearer token" https://api.example.com' -l javascript
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"curl_command",
|
|
||||||
help="The cURL command to convert"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-l", "--language",
|
|
||||||
choices=["python", "javascript", "go", "ruby", "php", "java"],
|
|
||||||
default="python",
|
|
||||||
help="Target programming language (default: python)"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-o", "--output",
|
|
||||||
help="Output file path (optional)"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-v", "--verbose",
|
|
||||||
action="store_true",
|
|
||||||
help="Show verbose output"
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
try:
|
|
||||||
curl_parser = CurlParser(args.curl_command)
|
|
||||||
parsed_data = curl_parser.parse()
|
|
||||||
|
|
||||||
if args.verbose:
|
|
||||||
print(f"Parsed cURL command:")
|
|
||||||
print(f" URL: {parsed_data.url}")
|
|
||||||
print(f" Method: {parsed_data.method}")
|
|
||||||
print(f" Headers: {parsed_data.headers}")
|
|
||||||
print(f" Data: {parsed_data.data}")
|
|
||||||
print(f" Auth: {parsed_data.auth}")
|
|
||||||
print()
|
|
||||||
|
|
||||||
generators = CodeGenerators()
|
|
||||||
code = generators.generate(parsed_data, args.language)
|
|
||||||
|
|
||||||
if args.output:
|
|
||||||
with open(args.output, 'w') as f:
|
|
||||||
f.write(code)
|
|
||||||
print(f"Code written to {args.output}")
|
|
||||||
else:
|
|
||||||
print(code)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error: {e}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
[build-system]
|
|
||||||
requires = ["setuptools>=61.0"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|
||||||
[project]
|
|
||||||
name = "curl-to-code-converter"
|
|
||||||
version = "1.0.0"
|
|
||||||
description = "A CLI tool that converts cURL commands into code snippets in various programming languages"
|
|
||||||
readme = "README.md"
|
|
||||||
license = {text = "MIT"}
|
|
||||||
requires-python = ">=3.7"
|
|
||||||
classifiers = [
|
|
||||||
"Development Status :: 4 - Beta",
|
|
||||||
"Intended Audience :: Developers",
|
|
||||||
"License :: OSI Approved :: MIT License",
|
|
||||||
"Programming Language :: Python :: 3",
|
|
||||||
"Programming Language :: Python :: 3.7",
|
|
||||||
"Programming Language :: Python :: 3.8",
|
|
||||||
"Programming Language :: Python :: 3.9",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
"Programming Language :: Python :: 3.11",
|
|
||||||
]
|
|
||||||
keywords = ["curl", "converter", "cli", "code-generation", "http"]
|
|
||||||
|
|
||||||
[project.scripts]
|
|
||||||
curl-to-code = "curl_to_code_converter.__main__:main"
|
|
||||||
|
|
||||||
[project.urls]
|
|
||||||
Homepage = "https://github.com/example/curl-to-code-converter"
|
|
||||||
|
|
||||||
[project.optional-dependencies]
|
|
||||||
dev = [
|
|
||||||
"pytest>=7.0.0",
|
|
||||||
"ruff>=0.1.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
|
||||||
where = ["*"]
|
|
||||||
include = ["curl_to_code_converter*"]
|
|
||||||
302
generators.py
302
generators.py
@@ -1,302 +0,0 @@
|
|||||||
"""
|
|
||||||
Code generators for different programming languages.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import json
|
|
||||||
from typing import Optional
|
|
||||||
from .parser import ParsedCurl
|
|
||||||
|
|
||||||
|
|
||||||
class CodeGenerators:
|
|
||||||
def generate(self, parsed: ParsedCurl, language: str) -> str:
|
|
||||||
"""Generate code snippet for the given language."""
|
|
||||||
generators = {
|
|
||||||
'python': self._generate_python,
|
|
||||||
'javascript': self._generate_javascript,
|
|
||||||
'go': self._generate_go,
|
|
||||||
'ruby': self._generate_ruby,
|
|
||||||
'php': self._generate_php,
|
|
||||||
'java': self._generate_java,
|
|
||||||
}
|
|
||||||
|
|
||||||
generator = generators.get(language)
|
|
||||||
if not generator:
|
|
||||||
raise ValueError(f"Unsupported language: {language}")
|
|
||||||
|
|
||||||
return generator(parsed)
|
|
||||||
|
|
||||||
def _generate_python(self, parsed: ParsedCurl) -> str:
|
|
||||||
"""Generate Python code using requests library."""
|
|
||||||
code = ["import requests\n"]
|
|
||||||
|
|
||||||
if parsed.auth:
|
|
||||||
code.append(f"response = requests.{parsed.method.lower()}(")
|
|
||||||
else:
|
|
||||||
code.append(f"response = requests.{parsed.method.lower()}(")
|
|
||||||
|
|
||||||
code.append(f" '{parsed.url}'\n")
|
|
||||||
|
|
||||||
if parsed.headers:
|
|
||||||
code.append(f" headers={json.dumps(parsed.headers, indent=8)}\n")
|
|
||||||
|
|
||||||
if parsed.data:
|
|
||||||
if parsed.content_type and 'application/json' in parsed.content_type:
|
|
||||||
try:
|
|
||||||
json_data = json.loads(parsed.data)
|
|
||||||
code.append(f" json={json.dumps(json_data, indent=8)}\n")
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
code.append(f" data='{parsed.data}'\n")
|
|
||||||
else:
|
|
||||||
data_str = parsed.data.replace("'", "\\'")
|
|
||||||
code.append(f" data='{data_str}'\n")
|
|
||||||
|
|
||||||
if parsed.auth:
|
|
||||||
code.append(f" auth={parsed.auth}\n")
|
|
||||||
|
|
||||||
code.append(")\n")
|
|
||||||
code.append(f"\nprint(response.status_code)")
|
|
||||||
code.append(f"\nprint(response.text)")
|
|
||||||
|
|
||||||
return ''.join(code)
|
|
||||||
|
|
||||||
def _generate_javascript(self, parsed: ParsedCurl) -> str:
|
|
||||||
"""Generate JavaScript code using fetch API."""
|
|
||||||
code = ["const fetchData = async () => {\n"]
|
|
||||||
code.append(" try {\n")
|
|
||||||
|
|
||||||
options_parts = [f"method: '{parsed.method}'"]
|
|
||||||
|
|
||||||
if parsed.headers:
|
|
||||||
options_parts.append(f"headers: {json.dumps(parsed.headers)}")
|
|
||||||
|
|
||||||
if parsed.data:
|
|
||||||
if parsed.content_type and 'application/json' in parsed.content_type:
|
|
||||||
options_parts.append(f"body: JSON.stringify({parsed.data})")
|
|
||||||
else:
|
|
||||||
data_str = parsed.data.replace("'", "\\'")
|
|
||||||
options_parts.append(f"body: '{data_str}'")
|
|
||||||
|
|
||||||
code.append(" const options = {\n")
|
|
||||||
for i, part in enumerate(options_parts):
|
|
||||||
if i > 0:
|
|
||||||
code.append(",\n")
|
|
||||||
code.append(f" {part}")
|
|
||||||
code.append("\n };\n\n")
|
|
||||||
|
|
||||||
code.append(f" const response = await fetch('{parsed.url}', options);\n")
|
|
||||||
code.append(" const data = await response.json();\n")
|
|
||||||
code.append(" console.log(data);\n")
|
|
||||||
code.append(" return data;\n")
|
|
||||||
code.append(" } catch (error) {\n")
|
|
||||||
code.append(" console.error('Error:', error);\n")
|
|
||||||
code.append(" }\n")
|
|
||||||
code.append("}\n\n")
|
|
||||||
code.append("fetchData();")
|
|
||||||
|
|
||||||
return ''.join(code)
|
|
||||||
|
|
||||||
def _generate_go(self, parsed: ParsedCurl) -> str:
|
|
||||||
"""Generate Go code using net/http package."""
|
|
||||||
code = ["package main\n\n"]
|
|
||||||
code.append("import (\n")
|
|
||||||
code.append(' "bytes"\n')
|
|
||||||
code.append(' "encoding/json"\n')
|
|
||||||
code.append(' "fmt"\n')
|
|
||||||
code.append(' "io/ioutil"\n')
|
|
||||||
code.append(' "net/http"\n')
|
|
||||||
code.append(')\n\n')
|
|
||||||
|
|
||||||
code.append("func main() {\n")
|
|
||||||
code.append(f" url := \"{parsed.url}\"\n\n")
|
|
||||||
|
|
||||||
if parsed.method == "GET":
|
|
||||||
code.append(" req, err := http.NewRequest(\"GET\", url, nil)\n")
|
|
||||||
else:
|
|
||||||
data_str = parsed.data if parsed.data else ""
|
|
||||||
code.append(f" jsonData := `{data_str}`\n")
|
|
||||||
code.append(" req, err := http.NewRequest(\"POST\", url, bytes.NewBuffer([]byte(jsonData)))\n")
|
|
||||||
|
|
||||||
code.append(" if err != nil {\n")
|
|
||||||
code.append(" panic(err)\n")
|
|
||||||
code.append(" }\n\n")
|
|
||||||
|
|
||||||
if parsed.headers:
|
|
||||||
for key, value in parsed.headers.items():
|
|
||||||
code.append(f' req.Header.Set(\"{key}\", \"{value}\")\n')
|
|
||||||
code.append("\n")
|
|
||||||
|
|
||||||
if parsed.auth:
|
|
||||||
code.append(f' req.SetBasicAuth(\"{parsed.auth[0]}\", \"{parsed.auth[1]}\")\n\n')
|
|
||||||
|
|
||||||
code.append(" client := &http.Client{}\n")
|
|
||||||
code.append(" resp, err := client.Do(req)\n")
|
|
||||||
code.append(" if err != nil {\n")
|
|
||||||
code.append(" panic(err)\n")
|
|
||||||
code.append(" }\n")
|
|
||||||
code.append(" defer resp.Body.Close()\n\n")
|
|
||||||
|
|
||||||
code.append(" body, err := ioutil.ReadAll(resp.Body)\n")
|
|
||||||
code.append(" if err != nil {\n")
|
|
||||||
code.append(" panic(err)\n")
|
|
||||||
code.append(" }\n\n")
|
|
||||||
|
|
||||||
code.append(" fmt.Println(string(body))\n")
|
|
||||||
code.append("}\n")
|
|
||||||
|
|
||||||
return ''.join(code)
|
|
||||||
|
|
||||||
def _generate_ruby(self, parsed: ParsedCurl) -> str:
|
|
||||||
"""Generate Ruby code using Net::HTTP."""
|
|
||||||
code = ["require 'net/http'\n"]
|
|
||||||
code.append("require 'uri'\n")
|
|
||||||
code.append("require 'json'\n\n")
|
|
||||||
|
|
||||||
code.append(f"uri = URI.parse(\"{parsed.url}\")\n\n")
|
|
||||||
|
|
||||||
code.append("http = Net::HTTP.new(uri.host, uri.port)\n")
|
|
||||||
code.append("http.use_ssl = true if uri.scheme == 'https'\n\n")
|
|
||||||
|
|
||||||
if parsed.method == "GET":
|
|
||||||
code.append("request = Net::HTTP::Get.new(uri)\n")
|
|
||||||
elif parsed.method == "POST":
|
|
||||||
code.append("request = Net::HTTP::Post.new(uri)\n")
|
|
||||||
elif parsed.method == "PUT":
|
|
||||||
code.append("request = Net::HTTP::Put.new(uri)\n")
|
|
||||||
elif parsed.method == "DELETE":
|
|
||||||
code.append("request = Net::HTTP::Delete.new(uri)\n")
|
|
||||||
else:
|
|
||||||
code.append(f"request = Net::HTTP::#{parsed.method}.new(uri)\n")
|
|
||||||
|
|
||||||
for key, value in parsed.headers.items():
|
|
||||||
code.append(f'request[\"{key}\"] = \"{value}\"\n')
|
|
||||||
|
|
||||||
if parsed.data:
|
|
||||||
if parsed.content_type and 'application/json' in parsed.content_type:
|
|
||||||
code.append(f"request.body = {parsed.data}\n")
|
|
||||||
else:
|
|
||||||
data_str = parsed.data.replace('"', '\\"')
|
|
||||||
code.append(f"request.body = \"{data_str}\"\n")
|
|
||||||
|
|
||||||
if parsed.auth:
|
|
||||||
code.append(f'request.basic_auth \"{parsed.auth[0]}\", \"{parsed.auth[1]}\"\n')
|
|
||||||
|
|
||||||
code.append("\nresponse = http.request(request)\n")
|
|
||||||
code.append("puts response.code\n")
|
|
||||||
code.append("puts response.body\n")
|
|
||||||
|
|
||||||
return ''.join(code)
|
|
||||||
|
|
||||||
def _generate_php(self, parsed: ParsedCurl) -> str:
|
|
||||||
"""Generate PHP code using cURL."""
|
|
||||||
code = ["<?php\n\n"]
|
|
||||||
code.append("$url = \"" + parsed.url + ";\n\n")
|
|
||||||
|
|
||||||
code.append("$ch = curl_init();\n\n")
|
|
||||||
|
|
||||||
code.append("curl_setopt($ch, CURLOPT_URL, $url);\n")
|
|
||||||
code.append(f"curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n")
|
|
||||||
|
|
||||||
if parsed.method == "POST":
|
|
||||||
code.append("curl_setopt($ch, CURLOPT_POST, true);\n")
|
|
||||||
if parsed.data:
|
|
||||||
data_str = parsed.data.replace('"', '\\"')
|
|
||||||
code.append(f"curl_setopt($ch, CURLOPT_POSTFIELDS, \"{data_str}\");\n")
|
|
||||||
elif parsed.method != "GET":
|
|
||||||
code.append(f"curl_setopt($ch, CURLOPT_CUSTOMREQUEST, \"{parsed.method}\");\n")
|
|
||||||
if parsed.data:
|
|
||||||
data_str = parsed.data.replace('"', '\\"')
|
|
||||||
code.append(f"curl_setopt($ch, CURLOPT_POSTFIELDS, \"{data_str}\");\n")
|
|
||||||
|
|
||||||
code.append("curl_setopt($ch, CURLOPT_HTTPHEADER, [\n")
|
|
||||||
headers_lines = []
|
|
||||||
for key, value in parsed.headers.items():
|
|
||||||
headers_lines.append(f" \"{key}: {value}\"")
|
|
||||||
if headers_lines:
|
|
||||||
code.append(",\n".join(headers_lines) + "\n")
|
|
||||||
code.append("]);\n\n")
|
|
||||||
|
|
||||||
if parsed.auth:
|
|
||||||
code.append(f'curl_setopt($ch, CURLOPT_USERPWD, \"{parsed.auth[0]}:{parsed.auth[1]}\");\n\n')
|
|
||||||
|
|
||||||
code.append("$response = curl_exec($ch);\n\n")
|
|
||||||
|
|
||||||
code.append("if (curl_errno($ch)) {\n")
|
|
||||||
code.append(" echo 'Error:' . curl_error($ch);\n")
|
|
||||||
code.append("}\n\n")
|
|
||||||
|
|
||||||
code.append("curl_close($ch);\n\n")
|
|
||||||
code.append("echo $response;\n")
|
|
||||||
code.append("?>\n")
|
|
||||||
|
|
||||||
return ''.join(code)
|
|
||||||
|
|
||||||
def _generate_java(self, parsed: ParsedCurl) -> str:
|
|
||||||
"""Generate Java code using HttpURLConnection."""
|
|
||||||
code = ["import java.io.*;\n"]
|
|
||||||
code.append("import java.net.*;\n")
|
|
||||||
code.append("import java.nio.charset.StandardCharsets;\n\n")
|
|
||||||
|
|
||||||
code.append("public class ApiClient {\n")
|
|
||||||
code.append(" public static void main(String[] args) {\n")
|
|
||||||
code.append(" try {\n")
|
|
||||||
code.append(f" String url = \"{parsed.url}\";\n\n")
|
|
||||||
|
|
||||||
code.append(" URL obj = new URL(url);\n")
|
|
||||||
code.append(" HttpURLConnection con = (HttpURLConnection) obj.openConnection();\n\n")
|
|
||||||
|
|
||||||
code.append(f" con.setRequestMethod(\"{parsed.method}\");\n\n")
|
|
||||||
|
|
||||||
for key, value in parsed.headers.items():
|
|
||||||
code.append(f' con.setRequestProperty(\"{key}\", \"{value}\");\n')
|
|
||||||
|
|
||||||
if parsed.auth:
|
|
||||||
code.append(f' String auth = \"{parsed.auth[0]}:{parsed.auth[1]}\";\n')
|
|
||||||
code.append(' String encodedAuth = java.util.Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));\n')
|
|
||||||
code.append(' con.setRequestProperty(\"Authorization\", \"Basic \" + encodedAuth);\n')
|
|
||||||
|
|
||||||
if parsed.data:
|
|
||||||
code.append("\n String urlParameters = ")
|
|
||||||
data_str = parsed.data.replace('"', '\\"')
|
|
||||||
code.append(f'"{data_str}";\n')
|
|
||||||
code.append("\n con.setDoOutput(true);\n")
|
|
||||||
code.append(" try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) {\n")
|
|
||||||
code.append(" wr.writeBytes(urlParameters);\n")
|
|
||||||
code.append(" wr.flush();\n")
|
|
||||||
code.append(" }\n")
|
|
||||||
|
|
||||||
code.append("\n int responseCode = con.getResponseCode();\n")
|
|
||||||
code.append(" System.out.println(\"Response Code: \" + responseCode);\n\n")
|
|
||||||
|
|
||||||
code.append(" try (BufferedReader in = new BufferedReader(\n")
|
|
||||||
code.append(" new InputStreamReader(con.getInputStream()))) {\n")
|
|
||||||
code.append(" String inputLine;\n")
|
|
||||||
code.append(" StringBuffer response = new StringBuffer();\n")
|
|
||||||
code.append(" while ((inputLine = in.readLine()) != null) {\n")
|
|
||||||
code.append(" response.append(inputLine);\n")
|
|
||||||
code.append(" }\n")
|
|
||||||
code.append(" System.out.println(response.toString());\n")
|
|
||||||
code.append(" }\n")
|
|
||||||
|
|
||||||
code.append(" } catch (Exception e) {\n")
|
|
||||||
code.append(" e.printStackTrace();\n")
|
|
||||||
code.append(" }\n")
|
|
||||||
code.append(" }\n")
|
|
||||||
code.append("}\n")
|
|
||||||
|
|
||||||
return ''.join(code)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parsed = ParsedCurl(
|
|
||||||
url="https://api.example.com/data",
|
|
||||||
method="POST",
|
|
||||||
headers={"Content-Type": "application/json", "Authorization": "Bearer token"},
|
|
||||||
data='{"key": "value"}',
|
|
||||||
auth=("user", "pass")
|
|
||||||
)
|
|
||||||
gen = CodeGenerators()
|
|
||||||
print("Python:")
|
|
||||||
print(gen._generate_python(parsed))
|
|
||||||
print("\n" + "="*50 + "\n")
|
|
||||||
print("JavaScript:")
|
|
||||||
print(gen._generate_javascript(parsed))
|
|
||||||
188
parser.py
188
parser.py
@@ -1,188 +0,0 @@
|
|||||||
"""
|
|
||||||
cURL command parser module.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import re
|
|
||||||
import shlex
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ParsedCurl:
|
|
||||||
url: str = ""
|
|
||||||
method: str = "GET"
|
|
||||||
headers: dict = field(default_factory=dict)
|
|
||||||
data: Optional[str] = None
|
|
||||||
auth: Optional[tuple] = None
|
|
||||||
content_type: Optional[str] = None
|
|
||||||
insecure: bool = False
|
|
||||||
|
|
||||||
|
|
||||||
class CurlParser:
|
|
||||||
def __init__(self, curl_command: str):
|
|
||||||
self.curl_command = curl_command
|
|
||||||
|
|
||||||
def parse(self) -> ParsedCurl:
|
|
||||||
"""Parse a cURL command and return structured data."""
|
|
||||||
result = ParsedCurl()
|
|
||||||
|
|
||||||
command = self._normalize_command()
|
|
||||||
tokens = self._tokenize(command)
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
while i < len(tokens):
|
|
||||||
token = tokens[i]
|
|
||||||
|
|
||||||
if token == 'curl':
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if token.startswith('-'):
|
|
||||||
if token in ['-X', '--request']:
|
|
||||||
i += 1
|
|
||||||
result.method = tokens[i].upper() if i < len(tokens) else 'GET'
|
|
||||||
elif token in ['-H', '--header']:
|
|
||||||
i += 1
|
|
||||||
header = ""
|
|
||||||
if i < len(tokens):
|
|
||||||
header = tokens[i]
|
|
||||||
if header.endswith(':'):
|
|
||||||
i += 1
|
|
||||||
while i < len(tokens) and not tokens[i].startswith('-'):
|
|
||||||
if '://' in tokens[i]:
|
|
||||||
i -= 1
|
|
||||||
break
|
|
||||||
header += ' ' + tokens[i]
|
|
||||||
i += 1
|
|
||||||
if header:
|
|
||||||
self._parse_header(header, result)
|
|
||||||
continue
|
|
||||||
elif token in ['-d', '--data', '--data-raw', '--data-binary']:
|
|
||||||
i += 1
|
|
||||||
result.data = tokens[i] if i < len(tokens) else ''
|
|
||||||
if not result.method or result.method == 'GET':
|
|
||||||
result.method = 'POST'
|
|
||||||
continue
|
|
||||||
elif token in ['-u', '--user']:
|
|
||||||
i += 1
|
|
||||||
if i < len(tokens):
|
|
||||||
auth = tokens[i]
|
|
||||||
if ':' in auth:
|
|
||||||
parts = auth.split(':', 1)
|
|
||||||
result.auth = (parts[0], parts[1])
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
elif token == '--url':
|
|
||||||
i += 1
|
|
||||||
result.url = tokens[i] if i < len(tokens) else ''
|
|
||||||
continue
|
|
||||||
elif token in ['-b', '--cookie', '--cookie-jar']:
|
|
||||||
i += 1
|
|
||||||
cookie = tokens[i]
|
|
||||||
if '=' in cookie:
|
|
||||||
name, value = cookie.split('=', 1)
|
|
||||||
result.headers['Cookie'] = value
|
|
||||||
continue
|
|
||||||
elif token in ['-A', '--user-agent']:
|
|
||||||
i += 1
|
|
||||||
result.headers['User-Agent'] = tokens[i] if i < len(tokens) else ''
|
|
||||||
continue
|
|
||||||
elif token == '--compressed':
|
|
||||||
result.headers['Accept-Encoding'] = 'gzip, deflate'
|
|
||||||
elif token in ['-k', '--insecure']:
|
|
||||||
result.insecure = True
|
|
||||||
i += 1
|
|
||||||
else:
|
|
||||||
if not result.url:
|
|
||||||
result.url = token
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _normalize_command(self) -> str:
|
|
||||||
"""Normalize the cURL command for parsing."""
|
|
||||||
command = self.curl_command.strip()
|
|
||||||
command = re.sub(r'\\\n', '', command)
|
|
||||||
command = re.sub(r'\s+', ' ', command)
|
|
||||||
return command
|
|
||||||
|
|
||||||
def _tokenize(self, command: str) -> list:
|
|
||||||
"""Tokenize the cURL command."""
|
|
||||||
tokens = []
|
|
||||||
current = ""
|
|
||||||
in_quote = False
|
|
||||||
quote_char = None
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
while i < len(command):
|
|
||||||
char = command[i]
|
|
||||||
|
|
||||||
if char in ['"', "'"] and not in_quote:
|
|
||||||
in_quote = True
|
|
||||||
quote_char = char
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
elif char == quote_char and in_quote:
|
|
||||||
in_quote = False
|
|
||||||
quote_char = None
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if in_quote:
|
|
||||||
if char == '\\' and i + 1 < len(command):
|
|
||||||
current += char
|
|
||||||
current += command[i + 1]
|
|
||||||
i += 2
|
|
||||||
continue
|
|
||||||
elif char == ' ':
|
|
||||||
if current:
|
|
||||||
tokens.append(current)
|
|
||||||
current = ""
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if char == ' ' and not in_quote:
|
|
||||||
if current:
|
|
||||||
tokens.append(current)
|
|
||||||
current = ""
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
current += char
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
if current:
|
|
||||||
tokens.append(current)
|
|
||||||
|
|
||||||
unescaped_tokens = []
|
|
||||||
for token in tokens:
|
|
||||||
token = token.replace('\\:', ':')
|
|
||||||
token = token.replace('\\"', '"')
|
|
||||||
token = token.replace("\\'", "'")
|
|
||||||
token = token.replace('\\n', '\n')
|
|
||||||
unescaped_tokens.append(token)
|
|
||||||
|
|
||||||
return unescaped_tokens
|
|
||||||
|
|
||||||
def _parse_header(self, header: str, result: ParsedCurl):
|
|
||||||
"""Parse a header string and update the result."""
|
|
||||||
if ':' in header:
|
|
||||||
parts = header.split(':', 1)
|
|
||||||
key = parts[0].strip()
|
|
||||||
value = parts[1].strip()
|
|
||||||
result.headers[key] = value
|
|
||||||
|
|
||||||
if key.lower() == 'content-type':
|
|
||||||
result.content_type = value
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import sys
|
|
||||||
parser = CurlParser(' '.join(sys.argv[1:]))
|
|
||||||
result = parser.parse()
|
|
||||||
print(f"URL: {result.url}")
|
|
||||||
print(f"Method: {result.method}")
|
|
||||||
print(f"Headers: {result.headers}")
|
|
||||||
print(f"Data: {result.data}")
|
|
||||||
print(f"Auth: {result.auth}")
|
|
||||||
Reference in New Issue
Block a user