ImageProxy.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #include "ImageProxy.h"
  2. #include "../Proxy/Proxy.h"
  3. #include <curl/curl.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #define MAX_IMAGE_SIZE (10 * 1024 * 1024)
  8. typedef struct {
  9. char *data;
  10. size_t size;
  11. size_t capacity;
  12. } MemoryBuffer;
  13. static int is_allowed_domain(const char *url) {
  14. const char *protocol = strstr(url, "://");
  15. if (!protocol) {
  16. protocol = url;
  17. } else {
  18. protocol += 3;
  19. }
  20. const char *path = strchr(protocol, '/');
  21. size_t host_len = path ? (size_t)(path - protocol) : strlen(protocol);
  22. char host[256] = {0};
  23. if (host_len >= sizeof(host)) {
  24. host_len = sizeof(host) - 1;
  25. }
  26. strncpy(host, protocol, host_len);
  27. const char *allowed_domains[] = {
  28. "mm.bing.net",
  29. "th.bing.com",
  30. NULL
  31. };
  32. for (int i = 0; allowed_domains[i] != NULL; i++) {
  33. size_t domain_len = strlen(allowed_domains[i]);
  34. size_t host_str_len = strlen(host);
  35. if (host_str_len >= domain_len) {
  36. const char *suffix = host + host_str_len - domain_len;
  37. if (strcmp(suffix, allowed_domains[i]) == 0) {
  38. return 1;
  39. }
  40. }
  41. }
  42. return 0;
  43. }
  44. static size_t write_callback(void *contents, size_t size, size_t nmemb,
  45. void *userp) {
  46. size_t realsize = size * nmemb;
  47. MemoryBuffer *buf = (MemoryBuffer *)userp;
  48. if (buf->size + realsize > MAX_IMAGE_SIZE) {
  49. return 0;
  50. }
  51. if (buf->size + realsize > buf->capacity) {
  52. size_t new_capacity = buf->capacity * 2;
  53. if (new_capacity < buf->size + realsize) {
  54. new_capacity = buf->size + realsize;
  55. }
  56. char *new_data = realloc(buf->data, new_capacity);
  57. if (!new_data) return 0;
  58. buf->data = new_data;
  59. buf->capacity = new_capacity;
  60. }
  61. memcpy(buf->data + buf->size, contents, realsize);
  62. buf->size += realsize;
  63. return realsize;
  64. }
  65. int image_proxy_handler(UrlParams *params) {
  66. const char *url = NULL;
  67. for (int i = 0; i < params->count; i++) {
  68. if (strcmp(params->params[i].key, "url") == 0) {
  69. url = params->params[i].value;
  70. break;
  71. }
  72. }
  73. if (!url || strlen(url) == 0) {
  74. send_response("Missing 'url' parameter");
  75. return 0;
  76. }
  77. if (!is_allowed_domain(url)) {
  78. send_response("Domain not allowed");
  79. return 0;
  80. }
  81. CURL *curl = curl_easy_init();
  82. if (!curl) {
  83. send_response("Failed to initialize curl");
  84. return 0;
  85. }
  86. MemoryBuffer buf = {
  87. .data = malloc(8192),
  88. .size = 0,
  89. .capacity = 8192
  90. };
  91. if (!buf.data) {
  92. curl_easy_cleanup(curl);
  93. send_response("Memory allocation failed");
  94. return 0;
  95. }
  96. curl_easy_setopt(curl, CURLOPT_URL, url);
  97. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
  98. curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
  99. curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
  100. curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
  101. apply_proxy_settings(curl);
  102. CURLcode res = curl_easy_perform(curl);
  103. long response_code;
  104. curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
  105. char *content_type_ptr = NULL;
  106. curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type_ptr);
  107. char content_type[64] = {0};
  108. if (content_type_ptr) {
  109. strncpy(content_type, content_type_ptr, sizeof(content_type) - 1);
  110. }
  111. curl_easy_cleanup(curl);
  112. if (res != CURLE_OK || response_code != 200) {
  113. free(buf.data);
  114. send_response("Failed to fetch image");
  115. return 0;
  116. }
  117. const char *mime_type = strlen(content_type) > 0 ? content_type : "image/jpeg";
  118. serve_data(buf.data, buf.size, mime_type);
  119. free(buf.data);
  120. return 0;
  121. }