webClient.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #pragma once
  2. #ifndef webClient_H_
  3. #define webClient_H_
  4. #include "threadedRunner.h"
  5. #include "curl/curl.h"
  6. #include <stdio.h>
  7. // runnable that provides generic web client functionality to a single host
  8. // you can subclass this to provide specific behaviour
  9. #pragma pack(push, 1)
  10. class webClient: public runnable
  11. {
  12. public:
  13. struct request
  14. {
  15. typedef enum { GET,POST } method_t;
  16. uniString::utf8 m_addr;
  17. uniString::utf8 m_path;
  18. // content
  19. std::vector<__uint8> m_content;
  20. uniString::utf8 m_contentType;
  21. // used for the setting the 'X-Forwarded-For' header field which
  22. // is a bit of a fiddle to allow destip to be different so the YP
  23. // can test an alternative external IP from that it auto detects
  24. uniString::utf8 m_XFF;
  25. httpHeaderMap_t m_queryVariables;
  26. method_t m_method;
  27. int m_port;
  28. size_t m_sid;
  29. int m_retryCounter;
  30. int m_userData_i;
  31. size_t m_received; // size of data got
  32. int m_nonBlocking; // do on an additional thread e.g. the YP add needs
  33. // this else it blocks the YP test exists connetion
  34. // two random pieces of user data
  35. unsigned m_userData_u;
  36. void* m_userData_p;
  37. request() : m_path(uniString::utf8("/")), m_method(GET), m_port(80),
  38. m_sid(0), m_retryCounter(0), m_userData_i(0), m_received(0),
  39. m_nonBlocking(0), m_userData_u(0), m_userData_p(0) {}
  40. };
  41. struct response
  42. {
  43. uniString::utf8 m_resultText;
  44. uniString::utf8 m_body; // body of response
  45. httpHeaderMap_t m_headers; // response headers
  46. size_t m_resultCode; // HTTP result code
  47. size_t m_received; // size of data got
  48. response() : m_resultCode(0), m_received(0) {}
  49. void clear() throw()
  50. {
  51. m_resultCode = 0;
  52. m_received = 0;
  53. m_headers.clear();
  54. m_body.clear();
  55. m_resultText.clear();
  56. }
  57. };
  58. static size_t ParseReplyHeaders(void *buffer, size_t size, size_t count, FILE *stream) throw(std::runtime_error);
  59. static size_t GetBody(void *buffer, size_t size, size_t count, FILE *stream);
  60. CURL* getCurlHandle(const size_t SID = 0) { return m_curl[(!SID ? m_nonBlockingID : SID)]; }
  61. void clearCurlHeader(const size_t SID = 0)
  62. {
  63. size_t id = (!SID ? m_nonBlockingID : SID);
  64. struct curl_slist *header = m_curl_headers[id];
  65. if (header)
  66. {
  67. curl_slist_free_all(header);
  68. m_curl_headers[id] = 0;
  69. }
  70. }
  71. void gotCurlRespose();
  72. void getCurlError(CURL* curl, const CURLcode ret) throw(std::exception);
  73. static CURL* setupCurlDefaults(CURL* oldCurl, const char *logPrefix, const uniString::utf8& requestUrl,
  74. const int timeout = -1, const int connnectTimeout = -1, size_t SID = 0);
  75. static THREAD_FUNC process(void* arg);
  76. protected:
  77. class retry_exception : public std::runtime_error
  78. {
  79. public:
  80. explicit retry_exception(const uniString::utf8 &msg) : runtime_error(msg.hideAsString()){}
  81. };
  82. private:
  83. typedef void (webClient::*state_t)();
  84. const uniString::utf8 m_logPrefix;
  85. state_t m_state;
  86. state_t m_nextState;
  87. // curl specific parts
  88. typedef std::map<size_t, CURL*> curlMap_t;
  89. curlMap_t m_curl;
  90. size_t m_nonBlockingID;
  91. uniString::utf8 m_curl_path;
  92. typedef std::map<size_t, struct curl_slist*> curlHeadersMap_t;
  93. curlHeadersMap_t m_curl_headers;
  94. response m_response;
  95. char* m_curl_error;
  96. AOL_namespace::mutex m_requestQueueLock;
  97. std::queue<request> m_requestQueue;
  98. pipeDrivenSignal<nullLock> m_requestSignal;
  99. void state_Idle() throw(std::exception);
  100. void state_Wait() throw(std::exception);
  101. void state_ResolveServer() throw(std::exception);
  102. void state_Connect() throw(std::exception);
  103. void state_ConnectWait() throw(std::exception);
  104. void state_Send() throw(std::exception);
  105. void state_Get() throw(std::exception);
  106. void state_SendRequest() throw(std::exception);
  107. void state_RequestComplete() throw(std::exception);
  108. virtual void timeSlice() throw(std::exception);
  109. protected:
  110. explicit webClient(const uniString::utf8 &logPrefix) throw();
  111. virtual ~webClient() throw();
  112. void queueRequest(const request &req) throw();
  113. // throw to treat as an error and retry entire request
  114. virtual void gotResponse(const request &q, const response &r) throw(std::exception); // called when response is received
  115. virtual void gotFailure(const request &q) throw(std::exception); // called when retries are exhausted
  116. const size_t queueEntries() throw();
  117. };
  118. #pragma pack(pop)
  119. uniString::utf8 encodeVariables(const httpHeaderMap_t &m) throw();
  120. #endif