requests.h 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #pragma once
  2. #include "common.h"
  3. #if PK_MODULE_REQUESTS
  4. #include "httplib.h"
  5. #include "cffi.h"
  6. #include "_generated.h"
  7. namespace pkpy {
  8. inline void add_module_requests(VM* vm){
  9. static StrName m_requests("requests");
  10. static StrName m_Response("Response");
  11. PyObject* mod = vm->new_module(m_requests);
  12. CodeObject_ code = vm->compile(kPythonLibs["requests"], "requests.py", EXEC_MODE);
  13. vm->_exec(code, mod);
  14. vm->bind_func<4>(mod, "_request", [](VM* vm, ArgsView args){
  15. Str method = CAST(Str&, args[0]);
  16. Str url = CAST(Str&, args[1]);
  17. PyObject* headers = args[2]; // a dict object
  18. PyObject* body = args[3]; // a bytes object
  19. if(url.index("http://") != 0){
  20. vm->ValueError("url must start with http://");
  21. }
  22. for(char c: url){
  23. switch(c){
  24. case '.':
  25. case '-':
  26. case '_':
  27. case '~':
  28. case ':':
  29. case '/':
  30. break;
  31. default:
  32. if(!isalnum(c)){
  33. vm->ValueError(fmt("invalid character in url: '", c, "'"));
  34. }
  35. }
  36. }
  37. int slash = url.index("/", 7);
  38. Str path = "/";
  39. if(slash != -1){
  40. path = url.substr(slash);
  41. url = url.substr(0, slash);
  42. if(path.empty()) path = "/";
  43. }
  44. httplib::Client client(url.str());
  45. httplib::Headers h;
  46. if(headers != vm->None){
  47. List list = CAST(List&, headers);
  48. for(auto& item : list){
  49. Tuple t = CAST(Tuple&, item);
  50. Str key = CAST(Str&, t[0]);
  51. Str value = CAST(Str&, t[1]);
  52. h.emplace(key.str(), value.str());
  53. }
  54. }
  55. auto _to_resp = [=](const httplib::Result& res){
  56. return vm->call(
  57. vm->_modules[m_requests]->attr(m_Response),
  58. VAR(res->status),
  59. VAR(res->reason),
  60. VAR(Bytes(res->body))
  61. );
  62. };
  63. if(method == "GET"){
  64. httplib::Result res = client.Get(path.str(), h);
  65. return _to_resp(res);
  66. }else if(method == "POST"){
  67. Bytes b = CAST(Bytes&, body);
  68. httplib::Result res = client.Post(path.str(), h, b.data(), b.size(), "application/octet-stream");
  69. return _to_resp(res);
  70. }else if(method == "PUT"){
  71. Bytes b = CAST(Bytes&, body);
  72. httplib::Result res = client.Put(path.str(), h, b.data(), b.size(), "application/octet-stream");
  73. return _to_resp(res);
  74. }else if(method == "DELETE"){
  75. httplib::Result res = client.Delete(path.str(), h);
  76. return _to_resp(res);
  77. }else{
  78. vm->ValueError("invalid method");
  79. }
  80. UNREACHABLE();
  81. });
  82. }
  83. } // namespace pkpy
  84. #else
  85. ADD_MODULE_PLACEHOLDER(requests)
  86. #endif