From c44e1af530c77223473d75dbe5b9c2cc02aa0cac Mon Sep 17 00:00:00 2001 From: "yu.dongliang" <18588496441@163.com> Date: Sat, 2 Nov 2024 21:09:06 +0800 Subject: [PATCH] add a simpile HTTP support for AF_UNIX --- html/Makefile | 4 +- html/abc_html.c | 51 ++++-- html/abc_html.h | 25 ++- html/abc_html_util.c | 5 +- html/abc_io_file.c | 47 +++++ html/abc_io_http.c | 355 ++++++++++++++++++++++++++++++++++++++ html/main.c | 3 + net/config | 4 + net/ngx_http_abc.h | 10 ++ net/ngx_http_abc_module.c | 105 +++++++++++ ui/Makefile | 3 + ui/main.c | 3 + util/scf_def.h | 7 + 13 files changed, 605 insertions(+), 17 deletions(-) create mode 100644 html/abc_io_file.c create mode 100644 html/abc_io_http.c create mode 100644 net/config create mode 100644 net/ngx_http_abc.h create mode 100644 net/ngx_http_abc_module.c diff --git a/html/Makefile b/html/Makefile index 2e9a348..fe589e2 100644 --- a/html/Makefile +++ b/html/Makefile @@ -4,11 +4,13 @@ CFILES += main.c CFILES += abc_obj.c CFILES += abc_html.c CFILES += abc_html_util.c +CFILES += abc_io_file.c +CFILES += abc_io_http.c CFLAGS += -g CFLAGS += -I../util -LDFLAGS += -ldl +LDFLAGS += -ldl -pthread all: gcc $(CFLAGS) $(CFILES) $(LDFLAGS) diff --git a/html/abc_html.c b/html/abc_html.c index 346de87..82afe93 100644 --- a/html/abc_html.c +++ b/html/abc_html.c @@ -19,6 +19,15 @@ typedef struct { #define abc_number_of(__array) (sizeof(__array) / sizeof(__array[0])) +extern abc_io_t abc_io_file; +extern abc_io_t abc_io_http; + +static abc_io_t* abc_io_array[ABC_PROTO_NB] = +{ + [ABC_PROTO_FILE] = &abc_io_file, + [ABC_PROTO_HTTP] = &abc_io_http, +}; + static char* src_keys[] = {"src", "源", NULL}; static char* href_keys[] = {"href", "地址", NULL}; @@ -250,24 +259,42 @@ int abc_html_open(abc_html_t** pp, const char* path) if (!pp || !path) return -EINVAL; - abc_html_t* html = calloc(1, sizeof(abc_html_t)); + abc_html_t* html; + abc_io_t* io; + int n; + + if (!strncmp(path, "file://", 7)) { + n = 7; + io = abc_io_array[ABC_PROTO_FILE]; + + } else if (!strncmp(path, "http://", 7)) { + n = 7; + io = abc_io_array[ABC_PROTO_HTTP]; + } else { + scf_loge("proto of '%s' NOT support\n", path); + return -EINVAL; + } + + html = calloc(1, sizeof(abc_html_t)); if (!html) return -ENOMEM; - html->fp = fopen(path, "r"); - if (!html->fp) { - char cwd[4096]; - getcwd(cwd, 4095); - scf_loge("path: %s, errno: %d, pwd: %s\n", path, errno, cwd); + html->io.proto = io->proto; + html->io.priv = NULL; + html->io.open = io->open; + html->io.close = io->close; + html->io.popc = io->popc; + html->io.post = io->post; + int ret = io->open(html, path + n); + if (ret < 0) { free(html); - return -1; + return ret; } html->file = scf_string_cstr(path); if (!html->file) { - fclose(html->fp); - free(html); + abc_html_close(html); return -ENOMEM; } @@ -292,8 +319,8 @@ void abc_html_close(abc_html_t* html) if (html->root) abc_obj_free(html->root); - if (html->fp) - fclose(html->fp); + if (html->io.close) + html->io.close(html); if (html->file) scf_string_free(html->file); @@ -756,7 +783,7 @@ int abc_html_parse(abc_html_t* html) } if ('<' != c->c) { - scf_loge("%c:%#x, html->n_lines: %d, pos: %d\n", c->c, c->c, html->n_lines, html->pos); + scf_loge("%c:%#x:%d, html->n_lines: %d, pos: %d\n", c->c, c->c, c->c, html->n_lines, html->pos); free(c); return -1; } diff --git a/html/abc_html.h b/html/abc_html.h index c335f48..48aa167 100644 --- a/html/abc_html.h +++ b/html/abc_html.h @@ -5,6 +5,15 @@ typedef struct abc_char_s abc_char_t; typedef struct abc_html_s abc_html_t; +typedef struct abc_io_s abc_io_t; + +enum abc_protos +{ + ABC_PROTO_FILE, + ABC_PROTO_HTTP, + + ABC_PROTO_NB +}; #define ABC_UTF8_MAX 6 struct abc_char_s @@ -16,6 +25,18 @@ struct abc_char_s uint8_t utf8[ABC_UTF8_MAX]; }; +struct abc_io_s +{ + char* proto; + void* priv; + + int (*open )(abc_html_t* html, const char* path); + void (*close)(abc_html_t* html); + + int (*popc )(abc_html_t* html); + int (*post )(abc_html_t* html); +}; + struct abc_html_s { scf_list_t list; @@ -25,11 +46,13 @@ struct abc_html_s abc_obj_t* root; abc_obj_t* current; - FILE* fp; + abc_io_t io; scf_string_t* file; int n_lines; int pos; + + uint8_t download:1; }; int abc_html_open (abc_html_t** pp, const char* path); diff --git a/html/abc_html_util.c b/html/abc_html_util.c index 5053387..011c377 100644 --- a/html/abc_html_util.c +++ b/html/abc_html_util.c @@ -3,7 +3,6 @@ abc_char_t* __html_pop_char(abc_html_t* html) { assert(html); - assert(html->fp); abc_char_t* c; @@ -17,7 +16,7 @@ abc_char_t* __html_pop_char(abc_html_t* html) if (!c) return NULL; - int ret = fgetc(html->fp); + int ret = html->io.popc(html); if (EOF == ret) { c->c = ret; return c; @@ -60,7 +59,7 @@ abc_char_t* __html_pop_char(abc_html_t* html) int i; for (i = 1; i < c->len; i++) { - ret = fgetc(html->fp); + ret = html->io.popc(html); if (0x2 == (ret >> 6)) { c->c <<= 6; diff --git a/html/abc_io_file.c b/html/abc_io_file.c new file mode 100644 index 0000000..16afbbd --- /dev/null +++ b/html/abc_io_file.c @@ -0,0 +1,47 @@ +#include"abc_html.h" + +static int __file_open(abc_html_t* html, const char* path) +{ + if (!html || !path) + return -EINVAL; + + html->io.priv = fopen(path, "r"); + if (!html->io.priv) { + char cwd[4096]; + getcwd(cwd, 4095); + + scf_loge("path: %s, errno: %d, pwd: %s\n", path, errno, cwd); + return -1; + } + + html->download = 1; + return 0; +} + +static void __file_close(abc_html_t* html) +{ + if (html && html->io.priv) { + + fclose(html->io.priv); + } +} + +static int __file_popc(abc_html_t* html) +{ + if (html && html->io.priv) { + + return fgetc(html->io.priv); + } + + return EOF; +} + +abc_io_t abc_io_file = +{ + .proto = "file://", + + .open = __file_open, + .close = __file_close, + + .popc = __file_popc, +}; diff --git a/html/abc_io_http.c b/html/abc_io_http.c new file mode 100644 index 0000000..8e29160 --- /dev/null +++ b/html/abc_io_http.c @@ -0,0 +1,355 @@ +#include"abc_html.h" + +typedef struct { + scf_string_t* host; + scf_string_t* uri; + + scf_string_t* rbuf; + scf_string_t* wbuf; + int rpos; + int wpos; + + int fd; + int epfd; + + int content_length; + + int exit; + pthread_t tid; + pthread_mutex_t mutex; + pthread_cond_t cond; +} abc_http_t; + +static void http_parse_head(abc_http_t* http) +{ + char* p0 = http->rbuf->data; + char* p1 = p0; + char* end = p0 + http->rpos; + + scf_logi("rbuf->len: %ld, http->rpos: %d\n", http->rbuf->len, http->rpos); + + while (p1 < end) { + if (strncmp(p1, "\r\n", 2)) { + p1++; + continue; + } + + size_t n = strlen("Content-Length: "); + + if (!strncmp(p0, "Content-Length: ", n)) { + http->content_length = atoi(p0 + n); + + scf_logi("Content-Length: %d\n", http->content_length); + break; + } + + p1 += 2; + p0 = p1; + } +} + +static void* http_thread(void* arg) +{ + abc_html_t* html = arg; + abc_http_t* http = html->io.priv; + + while (!http->exit) { + struct epoll_event ev; + + int ret = epoll_wait(http->epfd, &ev, 1, 50); + if (ret < 0) { + scf_loge("epoll_wait error: %d\n", -errno); + break; + } else if (0 == ret) { + continue; + } + + if (ev.events & EPOLLIN) { + while (1) { + uint8_t buf[4096]; + + ret = read(http->fd, buf, 4096); + if (ret < 0) { + if (EAGAIN == errno) + break; + else if (EINTR == errno) + continue; + + scf_loge("\n"); + goto error; + } + + pthread_mutex_lock(&http->mutex); + ret = scf_string_cat_cstr_len(http->rbuf, buf, ret); + if (ret < 0) { + scf_loge("\n"); + pthread_mutex_unlock(&http->mutex); + goto error; + } + + if (0 == http->rpos) { + int i; + for (i = 0; i < http->rbuf->len; i++) { + + if (!strncmp(http->rbuf->data + i, "\r\n\r\n", 4)) { + http->rpos = i + 4; + + http_parse_head(http); + break; + } + } + } + + if (http->content_length >= http->rbuf->len - http->rpos) + html->download = 1; + + pthread_mutex_unlock(&http->mutex); + } + } + + if (ev.events & EPOLLOUT) { + pthread_mutex_lock(&http->mutex); + if (0 == http->wpos) { + html->download = 0; + http->rbuf->len = 0; + http->rpos = 0; + } + + while (http->wpos < http->wbuf->len) { + + ret = write(http->fd, http->wbuf->data + http->wpos, http->wbuf->len - http->wpos); + if (ret < 0) { + if (EAGAIN == errno) + break; + else if (EINTR == errno) + continue; + + scf_loge("\n"); + pthread_mutex_unlock(&http->mutex); + goto error; + } + scf_logi("ret: %d, http->wpos: %d, http->wbuf->len: %ld\n", ret, http->wpos, http->wbuf->len); + + http->wpos += ret; + } + pthread_mutex_unlock(&http->mutex); + } + } + +error: + pthread_mutex_lock(&http->mutex); + http->tid = -1; + pthread_mutex_unlock(&http->mutex); + return 0; +} + +static void abc_http_close(abc_http_t* http) +{ + if (!http) + return; + + pthread_mutex_lock(&http->mutex); + http->exit = 1; + + while (-1 != http->tid) + pthread_cond_wait(&http->cond, &http->mutex); + pthread_mutex_unlock(&http->mutex); + + close(http->fd); + close(http->epfd); + + if (http->host) + scf_string_free(http->host); + + if (http->uri) + scf_string_free(http->uri); + + if (http->rbuf) + scf_string_free(http->rbuf); + + if (http->wbuf) + scf_string_free(http->wbuf); + + free(http); +} + +static int __http_parse(abc_http_t* http, const char* path) +{ + const char* p; + + for (p = path; *p; p++) { + if ('/' == *p) + break; + } + + http->host = scf_string_cstr_len(path, (size_t)(p - path)); + if (!http->host) + return -ENOMEM; + + if ('\0' == *p) + http->uri = scf_string_cstr("/"); + else + http->uri = scf_string_cstr(p); + + if (!http->uri) { + scf_string_free(http->host); + http->host = NULL; + return -ENOMEM; + } + + return 0; +} + +static int __http_open(abc_html_t* html, const char* path) +{ + if (!html || !path) + return -EINVAL; + + scf_logw("\n"); + + abc_http_t* http = calloc(1, sizeof(abc_http_t)); + if (!http) + return -ENOMEM; + + int ret = __http_parse(http, path); + if (ret < 0) { + free(http); + return ret; + } + + http->fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (http->fd < 0) { + free(http); + return -errno; + } + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, "/tmp/abc.sock", sizeof(addr.sun_path) - 1); + + ret = connect(http->fd, (struct sockaddr*)&addr, sizeof(addr)); + if (ret < 0) { + close(http->fd); + free(http); + return -errno; + } + + ret = fcntl(http->fd, F_GETFL); + ret |= O_NONBLOCK; + fcntl(http->fd, F_SETFL, ret); + + http->epfd = epoll_create(1); + if (http->epfd < 0) { + close(http->fd); + free(http); + return -errno; + } + + struct epoll_event ev; + ev.events = EPOLLIN | EPOLLOUT | EPOLLET | EPOLLRDHUP; + ev.data.ptr = http; + + ret = epoll_ctl(http->epfd, EPOLL_CTL_ADD, http->fd, &ev); + if (ret < 0) { + close(http->fd); + free(http); + return -errno; + } + + pthread_mutex_init(&http->mutex, NULL); + pthread_cond_init (&http->cond, NULL); + + http->tid = -1; + + http->rbuf = scf_string_alloc(); + if (!http->rbuf) { + abc_http_close(http); + return -ENOMEM; + } + + http->wbuf = scf_string_alloc(); + if (!http->wbuf) { + abc_http_close(http); + return -ENOMEM; + } + +#define ABC_HTTP_FILL(str) \ + do { \ + ret = scf_string_cat_cstr(http->wbuf, str); \ + if (ret < 0) { \ + abc_http_close(http); \ + return ret; \ + } \ + } while (0) + + ABC_HTTP_FILL("GET "); + ABC_HTTP_FILL(http->uri->data); + ABC_HTTP_FILL(" HTTP/1.1\r\n"); + + ABC_HTTP_FILL("Host: "); + ABC_HTTP_FILL(http->host->data); + ABC_HTTP_FILL("\r\n"); + + ABC_HTTP_FILL("User-Agent: advanced-browser-core\r\n"); + ABC_HTTP_FILL("Accept: */*\r\n"); + ABC_HTTP_FILL("\r\n"); + + html->io.priv = http; + + if (pthread_create(&http->tid, NULL, http_thread, html)) { + abc_http_close(http); + html->io.priv = NULL; + return -1; + } + + scf_logw("\n"); + return 0; +} + +static void __http_close(abc_html_t* html) +{ + if (html) + abc_http_close(html->io.priv); +} + +static int __http_popc(abc_html_t* html) +{ + abc_http_t* http; + + if (html) { + http = html->io.priv; + + if (http) { + int c; + + pthread_mutex_lock(&http->mutex); + assert(http->rpos > 0); + + if (http->rpos < http->rbuf->len) + c = http->rbuf->data[http->rpos++]; + else + c = EOF; + pthread_mutex_unlock(&http->mutex); + return c; + } + } + + return EOF; +} + +static int __http_post(abc_html_t* html) +{ + scf_loge("\n"); + return -1; +} + +abc_io_t abc_io_http = +{ + .proto = "http://", + + .open = __http_open, + .close = __http_close, + + .popc = __http_popc, + .post = __http_post, +}; diff --git a/html/main.c b/html/main.c index b8459d1..ff8a438 100644 --- a/html/main.c +++ b/html/main.c @@ -14,6 +14,9 @@ int main(int argc, char* argv[]) return -1; } + while (!html->download) + usleep(50 * 1000); + if (abc_html_parse(html) < 0) { scf_loge("\n"); return -1; diff --git a/net/config b/net/config new file mode 100644 index 0000000..068cf57 --- /dev/null +++ b/net/config @@ -0,0 +1,4 @@ +ngx_addon_name=ngx_http_abc_module +HTTP_MODULES="$HTTP_MODULES ngx_http_abc_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_abc_module.c" +NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/ngx_http_abc.h" diff --git a/net/ngx_http_abc.h b/net/ngx_http_abc.h new file mode 100644 index 0000000..01aabf8 --- /dev/null +++ b/net/ngx_http_abc.h @@ -0,0 +1,10 @@ +#ifndef NGX_HTTP_ABC_H +#define NGX_HTTP_ABC_H + +#include +#include +#include + +extern ngx_module_t ngx_http_abc_module; + +#endif diff --git a/net/ngx_http_abc_module.c b/net/ngx_http_abc_module.c new file mode 100644 index 0000000..2040d51 --- /dev/null +++ b/net/ngx_http_abc_module.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include "ngx_http_abc.h" + +static ngx_int_t ngx_http_abc_handler(ngx_http_request_t *r) +{ + printf("%s(),%d\n", __func__, __LINE__); + + ngx_chain_t out; + ngx_buf_t* b; + ngx_int_t rc; + + if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_POST))) + return NGX_HTTP_NOT_ALLOWED; + + rc = ngx_http_discard_request_body(r); + if (NGX_OK != rc) + return rc; + + ngx_str_t type = ngx_string("text/html"); + ngx_str_t body = ngx_string("hello

hello world

"); + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = body.len; + r->headers_out.content_type = type; + + rc = ngx_http_send_header(r); + + printf("%s(),%d, rc: %ld\n", __func__, __LINE__, rc); + + if (NGX_ERROR == rc || rc > NGX_OK || r->header_only) + return rc; + + b = ngx_create_temp_buf(r->pool, body.len); + if (!b) + return NGX_HTTP_INTERNAL_SERVER_ERROR; + + ngx_memcpy(b->pos, body.data, body.len); + + b->last = b->pos + body.len; + b->last_buf = 1; + + out.buf = b; + out.next = NULL; + + return ngx_http_output_filter(r, &out); +} + +static char* ngx_http_abc(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + printf("%s(),%d\n", __func__, __LINE__); + ngx_http_core_loc_conf_t* clcf; + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + clcf->handler = ngx_http_abc_handler; + + return NGX_CONF_OK; +} + +static ngx_command_t ngx_http_abc_commands[] = +{ + { + ngx_string("abc"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS, + ngx_http_abc, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, + + ngx_null_command +}; + +static ngx_http_module_t ngx_http_abc_module_ctx = +{ + NULL, /* pre configuration */ + NULL, /* post configuration */ + + NULL, + NULL, + + NULL, + NULL, + + NULL, + NULL, +}; + +ngx_module_t ngx_http_abc_module = +{ + NGX_MODULE_V1, + &ngx_http_abc_module_ctx, /* module context */ + ngx_http_abc_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; diff --git a/ui/Makefile b/ui/Makefile index a83c489..73e0508 100644 --- a/ui/Makefile +++ b/ui/Makefile @@ -30,6 +30,8 @@ CFILES += abc_render_input.c CFILES += ../html/abc_html.c CFILES += ../html/abc_html_util.c CFILES += ../html/abc_obj.c +CFILES += ../html/abc_io_file.c +CFILES += ../html/abc_io_http.c CFILES += ../ffmpeg/abc_ffmpeg_img.c @@ -46,6 +48,7 @@ LDFLAGS += -lavformat -lavcodec -lavfilter -lavutil LDFLAGS += -lm LDFLAGS += -lGL LDFLAGS += `pkg-config --libs gtk+-3.0` +LDFLAGS += -pthread all: gcc $(CFLAGS) $(CFILES) $(LDFLAGS) diff --git a/ui/main.c b/ui/main.c index 8e1f68e..a0c7804 100644 --- a/ui/main.c +++ b/ui/main.c @@ -457,6 +457,9 @@ int main(int argc, char *argv[]) return ret; } + while (!html->download) + usleep(50 * 1000); + ret = abc_html_parse(html); if (ret < 0) { scf_loge("\n"); diff --git a/util/scf_def.h b/util/scf_def.h index 55b1def..225e73f 100644 --- a/util/scf_def.h +++ b/util/scf_def.h @@ -13,6 +13,13 @@ #include #include +#include +#include + +#include +#include +#include + #if 1 #include static inline int64_t gettime() -- 2.25.1