소스 검색

add image proxying

frosty 3 주 전
부모
커밋
e116a5d1f5
4개의 변경된 파일174개의 추가작업 그리고 1개의 파일을 삭제
  1. 2 0
      src/Main.c
  2. 148 0
      src/Routes/ImageProxy.c
  3. 8 0
      src/Routes/ImageProxy.h
  4. 16 1
      src/Routes/Images.c

+ 2 - 0
src/Main.c

@@ -7,6 +7,7 @@
 #include "Config.h"
 #include "Routes/Home.h"
 #include "Routes/Images.h"
+#include "Routes/ImageProxy.h"
 #include "Routes/Search.h"
 
 int handle_opensearch(UrlParams *params) {
@@ -31,6 +32,7 @@ int main() {
   set_handler("/opensearch.xml", handle_opensearch);
   set_handler("/search", results_handler);
   set_handler("/images", images_handler);
+  set_handler("/proxy", image_proxy_handler);
 
   fprintf(stderr, "Starting Omnisearch on %s:%d\n", config.host, config.port);
 

+ 148 - 0
src/Routes/ImageProxy.c

@@ -0,0 +1,148 @@
+#include "ImageProxy.h"
+
+#include <curl/curl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAX_IMAGE_SIZE (10 * 1024 * 1024)
+
+typedef struct {
+  char *data;
+  size_t size;
+  size_t capacity;
+} MemoryBuffer;
+
+static int is_allowed_domain(const char *url) {
+  const char *protocol = strstr(url, "://");
+  if (!protocol) {
+    protocol = url;
+  } else {
+    protocol += 3;
+  }
+
+  const char *path = strchr(protocol, '/');
+  size_t host_len = path ? (size_t)(path - protocol) : strlen(protocol);
+
+  char host[256] = {0};
+  if (host_len >= sizeof(host)) {
+    host_len = sizeof(host) - 1;
+  }
+  strncpy(host, protocol, host_len);
+
+  const char *allowed_domains[] = {
+    "mm.bing.net",
+    "th.bing.com",
+    NULL
+  };
+
+  for (int i = 0; allowed_domains[i] != NULL; i++) {
+    size_t domain_len = strlen(allowed_domains[i]);
+    size_t host_str_len = strlen(host);
+
+    if (host_str_len >= domain_len) {
+      const char *suffix = host + host_str_len - domain_len;
+      if (strcmp(suffix, allowed_domains[i]) == 0) {
+        return 1;
+      }
+    }
+  }
+
+  return 0;
+}
+
+static size_t write_callback(void *contents, size_t size, size_t nmemb,
+                             void *userp) {
+  size_t realsize = size * nmemb;
+  MemoryBuffer *buf = (MemoryBuffer *)userp;
+
+  if (buf->size + realsize > MAX_IMAGE_SIZE) {
+    return 0;
+  }
+
+  if (buf->size + realsize > buf->capacity) {
+    size_t new_capacity = buf->capacity * 2;
+    if (new_capacity < buf->size + realsize) {
+      new_capacity = buf->size + realsize;
+    }
+    char *new_data = realloc(buf->data, new_capacity);
+    if (!new_data) return 0;
+    buf->data = new_data;
+    buf->capacity = new_capacity;
+  }
+
+  memcpy(buf->data + buf->size, contents, realsize);
+  buf->size += realsize;
+  return realsize;
+}
+
+int image_proxy_handler(UrlParams *params) {
+  const char *url = NULL;
+  for (int i = 0; i < params->count; i++) {
+    if (strcmp(params->params[i].key, "url") == 0) {
+      url = params->params[i].value;
+      break;
+    }
+  }
+
+  if (!url || strlen(url) == 0) {
+    send_response("Missing 'url' parameter");
+    return 0;
+  }
+
+  if (!is_allowed_domain(url)) {
+    send_response("Domain not allowed");
+    return 0;
+  }
+
+  CURL *curl = curl_easy_init();
+  if (!curl) {
+    send_response("Failed to initialize curl");
+    return 0;
+  }
+
+  MemoryBuffer buf = {
+    .data = malloc(8192),
+    .size = 0,
+    .capacity = 8192
+  };
+
+  if (!buf.data) {
+    curl_easy_cleanup(curl);
+    send_response("Memory allocation failed");
+    return 0;
+  }
+
+  curl_easy_setopt(curl, CURLOPT_URL, url);
+  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
+  curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
+  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
+
+  CURLcode res = curl_easy_perform(curl);
+
+  long response_code;
+  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
+
+  char *content_type_ptr = NULL;
+  curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type_ptr);
+
+  char content_type[64] = {0};
+  if (content_type_ptr) {
+    strncpy(content_type, content_type_ptr, sizeof(content_type) - 1);
+  }
+
+  curl_easy_cleanup(curl);
+
+  if (res != CURLE_OK || response_code != 200) {
+    free(buf.data);
+    send_response("Failed to fetch image");
+    return 0;
+  }
+
+  const char *mime_type = strlen(content_type) > 0 ? content_type : "image/jpeg";
+  serve_data(buf.data, buf.size, mime_type);
+
+  free(buf.data);
+  return 0;
+}

+ 8 - 0
src/Routes/ImageProxy.h

@@ -0,0 +1,8 @@
+#ifndef IMAGE_PROXY_HANDLER_H
+#define IMAGE_PROXY_HANDLER_H
+
+#include <beaker.h>
+
+int image_proxy_handler(UrlParams *params);
+
+#endif

+ 16 - 1
src/Routes/Images.c

@@ -231,8 +231,23 @@ int images_handler(UrlParams *params) {
       xmlChar *rurl = tit_node ? xmlGetProp(tit_node, (const xmlChar *)"href") : NULL;
 
       if (iurl && strlen((char *)iurl) > 0) {
+        char *proxy_url = NULL;
+        CURL *esc_curl = curl_easy_init();
+        if (esc_curl) {
+          char *encoded = curl_easy_escape(esc_curl, (char *)iurl, 0);
+          if (encoded) {
+            size_t proxy_len = strlen("/proxy?url=") + strlen(encoded) + 1;
+            proxy_url = malloc(proxy_len);
+            if (proxy_url) {
+              snprintf(proxy_url, proxy_len, "/proxy?url=%s", encoded);
+            }
+            curl_free(encoded);
+          }
+          curl_easy_cleanup(esc_curl);
+        }
+
         image_matrix[image_count] = malloc(sizeof(char *) * 4);
-        image_matrix[image_count][0] = strdup((char *)iurl);
+        image_matrix[image_count][0] = proxy_url ? proxy_url : strdup((char *)iurl);
         image_matrix[image_count][1] = strdup(title ? (char *)title : "Image");
         image_matrix[image_count][2] = strdup(rurl ? (char *)rurl : "#");
         image_matrix[image_count][3] = strdup(full_url ? (char *)full_url : "#");