Uncurl

  1. import argparse
  2. import json
  3. import re
  4. import shlex
  5. from collections import OrderedDict, namedtuple
  6. from six.moves import http_cookies as Cookie
  7. parser = argparse.ArgumentParser()
  8. parser.add_argument('command')
  9. parser.add_argument('url')
  10. parser.add_argument('-d', '--data')
  11. parser.add_argument('-b', '--data-binary', default=None)
  12. parser.add_argument('-X', default='')
  13. parser.add_argument('-H', '--header', action='append', default=[])
  14. parser.add_argument('--compressed', action='store_true')
  15. parser.add_argument('--insecure', action='store_true')
  16. BASE_INDENT = " " * 4
  17. ParsedContext = namedtuple('ParsedContext', ['method', 'url', 'data', 'headers', 'cookies', 'verify'])
  18. def parse_context(curl_command):
  19. method = "get"
  20. tokens = shlex.split(curl_command)
  21. parsed_args = parser.parse_args(tokens)
  22. post_data = parsed_args.data or parsed_args.data_binary
  23. if post_data:
  24. method = 'post'
  25. if parsed_args.X:
  26. method = parsed_args.X.lower()
  27. cookie_dict = OrderedDict()
  28. quoted_headers = OrderedDict()
  29. for curl_header in parsed_args.header:
  30. if curl_header.startswith(':'):
  31. occurrence = [m.start() for m in re.finditer(':', curl_header)]
  32. header_key, header_value = curl_header[:occurrence[1]], curl_header[occurrence[1] + 1:]
  33. else:
  34. header_key, header_value = curl_header.split(":", 1)
  35. if header_key.lower() == 'cookie':
  36. cookie = Cookie.SimpleCookie(header_value)
  37. for key in cookie:
  38. cookie_dict[key] = cookie[key].value
  39. else:
  40. quoted_headers[header_key] = header_value.strip()
  41. return ParsedContext(
  42. method=method,
  43. url=parsed_args.url,
  44. data=post_data,
  45. headers=quoted_headers,
  46. cookies=cookie_dict,
  47. verify=parsed_args.insecure
  48. )
  49. def parse(curl_command):
  50. parsed_context = parse_context(curl_command)
  51. data_token = ''
  52. if parsed_context.data:
  53. data_token = '{}data=\'{}\',\n'.format(BASE_INDENT, parsed_context.data)
  54. verify_token = ''
  55. if parsed_context.verify:
  56. verify_token = '\n{}verify=False'
  57. formatter = {
  58. 'method': parsed_context.method,
  59. 'url': parsed_context.url,
  60. 'data_token': data_token,
  61. 'headers_token': "{}headers={}".format(BASE_INDENT, dict_to_pretty_string(parsed_context.headers)),
  62. 'cookies_token': "{}cookies={}".format(BASE_INDENT, dict_to_pretty_string(parsed_context.cookies)),
  63. 'security_token': verify_token
  64. }
  65. return """
  66. import requests
  67. url = "http://localhost:22222"
  68. url = "{url}"
  69. resp = requests.{method}(
  70. url,
  71. {data_token}{headers_token},
  72. {cookies_token},{security_token}
  73. )
  74. print(resp.text)
  75. """.format(**formatter)
  76. def dict_to_pretty_string(the_dict, indent=4):
  77. if not the_dict:
  78. return "{}"
  79. return ("\n" + " " * indent).join(
  80. json.dumps(the_dict, sort_keys=True, indent=indent, separators=(',', ': ')).splitlines())