HTTP
Header file
#include "mln_http.h"
Module
http
Functions/Macros
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 **);
Description: Create and initialize the mln_http_t structure. connection is a TCP structure, which contains a TCP socket. data is the user-defined data part of the body processing function, which is used to assist the processing of the request or response body. body_handler is the body handler function, which is called every time the mln_http_parse or mln_http_generate function is called if it is not NULL. The body processing function has three parameters: http structure, the head and tail nodes of the doubly linked list used to parse or generate HTTP packets.
Return value: return mln_http_t structure pointer if successful, otherwise return NULL
mln_http_destroy
void mln_http_destroy(mln_http_t *http);
Description: Destroy the http structure and free resources.
Return value: none
mln_http_reset
void mln_http_reset(mln_http_t *http);
Description: Resets the http structure, but does not free the structure for the next processing.
Return value: none
mln_http_parse
int mln_http_parse(mln_http_t *http, mln_chain_t **in);
Description: Used to parse HTTP packets and write the parsed results into
http.return value:
M_HTTP_RET_DONEparsing completedM_HTTP_RET_OKparsing is not completed but no error occurs, continue to pass in new data to complete the parsingM_HTTP_RET_ERRORparsing failed
mln_http_generate
int mln_http_generate(mln_http_t *http, mln_chain_t **out_head, mln_chain_t **out_tail);
Description: Generate HTTP messages from HTTP related information in http. The message may not be generated all at once, so it can be called multiple times. The generated packets will be stored in the doubly linked list specified by out_head and out_tail.
return value:
M_HTTP_RET_DONEgeneration completeM_HTTP_RET_OKgeneration did not complete without errorsM_HTTP_RET_ERRORfailed to generate
mln_http_field_set
int mln_http_field_set(mln_http_t *http, mln_string_t *key, mln_string_t *val);
Description: Set the HTTP header field. If the header field key exists, val will be replaced with the original value.
return value:
M_HTTP_RET_OKis processed successfullyM_HTTP_RET_ERRORprocessing failed
mln_http_field_get
mln_string_t *mln_http_field_get(mln_http_t *http, mln_string_t *key);
Description: Get the value of the key key in the HTTP header field.
Return value: return value string structure pointer if successful, otherwise return NULL
mln_http_field_iterator
mln_string_t *mln_http_field_iterator(mln_http_t *http, mln_string_t *key);
Description: Returns a header field value with key key each time (that is, assuming that there are multiple header fields with the same key name).
Return value: return value string structure pointer if successful, otherwise return NULL
mln_http_field_remove
void mln_http_field_remove(mln_http_t *http, mln_string_t *key);
Description: Remove header field key and its value.
Return value: none
mln_http_dump
void mln_http_dump(mln_http_t *http);
Description: Print HTTP messages to standard output for debugging purposes.
Return value: none
mln_http_connection_get
mln_http_connection_get(h)
Description: Get the TCP link structure in h of type mln_http_t.
Return value: mln_tcp_conn_t type pointer
mln_http_connection_set
mln_http_connection_set(h,c)
Description: Set the TCP connection structure in h of type mln_http_t to c of type mln_tcp_conn_t.
Return value: none
mln_http_pool_get
mln_http_pool_get(h)
Description: Get the memory pool structure in h of type mln_http_t.
Return value: pointer of type mln_alloc_t
mln_http_pool_set
mln_http_pool_set(h,p)
Description: Set the memory pool in h of type mln_http_t to p of type mln_alloc_t.
Return value: none
mln_http_data_get
mln_http_data_get(h)
Description: Get the user-defined data of the auxiliary body handler function in h of type mln_http_t.
Return value: user-defined data pointer
mln_http_data_set
mln_http_data_set(h,d)
Description: Set the user-defined data of the auxiliary body handler in h of type mln_http_t to d.
Return value: none
mln_http_uri_get
mln_http_uri_get(h)
Description: Get the URI string in h of type mln_http_t.
Return value: pointer of type mln_string_t
mln_http_uri_set
mln_http_uri_set(h,u)
Description: Set the URI in h of type mln_http_t to u of pointer of type mln_string_t.
Return value: none
mln_http_args_get
mln_http_args_get(h)
Description: Get the parameter string in h of type mln_http_t.
Return value: pointer of type mln_string_t
mln_http_args_set
mln_http_args_set(h,a)
Description: Set the parameter in h of type mln_http_t to a of type pointer of mln_string_t.
Return value: none
mln_http_status_get
mln_http_status_get(h)
Description: Get the response status word in h of type mln_http_t, such as 200 400, etc.
Return value: Integer status word
mln_http_status_set
mln_http_status_set(h,s)
Description: Set the response status word in h of type mln_http_t to s of type integer.
Return value: none
mln_http_method_get
mln_http_method_get(h)
Description: Get the method field in h of type mln_http_t
return value:
M_HTTP_GETM_HTTP_POSTM_HTTP_HEADM_HTTP_PUTM_HTTP_DELETEM_HTTP_TRACEM_HTTP_CONNECTM_HTTP_OPTIONS
mln_http_set_method
mln_http_set_method(h,m)
Description: Set the request method in h of type mln_http_t to m. For the available values of m, refer to the return value section of mln_http_get_method.
Return value: none
mln_http_version_get
mln_http_version_get(h)
Description: Get the HTTP version in h of type mln_http_t
return value:
M_HTTP_VERSION_1_0HTTP 1.0M_HTTP_VERSION_1_1HTTP 1.1
mln_http_version_set
mln_http_version_set(h,v)
Description: Set the HTTP version number in h of type mln_http_t to v, and refer to the return value of mln_http_version_get for the value of v.
Return value: none
mln_http_type_get
mln_http_type_get(h)
Description: Get the HTTP type in h of type mln_http_t, that is, request or response.
return value:
M_HTTP_UNKNOWNunknown typeM_HTTP_REQUESTrequestM_HTTP_RESPONSEresponse
mln_http_type_set
mln_http_type_set(h,t)
Description: Set the packet type in h of type mln_http_t to t. The value of t refers to the return value of mln_http_type_get.
Return value: none
mln_http_handler_get
mln_http_handler_get(h)
Description: Get the h body handler pointer of type mln_http_t.
Return value: function pointer of type mln_http_handler
mln_http_handler_set
mln_http_handler_set(h,hlr)
Description: Set the h handler function of type mln_http_t to hlr of type mln_http_handler.
Return value: none
mln_http_response_msg_get
mln_http_response_msg_get(h)
Description: Get the response information in h of type mln_http_t, that is, strings like: Bad Request or Internal Server Error.
Return value: pointer of type mln_string_t
mln_http_response_msg_set
mln_http_response_msg_set(h,m)
Description: Set the response information in h of type mln_http_t to m of type mln_string_t pointer.
Return value: none
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
Description: Get error information in h of type mln_http_t.
Return value: the error value defined by the macro
mln_http_error_set
mln_http_error_set(h,e)
Description: Set the error message in h of type mln_http_t to e. For the value of e, see the macro definition in mln_http_error_get.
Return value: none
mln_http_header_get
mln_http_header_get(h)
Description: Get the header field structure in h of type mln_http_t.
Return value: mln_hash_t type structure
Example
#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);
}