PageRenderTime 26ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/riak_curl.c

https://github.com/maxbeutel/ext.riak
C | 365 lines | 235 code | 126 blank | 4 comment | 43 complexity | 537bfc08fe33f82a9ff2bb4d4f3760b7 MD5 | raw file
  1. #include <php.h>
  2. #include <ext/json/php_json.h>
  3. #include "ext/standard/php_smart_str.h"
  4. #include <curl/curl.h>
  5. #include <curl/easy.h>
  6. #include "riak_curl.h"
  7. #include "riak_shared.h"
  8. PHPAPI riakCurlRequestHeader* riak_curl_create_request_header() {
  9. size_t block_size;
  10. block_size = 2;
  11. riakCurlRequestHeader* request_header = malloc(sizeof(riakCurlRequestHeader));
  12. if (request_header != NULL) {
  13. request_header->num = 0;
  14. request_header->size = block_size;
  15. request_header->block_size = block_size;
  16. request_header->str = malloc(sizeof(char*)*block_size);
  17. if (request_header->str == NULL) {
  18. free(request_header);
  19. return NULL;
  20. }
  21. }
  22. return request_header;
  23. }
  24. PHPAPI void riak_curl_delete_request_header(riakCurlRequestHeader* request_header) {
  25. char **iter;
  26. for (iter = riak_curl_add_request_header_start(request_header); iter != riak_curl_add_request_header_end(request_header); ++iter) {
  27. free(*iter);
  28. }
  29. free(request_header->str);
  30. free(request_header);
  31. }
  32. PHPAPI int riak_curl_add_request_header_str(riakCurlRequestHeader* request_header, char* str, int str_len) {
  33. size_t num = request_header->num;
  34. if (num >= request_header->size) {
  35. size_t new_size = request_header->size + request_header->block_size;
  36. void* new_request_header = realloc(request_header->str, sizeof(char*)*new_size);
  37. if (new_request_header == NULL) {
  38. return FAILURE;
  39. } else {
  40. request_header->size = new_size;
  41. request_header->str = (char**)new_request_header;
  42. }
  43. }
  44. request_header->str[num] = strndup(str, str_len);
  45. ++request_header->num;
  46. return SUCCESS;
  47. }
  48. PHPAPI char** riak_curl_add_request_header_start(riakCurlRequestHeader* request_header) {
  49. return request_header->str;
  50. }
  51. PHPAPI char** riak_curl_add_request_header_end(riakCurlRequestHeader* request_header) {
  52. return &request_header->str[request_header->num];
  53. }
  54. typedef struct {
  55. char *str;
  56. size_t len;
  57. } riakCurlResponse;
  58. PHPAPI void riak_curl_response_init(riakCurlResponse *s) {
  59. s->len = 0;
  60. s->str = emalloc(s->len + 1);
  61. s->str[0] = '\0';
  62. }
  63. PHPAPI size_t riak_curl_writefunc(void *ptr, size_t size, size_t nmemb, riakCurlResponse *s) {
  64. size_t new_len = s->len + size * nmemb;
  65. s->str = erealloc(s->str, new_len + 1);
  66. memcpy(s->str + s->len, ptr, size*nmemb);
  67. s->str[new_len] = '\0';
  68. s->len = new_len;
  69. return size * nmemb;
  70. }
  71. PHPAPI void riak_curl_data_to_json_str(zval *data, char **json_struct TSRMLS_DC) {
  72. smart_str buf = {0};
  73. php_json_encode(&buf, data, 0 TSRMLS_CC);
  74. *json_struct = strndup(buf.c, buf.len);
  75. php_printf("json encoded: |%s|\n", *json_struct);
  76. smart_str_free(&buf);
  77. }
  78. PHPAPI int riak_curl_fetch_response(char *client_id, char *request_url, char **response_body, riakCurlRequestHeader *response_header TSRMLS_DC) {
  79. CURL *curl;
  80. CURLcode res;
  81. struct curl_slist *headers = NULL;
  82. riakCurlResponse response_body_content;
  83. riakCurlResponse response_header_content;
  84. char *client_id_header = NULL;
  85. char *response_header_copy = NULL;
  86. char *header_line = NULL;
  87. char *last;
  88. int result;
  89. if (asprintf(&client_id_header, "X-Riak-ClientId: %s", client_id) < 0) {
  90. RIAK_MALLOC_WARNING();
  91. result = FAILURE;
  92. goto cleanup;
  93. }
  94. curl = curl_easy_init();
  95. if (curl) {
  96. riak_curl_response_init(&response_body_content);
  97. if (response_header) {
  98. riak_curl_response_init(&response_header_content);
  99. }
  100. headers = curl_slist_append(headers, client_id_header);
  101. curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  102. curl_easy_setopt(curl, CURLOPT_URL, request_url);
  103. /* store response headers if needed */
  104. if (response_header) {
  105. curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, riak_curl_writefunc);
  106. curl_easy_setopt(curl, CURLOPT_WRITEHEADER, &response_header_content);
  107. }
  108. /* store response body */
  109. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, riak_curl_writefunc);
  110. curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body_content);
  111. res = curl_easy_perform(curl);
  112. curl_slist_free_all(headers);
  113. curl_easy_cleanup(curl);
  114. if (asprintf(response_body, "%s", response_body_content.str) < 0) {
  115. RIAK_MALLOC_WARNING();
  116. result = FAILURE;
  117. goto cleanup;
  118. }
  119. /* parse headers in array struct */
  120. if (response_header) {
  121. if (asprintf(&response_header_copy, "%s", response_header_content.str) < 0) {
  122. RIAK_MALLOC_WARNING();
  123. result = FAILURE;
  124. goto cleanup;
  125. }
  126. for (header_line = strtok_r(response_header_copy, "\r\n", &last); header_line; header_line = strtok_r(NULL, "\r\n", &last)) {
  127. riak_curl_add_request_header_str(response_header, header_line, strlen(header_line));
  128. }
  129. }
  130. /* output some debug info */
  131. if (response_header) {
  132. php_printf("Response header: %s\n", response_header_content.str);
  133. }
  134. php_printf("JSON response: %s\n", response_body_content.str);
  135. efree(response_body_content.str);
  136. if (response_header) {
  137. efree(response_header_content.str);
  138. }
  139. result = SUCCESS;
  140. } else {
  141. RIAK_CURL_WARNING();
  142. result = FAILURE;
  143. goto cleanup;
  144. }
  145. cleanup:
  146. if (response_header_copy) {
  147. free(response_header_copy);
  148. }
  149. if (client_id_header) {
  150. free(client_id_header);
  151. }
  152. return result;
  153. }
  154. PHPAPI int riak_curl_fetch_json_response(char *client_id, char *request_url, zval **json_response, riakCurlRequestHeader *response_headers TSRMLS_DC) {
  155. char *response = NULL;
  156. zval *tmp = NULL;
  157. int result;
  158. if (riak_curl_fetch_response(client_id, request_url, &response, response_headers TSRMLS_CC) == SUCCESS) {
  159. tmp = *json_response;
  160. php_json_decode(tmp, response, strlen(response), 1, 20 TSRMLS_CC);
  161. result = SUCCESS;
  162. } else {
  163. result = FAILURE;
  164. }
  165. if (response) {
  166. free(response);
  167. }
  168. return result;
  169. }
  170. PHPAPI int riak_curl_send_write_request(char *method, char *client_id, char *request_url, char *data, riakCurlRequestHeader* request_header TSRMLS_DC) {
  171. CURL *curl;
  172. CURLcode res;
  173. struct curl_slist *headers = NULL;
  174. char *client_id_header = NULL;
  175. int result;
  176. long http_code = 0;
  177. if (asprintf(&client_id_header, "X-Riak-ClientId: %s", client_id) < 0) {
  178. RIAK_MALLOC_WARNING();
  179. result = FAILURE;
  180. goto cleanup;
  181. }
  182. curl = curl_easy_init();
  183. if (curl) {
  184. headers = curl_slist_append(headers, client_id_header);
  185. if (request_header) {
  186. char** iter;
  187. for (iter = riak_curl_add_request_header_start(request_header); iter != riak_curl_add_request_header_end(request_header); ++iter) {
  188. php_printf("Additional header: %s\n", *iter);
  189. }
  190. }
  191. curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  192. curl_easy_setopt(curl, CURLOPT_URL, request_url);
  193. if (strcmp(method, "PUT") == 0) {
  194. curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
  195. }
  196. curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
  197. res = curl_easy_perform(curl);
  198. curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
  199. if (CURLE_OK != res || http_code != 204) {
  200. php_printf("Error: %s\n", curl_easy_strerror(res));
  201. result = FAILURE;
  202. } else {
  203. result = SUCCESS;
  204. }
  205. curl_slist_free_all(headers);
  206. curl_easy_cleanup(curl);
  207. } else {
  208. RIAK_CURL_WARNING();
  209. result = FAILURE;
  210. goto cleanup;
  211. }
  212. cleanup:
  213. if (client_id_header) {
  214. free(client_id_header);
  215. }
  216. return result;
  217. }
  218. PHPAPI int riak_curl_send_post_json_request(char *client_id, char *request_url, zval *data, riakCurlRequestHeader* request_header TSRMLS_DC) {
  219. char *json_struct;
  220. riak_curl_data_to_json_str(data, &json_struct TSRMLS_CC);
  221. if (request_header) {
  222. riak_curl_add_request_header_str(request_header, RIAK_CURL_REQUESTHEADER_CONTENTTYPE_JSON, RIAK_CURL_REQUESTHEADER_CONTENTTYPE_JSON_LEN);
  223. }
  224. return riak_curl_send_write_request("POST", client_id, request_url, json_struct, request_header TSRMLS_CC);
  225. }
  226. PHPAPI int riak_curl_send_put_json_request(char *client_id, char *request_url, zval *data, riakCurlRequestHeader* request_header TSRMLS_DC) {
  227. char *json_struct;
  228. riak_curl_data_to_json_str(data, &json_struct TSRMLS_CC);
  229. if (request_header) {
  230. riak_curl_add_request_header_str(request_header, RIAK_CURL_REQUESTHEADER_CONTENTTYPE_JSON, RIAK_CURL_REQUESTHEADER_CONTENTTYPE_JSON_LEN);
  231. }
  232. return riak_curl_send_write_request("PUT", client_id, request_url, json_struct, request_header TSRMLS_CC);
  233. }
  234. PHPAPI int riak_curl_send_post_request(char *client_id, char *request_url, char *data, riakCurlRequestHeader* request_header TSRMLS_DC) {
  235. return riak_curl_send_write_request("POST", client_id, request_url, data, request_header TSRMLS_CC);
  236. }
  237. PHPAPI int riak_curl_send_put_request(char *client_id, char *request_url, char *data, riakCurlRequestHeader* request_header TSRMLS_DC) {
  238. return riak_curl_send_write_request("PUT", client_id, request_url, data, request_header TSRMLS_CC);
  239. }