add a simpile HTTP support for AF_UNIX
authoryu.dongliang <18588496441@163.com>
Sat, 2 Nov 2024 13:09:06 +0000 (21:09 +0800)
committeryu.dongliang <18588496441@163.com>
Sat, 2 Nov 2024 13:09:06 +0000 (21:09 +0800)
13 files changed:
html/Makefile
html/abc_html.c
html/abc_html.h
html/abc_html_util.c
html/abc_io_file.c [new file with mode: 0644]
html/abc_io_http.c [new file with mode: 0644]
html/main.c
net/config [new file with mode: 0644]
net/ngx_http_abc.h [new file with mode: 0644]
net/ngx_http_abc_module.c [new file with mode: 0644]
ui/Makefile
ui/main.c
util/scf_def.h

index 2e9a348121bdefad6f3407d95f935d528a4afb74..fe589e279f434bd5c5e25829309bbc41615073b5 100644 (file)
@@ -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)
index 346de8713231b2421b39aa4ed805f0b67c70677f..82afe9384dfb9cc7da27570fe711aa6092d7f100 100644 (file)
@@ -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;
                }
index c335f486583c4f15366e659463656fb3f7bea01c..48aa1674e1d7db6d0483ee3140768a4d33dc4f03 100644 (file)
@@ -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);
index 5053387050d61bffd959382dec0c830ace430b02..011c3779aa772c565aaa415466e5a31f53a01a3d 100644 (file)
@@ -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 (file)
index 0000000..16afbbd
--- /dev/null
@@ -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 (file)
index 0000000..8e29160
--- /dev/null
@@ -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,
+};
index b8459d1ecc7f313686a7add07b18d000541fbfb4..ff8a43890abf8264b29a11620f6a3cce58730b5c 100644 (file)
@@ -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 (file)
index 0000000..068cf57
--- /dev/null
@@ -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 (file)
index 0000000..01aabf8
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef NGX_HTTP_ABC_H
+#define NGX_HTTP_ABC_H
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+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 (file)
index 0000000..2040d51
--- /dev/null
@@ -0,0 +1,105 @@
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+#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("<html><head><title>hello</title></head><body><h1>hello world</h1></body></html>");
+
+       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
+};
index a83c489154cdc8b12b5fdd9d08daca41f5db941f..73e05081390488db3e89ab5604b8426fafc3b25d 100644 (file)
@@ -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)
index 8e1f68e165cd2c831217e16cffeb7390862e4cc7..a0c7804d64f50368d02c242955b1256faa66e7d1 100644 (file)
--- 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");
index 55b1def0cdce3471b7196b3eb26fe0e2d2d573b7..225e73fbfd391fe866b049c15016a80acaaee722 100644 (file)
 #include<limits.h>
 #include<math.h>
 
+#include<fcntl.h>
+#include<pthread.h>
+
+#include<sys/epoll.h>
+#include<sys/socket.h>
+#include<sys/un.h>
+
 #if 1
 #include<sys/time.h>
 static inline int64_t gettime()