imgurxp/src/proxy_image.cpp

106 lines
4.1 KiB
C++

#include <kore/kore.h>
#include <kore/http.h>
#include <kore/curl.h>
#include <string>
#include "utils.hpp"
#include "404.hpp"
extern "C" {
int proxy_image(struct http_request*);
static int proxy_start(struct http_request*);
static int proxy_end(struct http_request*);
}
static struct http_state proxy_states[] = {
KORE_HTTP_STATE(proxy_start),
KORE_HTTP_STATE(proxy_end)
};
int proxy_image(struct http_request* req) {
return http_state_run(proxy_states, 2, req);
}
static int proxy_start(struct http_request* req) {
// /proxy/
const char* filename = &(req->path[7]);
std::string url = "https://i.imgur.com/";
url.append(filename);
struct kore_curl* client = (kore_curl*)http_state_create(req, sizeof(*client), NULL);
if (!kore_curl_init(client, url.c_str(), KORE_CURL_ASYNC)) {
http_state_cleanup(req);
kore_log(LOG_NOTICE, "failed to initialize curl client");
std::string error_page = build_error_page("Failed to initialize curl client");
http_response(req, 500, error_page.c_str(), error_page.length());
return HTTP_STATE_COMPLETE;
}
const char* header_value;
if (http_request_header(req, "Content-Range", &header_value) == KORE_RESULT_OK) {
kore_curl_http_set_header(client, "Content-Range", header_value);
}
if (http_request_header(req, "If-None-Match", &header_value) == KORE_RESULT_OK) {
kore_curl_http_set_header(client, "If-None-Match", header_value);
}
if (http_request_header(req, "If-Match", &header_value) == KORE_RESULT_OK) {
kore_curl_http_set_header(client, "If-Match", header_value);
}
if (http_request_header(req, "If-Modified-Since", &header_value) == KORE_RESULT_OK) {
kore_curl_http_set_header(client, "If-Modified-Since", header_value);
}
if (http_request_header(req, "If-Unmodified-Since", &header_value) == KORE_RESULT_OK) {
kore_curl_http_set_header(client, "If-Unmodified-Since", header_value);
}
// hmm
if (http_request_header(req, "Cache-Control", &header_value) == KORE_RESULT_OK) {
kore_curl_http_set_header(client, "Cache-Control", header_value);
}
kore_curl_http_setup(client, HTTP_METHOD_GET, NULL, 0);
kore_curl_bind_request(client, req);
kore_curl_run(client);
req->fsm_state = 1;
return HTTP_STATE_RETRY;
}
static int proxy_end(struct http_request* req) {
struct kore_curl* client = (kore_curl*)http_state_get(req);
if (!kore_curl_success(client)) {
kore_curl_logerror(client);
std::string error = "Failed to contact Imgur: ";
error.append(kore_curl_strerror(client));
kore_curl_cleanup(client);
http_state_cleanup(req);
std::string error_page = build_error_page(error.c_str());
http_response(req, 500, error_page.c_str(), error_page.length());
return HTTP_STATE_COMPLETE;
}
// imgur redirects to https://imgur.com/<rest of path> when image 404s
if (client->http.status == 302) {
kore_curl_cleanup(client);
http_state_cleanup(req);
not_found(req);
return HTTP_STATE_COMPLETE;
}
const char* header_value;
if (kore_curl_http_get_header(client, "Range", &header_value) == KORE_RESULT_OK) {
http_response_header(req, "Range", header_value);
}
if (kore_curl_http_get_header(client, "Accept-Ranges", &header_value) == KORE_RESULT_OK) {
http_response_header(req, "Accept-Ranges", header_value);
}
if (kore_curl_http_get_header(client, "ETag", &header_value) == KORE_RESULT_OK) {
http_response_header(req, "ETag", header_value);
}
if (kore_curl_http_get_header(client, "Content-Type", &header_value) == KORE_RESULT_OK) {
http_response_header(req, "Content-Type", header_value);
}
if (kore_curl_http_get_header(client, "Cache-Control", &header_value) == KORE_RESULT_OK) {
http_response_header(req, "Cache-Control", header_value);
}
const u_int8_t* body;
size_t len;
kore_curl_response_as_bytes(client, &body, &len);
http_response(req, client->http.status, body, len);
kore_curl_cleanup(client);
http_state_cleanup(req);
return HTTP_STATE_COMPLETE;
}