Files
iptv-downloader/http/http.c
T

156 lines
5.7 KiB
C
Raw Normal View History

#include "http.h"
#include "config.h" /* g_cfg */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
char *g_header = NULL; int g_header_len = 0;
char *g_footer = NULL; int g_footer_len = 0;
char *g_css = NULL; int g_css_len = 0;
StaticJS g_js[] = {
{ "/iptv.js", "js/iptv.js", NULL, 0 },
{ "/downloads.js", "js/downloads.js", NULL, 0 },
{ "/series_show.js", "js/series_show.js", NULL, 0 },
{ NULL, NULL, NULL, 0 }
};
static int load_file(const char *path, char **out, int *out_len) {
FILE *f = fopen(path, "rb");
if (!f) { fprintf(stderr, "iptv-dl: cannot open %s: %s\n", path, strerror(errno)); return 0; }
fseek(f, 0, SEEK_END); long sz = ftell(f); fseek(f, 0, SEEK_SET);
*out = malloc(sz + 1);
if (!*out) { fclose(f); return 0; }
*out_len = (int)fread(*out, 1, sz, f);
(*out)[*out_len] = '\0';
fclose(f);
return 1;
}
int http_load_templates(void) {
char path[512];
snprintf(path, sizeof(path), "%s/html/header.html", g_cfg.template_dir);
if (!load_file(path, &g_header, &g_header_len)) return 0;
snprintf(path, sizeof(path), "%s/html/footer.html", g_cfg.template_dir);
if (!load_file(path, &g_footer, &g_footer_len)) return 0;
snprintf(path, sizeof(path), "%s/css/iptv.css", g_cfg.template_dir);
if (!load_file(path, &g_css, &g_css_len)) return 0;
for (int i = 0; g_js[i].url_path; i++) {
snprintf(path, sizeof(path), "%s/%s", g_cfg.template_dir, g_js[i].fs_name);
/* non-fatal if JS file missing */
load_file(path, &g_js[i].data, &g_js[i].len);
}
fprintf(stderr, "iptv-dl: templates loaded (header=%d footer=%d css=%d bytes)\n",
g_header_len, g_footer_len, g_css_len);
return 1;
}
int parse_request(int fd, Req *req) {
char buf[131072]; int total = 0, n;
memset(req, 0, sizeof(*req));
while ((n = read(fd, buf+total, sizeof(buf)-1-total)) > 0) {
total += n; buf[total] = 0;
if (strstr(buf, "\r\n\r\n")) break;
}
if (total <= 0) return -1;
buf[total] = 0;
char *sp1 = strchr(buf, ' '); if (!sp1) return -1;
size_t mlen = sp1 - buf; if (mlen >= 8) mlen = 7;
memcpy(req->method, buf, mlen); req->method[mlen] = 0;
char *sp2 = strchr(sp1+1, ' '); if (!sp2) return -1;
size_t plen = sp2 - sp1 - 1; if (plen >= 256) plen = 255;
char full[256]; memcpy(full, sp1+1, plen); full[plen] = 0;
char *qm = strchr(full, '?');
if (qm) { *qm = 0; strncpy(req->query, qm+1, sizeof(req->query)-1); }
strncpy(req->path, full, sizeof(req->path)-1);
char *body_start = strstr(buf, "\r\n\r\n");
if (body_start) {
body_start += 4;
int blen = total - (int)(body_start - buf);
if (blen > 0 && blen < (int)sizeof(req->body)) { memcpy(req->body, body_start, blen); req->body_len = blen; }
}
return 0;
}
void send_page(int fd, const char *title, Buf *body, const char *script_src) {
Buf page; buf_init(&page);
buf_str(&page, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\n\r\n");
/* inject <base href> so relative assets resolve correctly at any sub-path */
const char *ph = strstr(g_header, "{{TITLE}}");
const char *head_end = strstr(g_header, "</head>");
if (ph && head_end && head_end > ph) {
/* write up to </head>, inject base tag, then rest of header */
buf_append(&page, g_header, ph - g_header);
buf_str(&page, title);
const char *after_title = ph + 9;
buf_append(&page, after_title, head_end - after_title);
if (g_cfg.base_path[0])
buf_fmt(&page, "<base href=\"%s/\">", g_cfg.base_path);
buf_str(&page, head_end);
} else if (ph) {
buf_append(&page, g_header, ph - g_header);
buf_str(&page, title);
buf_str(&page, ph + 9);
} else {
buf_str(&page, g_header);
}
buf_append(&page, body->data, body->len);
if (script_src && script_src[0])
buf_fmt(&page, "<script src=\"%s\"></script>", script_src);
buf_str(&page, g_footer);
write(fd, page.data, page.len);
buf_free(&page);
}
void send_css(int fd) {
char hdr[256];
int hl = snprintf(hdr, sizeof(hdr),
"HTTP/1.1 200 OK\r\nContent-Type: text/css\r\n"
"Content-Length: %d\r\nConnection: close\r\n\r\n", g_css_len);
write(fd, hdr, hl);
write(fd, g_css, g_css_len);
}
void send_static_js(int fd, const char *path) {
for (int i = 0; g_js[i].url_path; i++) {
if (strcmp(g_js[i].url_path, path) == 0) {
if (!g_js[i].data) { send_404(fd); return; }
char hdr[256];
int hl = snprintf(hdr, sizeof(hdr),
"HTTP/1.1 200 OK\r\nContent-Type: application/javascript\r\n"
"Content-Length: %d\r\nConnection: close\r\n\r\n", g_js[i].len);
write(fd, hdr, hl);
write(fd, g_js[i].data, g_js[i].len);
return;
}
}
send_404(fd);
}
void send_json(int fd, const char *json) {
char hdr[256];
snprintf(hdr, sizeof(hdr),
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Length: %zu\r\nConnection: close\r\n\r\n", strlen(json));
write(fd, hdr, strlen(hdr));
write(fd, json, strlen(json));
}
void send_json_buf(int fd, Buf *b) {
char hdr[256];
snprintf(hdr, sizeof(hdr),
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Length: %zu\r\nConnection: close\r\n\r\n", b->len);
write(fd, hdr, strlen(hdr));
write(fd, b->data, b->len);
}
void send_404(int fd) {
const char *r = "HTTP/1.1 404 Not Found\r\nContent-Length: 9\r\nConnection: close\r\n\r\nNot Found";
write(fd, r, strlen(r));
}