requests.h 3.0 KB

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