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)
#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};
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;
}
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);
}
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;
}
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
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;
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);
abc_char_t* __html_pop_char(abc_html_t* html)
{
assert(html);
- assert(html->fp);
abc_char_t* c;
if (!c)
return NULL;
- int ret = fgetc(html->fp);
+ int ret = html->io.popc(html);
if (EOF == ret) {
c->c = ret;
return c;
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;
--- /dev/null
+#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,
+};
--- /dev/null
+#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,
+};
return -1;
}
+ while (!html->download)
+ usleep(50 * 1000);
+
if (abc_html_parse(html) < 0) {
scf_loge("\n");
return -1;
--- /dev/null
+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"
--- /dev/null
+#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
--- /dev/null
+#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
+};
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
LDFLAGS += -lm
LDFLAGS += -lGL
LDFLAGS += `pkg-config --libs gtk+-3.0`
+LDFLAGS += -pthread
all:
gcc $(CFLAGS) $(CFILES) $(LDFLAGS)
return ret;
}
+ while (!html->download)
+ usleep(50 * 1000);
+
ret = abc_html_parse(html);
if (ret < 0) {
scf_loge("\n");
#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()