HTTP

头文件

#include "mln_http.h"

模块名

http

函数/宏

mln_http_init

mln_http_t *mln_http_init(mln_tcp_conn_t *connection, void *data, mln_http_handler body_handler);

typedef int (*mln_http_handler)(mln_http_t *, mln_chain_t **, mln_chain_t **);

描述:创建并初始化mln_http_t结构。connection是TCP结构,内含TCP套接字。data为体处理函数的用户自定义数据部分,用于辅助请求或响应体的处理。body_handler是体处理函数,如果该指针非NULL,则该函数会在每次调用mln_http_parsemln_http_generate函数时被调用。体处理函数有三个参数,分别为:http结构,用于解析或生成HTTP报文的双向链表的头和尾节点。

返回值:成功则返回mln_http_t结构指针,否则返回NULL

mln_http_destroy

void mln_http_destroy(mln_http_t *http);

描述:销毁http结构并释放资源。

返回值:无

mln_http_reset

void mln_http_reset(mln_http_t *http);

描述:重置http结构,但不会将结构释放,可用于下一次处理。

返回值:无

mln_http_parse

int mln_http_parse(mln_http_t *http, mln_chain_t **in);

描述:用于解析HTTP报文,并将解析的结果写入http中。

返回值:

  • M_HTTP_RET_DONE 解析完成
  • M_HTTP_RET_OK 解析未完成但未出错,继续传入新的数据使解析完成
  • M_HTTP_RET_ERROR 解析失败

mln_http_generate

int mln_http_generate(mln_http_t *http, mln_chain_t **out_head, mln_chain_t **out_tail);

描述:将http中HTTP相关信息生成HTTP报文。报文可能不会一次性生成完全,因此可以多次调用。已生成的报文将会存放在out_headout_tail指定的双向链表中。

返回值:

  • M_HTTP_RET_DONE 生成完成
  • M_HTTP_RET_OK 生成未完成但未出错
  • M_HTTP_RET_ERROR 生成失败

mln_http_field_set

int mln_http_field_set(mln_http_t *http, mln_string_t *key, mln_string_t *val);

描述:设置HTTP头字段。若头字段key存在,则会将val替换原有值。

返回值:

  • M_HTTP_RET_OK 处理成功
  • M_HTTP_RET_ERROR处理失败

mln_http_field_get

mln_string_t *mln_http_field_get(mln_http_t *http, mln_string_t *key);

描述:获取HTTP头字段中键为key的值。

返回值:成功则返回值字符串结构指针,否则返回NULL

mln_http_field_iterator

mln_string_t *mln_http_field_iterator(mln_http_t *http, mln_string_t *key);

描述:每次返回一个键为key的头字段值(即假设存在多个相同键名的头字段)。

返回值:成功则返回值字符串结构指针,否则返回NULL

mln_http_field_remove

void mln_http_field_remove(mln_http_t *http, mln_string_t *key);

描述:移除头字段key及其值。

返回值:无

mln_http_dump

void mln_http_dump(mln_http_t *http);

描述:将HTTP信息输出到标准输出,用于调试之用。

返回值:无

mln_http_connection_get

mln_http_connection_get(h)

描述:获取类型为mln_http_th中TCP链接结构。

返回值:mln_tcp_conn_t类型指针

mln_http_connection_set

mln_http_connection_set(h,c)

描述:将mln_http_t类型的h中TCP链接结构设置为mln_tcp_conn_t类型的c

返回值:无

mln_http_pool_get

mln_http_pool_get(h)

描述:获取类型为mln_http_th中内存池结构。

返回值:mln_alloc_t类型指针

mln_http_pool_set

mln_http_pool_set(h,p)

描述:将mln_http_t类型的h中内存池设置为mln_alloc_t类型的p

返回值:无

mln_http_data_get

mln_http_data_get(h)

描述:获取类型为mln_http_th中辅助体处理函数的用户自定义数据。

返回值:用户自定义数据指针

mln_http_data_set

mln_http_data_set(h,d)

描述:将mln_http_t类型的h中辅助体处理函数的用户自定义数据设置为d

返回值:无

mln_http_uri_get

mln_http_uri_get(h)

描述:获取类型为mln_http_th中URI字符串。

返回值:mln_string_t类型指针

mln_http_uri_set

mln_http_uri_set(h,u)

描述:将mln_http_t类型的h中URI设置为mln_string_t类型指针的u

返回值:无

mln_http_args_get

mln_http_args_get(h)

描述:获取类型为mln_http_th中参数字符串。

返回值:mln_string_t类型指针

mln_http_args_set

mln_http_args_set(h,a)

描述:将mln_http_t类型的h中参数设置为mln_string_t类型指针的a

返回值:无

mln_http_status_get

mln_http_status_get(h)

描述:获取类型为mln_http_th中响应状态字,例如200 400等。

返回值:整型状态字

mln_http_status_set

mln_http_status_set(h,s)

描述:将mln_http_t类型的h中响应状态字设置为整型的s

返回值:无

mln_http_method_get

mln_http_method_get(h)

描述:获取类型为mln_http_th中方法字段

返回值:

  • M_HTTP_GET
  • M_HTTP_POST
  • M_HTTP_HEAD
  • M_HTTP_PUT
  • M_HTTP_DELETE
  • M_HTTP_TRACE
  • M_HTTP_CONNECT
  • M_HTTP_OPTIONS

mln_http_method_set

mln_http_method_set(h,m)

描述:将mln_http_t类型的h中请求方法设置为mm的可用值参考mln_http_get_method的返回值部分。

返回值:无

mln_http_version_get

mln_http_version_get(h)

描述:获取类型为mln_http_th中HTTP版本

返回值:

  • M_HTTP_VERSION_1_0 HTTP 1.0
  • M_HTTP_VERSION_1_1 HTTP 1.1

mln_http_version_set

mln_http_version_set(h,v)

描述:将mln_http_t类型的h中的HTTP版本号为vv的取值参考mln_http_version_get的返回值。

返回值:无

mln_http_type_get

mln_http_type_get(h)

描述:获取类型为mln_http_th中HTTP类型,即请求还是响应。

返回值:

  • M_HTTP_UNKNOWN未知类型
  • M_HTTP_REQUEST请求
  • M_HTTP_RESPONSE响应

mln_http_type_set

mln_http_type_set(h,t)

描述:将mln_http_t类型的h中报文类型设置为tt的取值参考mln_http_type_get的返回值。

返回值:无

mln_http_handler_get

mln_http_handler_get(h)

描述:获取类型为mln_http_th中体处理函数指针。

返回值:类型为mln_http_handler的函数指针

mln_http_handler_set

mln_http_handler_set(h,hlr)

描述:将mln_http_t类型的h中提处理函数设置为mln_http_handler类型的hlr

返回值:无

mln_http_response_msg_get

mln_http_response_msg_get(h)

描述:获取类型为mln_http_th中响应信息,即类似:Bad Request 或 Internal Server Error等字符串。

返回值:mln_string_t类型指针

mln_http_response_msg_set

mln_http_response_msg_set(h,m)

描述:将mln_http_t类型的h中响应信息设置为mln_string_t类型指针的m

返回值:无

mln_http_error_get

mln_http_error_get(h)

#define M_HTTP_CONTINUE                        100
#define M_HTTP_SWITCHING_PROTOCOLS             101
#define M_HTTP_PROCESSING                      102
#define M_HTTP_OK                              200
#define M_HTTP_CREATED                         201
#define M_HTTP_ACCEPTED                        202
#define M_HTTP_NON_AUTHORITATIVE_INFORMATION   203
#define M_HTTP_NO_CONTENT                      204
#define M_HTTP_RESET_CONTENT                   205
#define M_HTTP_PARTIAL_CONTENT                 206
#define M_HTTP_MULTI_STATUS                    207
#define M_HTTP_MULTIPLE_CHOICES                300
#define M_HTTP_MOVED_PERMANENTLY               301
#define M_HTTP_MOVED_TEMPORARILY               302
#define M_HTTP_SEE_OTHER                       303
#define M_HTTP_NOT_MODIFIED                    304
#define M_HTTP_USE_PROXY                       305
#define M_HTTP_SWITCH_PROXY                    306
#define M_HTTP_TEMPORARY_REDIRECT              307
#define M_HTTP_BAD_REQUEST                     400
#define M_HTTP_UNAUTHORIZED                    401
#define M_HTTP_PAYMENT_REQUIRED                402
#define M_HTTP_FORBIDDEN                       403
#define M_HTTP_NOT_FOUND                       404
#define M_HTTP_METHOD_NOT_ALLOWED              405
#define M_HTTP_NOT_ACCEPTABLE                  406
#define M_HTTP_PROXY_AUTHENTICATION_REQUIRED   407
#define M_HTTP_REQUEST_TIMEOUT                 408
#define M_HTTP_CONFLICT                        409
#define M_HTTP_GONE                            410
#define M_HTTP_LENGTH_REQUIRED                 411
#define M_HTTP_PRECONDITION_FAILED             412
#define M_HTTP_REQUEST_ENTITY_TOO_LARGE        413
#define M_HTTP_REQUEST_URI_TOO_LARGE           414
#define M_HTTP_UNSUPPORTED_MEDIA_TYPE          415
#define M_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE 416
#define M_HTTP_EXPECTATION_FAILED              417
#define M_HTTP_TOO_MANY_CONNECTIONS            421
#define M_HTTP_UNPROCESSABLE_ENTITY            422
#define M_HTTP_LOCKED                          423
#define M_HTTP_FAILED_DEPENDENCY               424
#define M_HTTP_UNORDERED_COLLECTION            425
#define M_HTTP_UPGRADE_REQUIRED                426
#define M_HTTP_RETRY_WITH                      449
#define M_HTTP_INTERNAL_SERVER_ERROR           500
#define M_HTTP_NOT_IMPLEMENTED                 501
#define M_HTTP_BAD_GATEWAY                     502
#define M_HTTP_SERVICE_UNAVAILABLE             503
#define M_HTTP_GATEWAY_TIMEOUT                 504
#define M_HTTP_VERSION_NOT_SUPPORTED           505
#define M_HTTP_VARIANT_ALSO_NEGOTIATES         506
#define M_HTTP_INSUFFICIENT_STORAGE            507
#define M_HTTP_BANDWIDTH_LIMIT_EXCEEDED        509
#define M_HTTP_NOT_EXTENDED                    510
#define M_HTTP_UNPARSEABLE_RESPONSE_HEADERS    600

描述:获取类型为mln_http_th中错误信息。

返回值:宏定义的错误值

mln_http_error_set

mln_http_error_set(h,e)

描述:将mln_http_t类型的h中错误信息设置为ee的取值参见mln_http_error_get中的宏定义。

返回值:无

mln_http_header_get

mln_http_header_get(h)

描述:获取类型为mln_http_th中头字段结构。

返回值:mln_hash_t类型结构

示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include "mln_framework.h"
#include "mln_log.h"
#include "mln_http.h"
#include "mln_file.h"


static void mln_accept(mln_event_t *ev, int fd, void *data);
static int mln_http_recv_body_handler(mln_http_t *http, mln_chain_t **in, mln_chain_t **nil);
static void mln_recv(mln_event_t *ev, int fd, void *data);
static void mln_quit(mln_event_t *ev, int fd, void *data);
static void mln_send(mln_event_t *ev, int fd, void *data);
static int mln_http_send_body_handler(mln_http_t *http, mln_chain_t **body_head, mln_chain_t **body_tail);

static void worker_process(mln_event_t *ev)
{
    mln_u16_t port = 1234;
    mln_s8_t ip[] = "0.0.0.0";
    struct sockaddr_in addr;
    int val = 1;
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0) {
        mln_log(error, "listen socket error\n");
        return;
    }
    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
        mln_log(error, "setsockopt error\n");
        close(listenfd);
        return;
    }
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip);
    if (bind(listenfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        mln_log(error, "bind error\n");
        close(listenfd);
        return;
    }
    if (listen(listenfd, 511) < 0) {
        mln_log(error, "listen error\n");
        close(listenfd);
        return;
    }

    if (mln_event_fd_set(ev, \
                         listenfd, \
                         M_EV_RECV|M_EV_NONBLOCK, \
                         M_EV_UNLIMITED, \
                         NULL, \
                         mln_accept) < 0)
    {
        mln_log(error, "listen sock set event error\n");
        close(listenfd);
        return;
    }
}

static void mln_accept(mln_event_t *ev, int fd, void *data)
{
    mln_tcp_conn_t *connection;
    mln_http_t *http;
    int connfd;
    socklen_t len;
    struct sockaddr_in addr;

    while (1) {
        memset(&addr, 0, sizeof(addr));
        len = sizeof(addr);
        connfd = accept(fd, (struct sockaddr *)&addr, &len);
        if (connfd < 0) {
            if (errno == EAGAIN) break;
            if (errno == EINTR) continue;
            perror("accept");
            exit(1);
        }

        connection = (mln_tcp_conn_t *)malloc(sizeof(mln_tcp_conn_t));
        if (connection == NULL) {
            fprintf(stderr, "3No memory.\n");
            close(connfd);
            continue;
        }
        if (mln_tcp_conn_init(connection, connfd) < 0) {
            fprintf(stderr, "4No memory.\n");
            close(connfd);
            free(connection);
            continue;
        }

        http = mln_http_init(connection, NULL, mln_http_recv_body_handler);
        if (http == NULL) {
            fprintf(stderr, "5No memory.\n");
            mln_tcp_conn_destroy(connection);
            free(connection);
            close(connfd);
            continue;
        }

        if (mln_event_fd_set(ev, \
                             connfd, \
                             M_EV_RECV|M_EV_NONBLOCK, \
                             M_EV_UNLIMITED, \
                             http, \
                             mln_recv) < 0)
        {
            fprintf(stderr, "6No memory.\n");
            mln_http_destroy(http);
            mln_tcp_conn_destroy(connection);
            free(connection);
            close(connfd);
            continue;
        }
    }
}

static void mln_quit(mln_event_t *ev, int fd, void *data)
{
    mln_http_t *http = (mln_http_t *)data;
    mln_tcp_conn_t *connection = mln_http_connection_get(http);

    mln_event_fd_set(ev, fd, M_EV_CLR, M_EV_UNLIMITED, NULL, NULL);
    mln_http_destroy(http);
    mln_tcp_conn_destroy(connection);
    free(connection);
    close(fd);
}

static void mln_recv(mln_event_t *ev, int fd, void *data)
{
    mln_http_t *http = (mln_http_t *)data;
    mln_tcp_conn_t *connection = mln_http_connection_get(http);
    int ret, rc;
    mln_chain_t *c;

    while (1) {
        ret = mln_tcp_conn_recv(connection, M_C_TYPE_MEMORY);
        if (ret == M_C_FINISH) {
            continue;
        } else if (ret == M_C_NOTYET) {
            c = mln_tcp_conn_remove(connection, M_C_RECV);
            if (c != NULL) {
                rc = mln_http_parse(http, &c);
                if (c != NULL) {
                    mln_tcp_conn_append_chain(connection, c, NULL, M_C_RECV);
                }
                if (rc == M_HTTP_RET_OK) {
                    return;
                } else if (rc == M_HTTP_RET_DONE) {
                    mln_send(ev, fd, data);
                } else {
                    fprintf(stderr, "Http parse error. error_code:%u\n", mln_http_error_get(http));
                    mln_quit(ev, fd, data);
                    return;
                }
            }
            break;
        } else if (ret == M_C_CLOSED) {
            c = mln_tcp_conn_remove(connection, M_C_RECV);
            if (c != NULL) {
                rc = mln_http_parse(http, &c);
                if (c != NULL) {
                    mln_tcp_conn_append_chain(connection, c, NULL, M_C_RECV);
                }
                if (rc == M_HTTP_RET_ERROR) {
                    fprintf(stderr, "Http parse error. error_code:%u\n", mln_http_error_get(http));
                }
            }
            mln_quit(ev, fd, data);
            return;
        } else if (ret == M_C_ERROR) {
            mln_quit(ev, fd, data);
            return;
        }
    }
}

static int mln_http_recv_body_handler(mln_http_t *http, mln_chain_t **in, mln_chain_t **nil)
{
    mln_u32_t method = mln_http_method_get(http);
    if (method == M_HTTP_GET)
        return M_HTTP_RET_DONE;
    mln_http_error_set(http, M_HTTP_NOT_IMPLEMENTED);
    return M_HTTP_RET_ERROR;
}

static void mln_send(mln_event_t *ev, int fd, void *data)
{
    mln_http_t *http = (mln_http_t *)data;
    mln_tcp_conn_t *connection = mln_http_connection_get(http);
    mln_chain_t *c = mln_tcp_conn_head(connection, M_C_SEND);
    int ret;

    if (c == NULL) {
        mln_http_reset(http);
        mln_http_status_set(http, M_HTTP_OK);
        mln_http_version_set(http, M_HTTP_VERSION_1_0);
        mln_http_type_set(http, M_HTTP_RESPONSE);
        mln_http_handler_set(http, mln_http_send_body_handler);
        mln_chain_t *body_head = NULL, *body_tail = NULL;
        if (mln_http_generate(http, &body_head, &body_tail) == M_HTTP_RET_ERROR) {
            fprintf(stderr, "mln_http_generate() failed. %u\n", mln_http_error_get(http));
            mln_quit(ev, fd, data);
            return;
        }
        mln_tcp_conn_append_chain(connection, body_head, body_tail, M_C_SEND);
    }

    while ((c = mln_tcp_conn_head(connection, M_C_SEND)) != NULL) {
        ret = mln_tcp_conn_send(connection);
        if (ret == M_C_FINISH) {
            mln_quit(ev, fd, data);
            break;
        } else if (ret == M_C_NOTYET) {
            mln_chain_pool_release_all(mln_tcp_conn_remove(connection, M_C_SENT));
            mln_event_fd_set(ev, fd, M_EV_SEND|M_EV_APPEND|M_EV_NONBLOCK, M_EV_UNLIMITED, data, mln_send);
            return;
        } else if (ret == M_C_ERROR) {
            mln_quit(ev, fd, data);
            return;
        } else {
            fprintf(stderr, "Shouldn't be here.\n");
            abort();
        }
    }
}

static int mln_http_send_body_handler(mln_http_t *http, mln_chain_t **body_head, mln_chain_t **body_tail)
{
    mln_u8ptr_t buf;
    mln_alloc_t *pool = mln_http_pool_get(http);
    mln_string_t cttype_key = mln_string("Content-Type");
    mln_string_t cttype_val = mln_string("text/html");

    buf = mln_alloc_m(pool, 5);
    if (buf == NULL) {
        mln_http_error_set(http, M_HTTP_INTERNAL_SERVER_ERROR);
        return M_HTTP_RET_ERROR;
    }
    memcpy(buf, "hello", 5);

    if (mln_http_field_set(http, &cttype_key, &cttype_val) == M_HTTP_RET_ERROR) {
        mln_http_error_set(http, M_HTTP_INTERNAL_SERVER_ERROR);
        return M_HTTP_RET_ERROR;
    }

    mln_string_t ctlen_key = mln_string("Content-Length");
    mln_string_t ctlen_val = mln_string("5");
    if (mln_http_field_set(http, &ctlen_key, &ctlen_val) == M_HTTP_RET_ERROR) {
        mln_http_error_set(http, M_HTTP_INTERNAL_SERVER_ERROR);
        return M_HTTP_RET_ERROR;
    }

    mln_chain_t *c = mln_chain_new(pool);
    if (c == NULL) {
        mln_http_error_set(http, M_HTTP_INTERNAL_SERVER_ERROR);
        return M_HTTP_RET_ERROR;
    }
    mln_buf_t *b = mln_buf_new(pool);
    if (b == NULL) {
        mln_chain_pool_release(c);
        mln_http_error_set(http, M_HTTP_INTERNAL_SERVER_ERROR);
        return M_HTTP_RET_ERROR;
    }
    c->buf = b;
    b->left_pos = b->pos = b->start = buf;
    b->last = b->end = buf + 5;
    b->in_memory = 1;
    b->last_buf = 1;
    b->last_in_chain = 1;

    if (*body_head == NULL) {
        *body_head = *body_tail = c;
    } else {
        (*body_tail)->next = c;
        *body_tail = c;
    }

    return M_HTTP_RET_DONE;
}

int main(int argc, char *argv[])
{
    struct mln_framework_attr cattr;

    cattr.argc = argc;
    cattr.argv = argv;
    cattr.global_init = NULL;
    cattr.main_thread = NULL;
    cattr.master_process = NULL;
    cattr.worker_process = worker_process;
    return mln_framework_init(&cattr);
}

results matching ""

    No results matching ""