43 #include <event2/buffer.h>
44 #include "qlibc/qlibc.h"
50 static ad_http_t *http_new(
struct evbuffer *out);
52 static void http_free_cb(
ad_conn_t *conn,
void *userdata);
53 static size_t http_add_inbuf(
struct evbuffer *buffer,
ad_http_t *http,
56 static int http_parser(
ad_http_t *http,
struct evbuffer *in);
57 static int parse_requestline(
ad_http_t *http,
char *line);
58 static int parse_headers(
ad_http_t *http,
struct evbuffer *in);
59 static int parse_body(
ad_http_t *http,
struct evbuffer *in);
60 static ssize_t parse_chunked_body(
ad_http_t *http,
struct evbuffer *in);
62 static bool isValidPathname(
const char *path);
63 static void correctPathname(
char *path);
64 static char *evbuffer_peekln(
struct evbuffer *buffer,
size_t *n_read_out,
65 enum evbuffer_eol_style eol_style);
66 static ssize_t evbuffer_drainln(
struct evbuffer *buffer,
size_t *n_read_out,
67 enum evbuffer_eol_style eol_style);
86 DEBUG(
"==> HTTP INIT");
93 DEBUG(
"==> HTTP READ");
95 int status = http_parser(http, conn->
in);
101 DEBUG(
"==> HTTP WRITE");
104 DEBUG(
"==> HTTP CLOSE=%x (TIMEOUT=%d, SHUTDOWN=%d)",
161 size_t inbuflen = evbuffer_get_length(http->
request.
inbuf);
164 inbuflen : ((inbuflen < maxsize) ? inbuflen : maxsize);
168 void *data = malloc(readlen);
172 size_t removedlen = evbuffer_remove(http->
request.
inbuf, data, readlen);
174 *storedsize = removedlen;
193 if (connection != NULL && !strcmp(connection,
"close")) {
199 if (connection != NULL
200 && (!strcmp(connection,
"Keep-Alive")
201 || !strcmp(connection,
"TE"))) {
275 conn,
"Content-Type",
278 char clenval[20 + 1];
279 sprintf(clenval,
"%jd", size);
294 const void *data, off_t size) {
333 bzero((
void*) &obj,
sizeof(obj));
336 while (tbl->getnext(tbl, &obj, NULL,
false)) {
338 (
char*) obj.name, (
char*) obj.data);
356 WARN(
"Content-Length is not set. Invalid usage.");
361 WARN(
"Trying to send more data than supposed to");
370 if (data != NULL && size > 0) {
383 WARN(
"Content-Length is set. Invalid usage.");
404 WARN(
"Failed to add data to out-buffer. (size:%jd)", size);
408 size_t bytesout = evbuffer_get_length(http->
response.
outbuf) - beforesize;
424 return "Partial Content";
426 return "Multi Status";
428 return "Moved Temporarily";
430 return "Not Modified";
432 return "Bad Request";
434 return "Authorization Required";
440 return "Method Not Allowed";
442 return "Request Time Out";
446 return "Request URI Too Long";
450 return "Internal Server Error";
452 return "Not Implemented";
454 return "Service Unavailable";
457 WARN(
"Undefined code found. %d", code);
464 #ifndef _DOXYGEN_SKIP
466 static ad_http_t *http_new(
struct evbuffer *out) {
475 QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
477 QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
524 static void http_free_cb(
ad_conn_t *conn,
void *userdata) {
528 static size_t http_add_inbuf(
struct evbuffer *buffer,
ad_http_t *http,
530 if (maxsize == 0 || evbuffer_get_length(buffer) == 0) {
534 return evbuffer_remove_buffer(buffer, http->
request.
inbuf, maxsize);
537 static int http_parser(
ad_http_t *http,
struct evbuffer *in) {
538 ASSERT(http != NULL && in != NULL);
541 char *line = evbuffer_readln(in, NULL, EVBUFFER_EOL_CRLF);
580 static int parse_requestline(
ad_http_t *http,
char *line) {
583 char *method = strtok_r(line,
" ", &saveptr);
584 char *uri = strtok_r(NULL,
" ", &saveptr);
585 char *httpver = strtok_r(NULL,
" ", &saveptr);
586 char *tmp = strtok_r(NULL,
" ", &saveptr);
588 if (method == NULL || uri == NULL || httpver == NULL || tmp != NULL) {
589 DEBUG(
"Invalid request line. %s", line);
608 }
else if ((tmp = strstr(uri,
"://"))) {
610 char *path = strstr(tmp + CONST_STRLEN(
"://"),
"/");
613 tmp + CONST_STRLEN(
"://"));
618 tmp + CONST_STRLEN(
"://"));
623 DEBUG(
"Invalid URI format. %s", uri);
639 if (isValidPathname(http->
request.
path) ==
false) {
640 DEBUG(
"Invalid URI format : %s", http->
request.
uri);
650 static int parse_headers(
ad_http_t *http,
struct evbuffer *in) {
652 while ((line = evbuffer_readln(in, NULL, EVBUFFER_EOL_CRLF))) {
653 if (IS_EMPTY_STR(line)) {
662 char *tmp = strstr(line,
":");
665 name = qstrtrim(line);
666 value = qstrtrim(tmp + 1);
668 name = qstrtrim(line);
680 static int parse_body(
ad_http_t *http,
struct evbuffer *in) {
687 if (maxread > 0 && evbuffer_get_length(in) > 0) {
698 if (tranenc != NULL && !strcmp(tranenc,
"chunked")) {
701 ssize_t chunksize = parse_chunked_body(http, in);
704 }
else if (chunksize == 0) {
706 }
else if (chunksize == -1) {
725 static ssize_t parse_chunked_body(
ad_http_t *http,
struct evbuffer *in) {
728 char *line = evbuffer_peekln(in, &crlf_len, EVBUFFER_EOL_CRLF);
731 size_t linelen = strlen(line);
735 sscanf(line,
"%x", &chunksize);
741 size_t datalen = linelen + crlf_len + chunksize + crlf_len;
742 size_t inbuflen = evbuffer_get_length(in);
743 if (inbuflen < datalen) {
748 evbuffer_drainln(in, NULL, EVBUFFER_EOL_CRLF);
749 http_add_inbuf(in, http, chunksize);
750 evbuffer_drainln(in, NULL, EVBUFFER_EOL_CRLF);
758 static bool isValidPathname(
const char *path) {
762 int len = strlen(path);
763 if (len == 0 || len >= PATH_MAX)
765 else if (path[0] !=
'/')
767 else if (strpbrk(path,
"\\:*?\"<>|") != NULL)
773 for (n = 0, t = (
char *) path; *t !=
'\0'; t++) {
778 if (n >= FILENAME_MAX) {
779 DEBUG(
"Filename too long.");
794 static void correctPathname(
char *path) {
799 while (strstr(path,
"//") != NULL)
800 qstrreplace(
"sr", path,
"//",
"/");
803 int len = strlen(path);
806 if (path[len - 1] ==
'/')
807 path[len - 1] =
'\0';
810 static char *evbuffer_peekln(
struct evbuffer *buffer,
size_t *n_read_out,
811 enum evbuffer_eol_style eol_style) {
813 struct evbuffer_ptr ptr = evbuffer_search_eol(buffer, NULL, n_read_out,
818 char *line = (
char *) malloc(ptr.pos + 1);
824 char *bufferptr = (
char *) evbuffer_pullup(buffer, ptr.pos);
825 ASSERT(bufferptr != NULL);
826 strncpy(line, bufferptr, ptr.pos);
828 line[ptr.pos] =
'\0';
833 static ssize_t evbuffer_drainln(
struct evbuffer *buffer,
size_t *n_read_out,
834 enum evbuffer_eol_style eol_style) {
835 char *line = evbuffer_readln(buffer, n_read_out, eol_style);
839 size_t linelen = strlen(line);
844 #endif // _DOXYGEN_SKIP
#define HTTP_CODE_BAD_REQUEST
#define HTTP_CODE_UNAUTHORIZED
#define HTTP_CODE_MULTI_STATUS
#define HTTP_CODE_CREATED
#define HTTP_CODE_REQUEST_URI_TOO_LONG
size_t ad_http_response(ad_conn_t *conn, int code, const char *contenttype, const void *data, off_t size)
#define HTTP_CODE_SERVICE_UNAVAILABLE
#define HTTP_CODE_REQUEST_TIME_OUT
void * ad_http_get_content(ad_conn_t *conn, size_t maxsize, size_t *storedsize)
Remove content from the in-buffer.
const char * ad_http_get_response_header(ad_conn_t *conn, const char *name)
Get response header.
int ad_http_is_keepalive_request(ad_conn_t *conn)
Return whether the request is keep-alive request or not.
#define HTTP_CODE_NO_CONTENT
#define AD_EVENT_SHUTDOWN
struct ad_http_s::@1 response
const char * ad_http_get_request_header(ad_conn_t *conn, const char *name)
Get request header.
int ad_http_handler(short event, ad_conn_t *conn, void *userdata)
HTTP protocol handler hook.
int ad_http_set_response_content(ad_conn_t *conn, const char *contenttype, off_t size)
enum ad_http_request_status_e status
#define HTTP_CODE_FORBIDDEN
char * ad_conn_set_method(ad_conn_t *conn, char *method)
Set method name on this connection.
const char * ad_http_get_reason(int code)
#define HTTP_CODE_PARTIAL_CONTENT
#define AD_EVENT_INIT
Event types.
#define HTTP_CODE_NOT_MODIFIED
size_t ad_http_send_chunk(ad_conn_t *conn, const void *data, size_t size)
struct evbuffer * ad_http_get_outbuf(ad_conn_t *conn)
#define HTTP_DEF_CONTENTTYPE
ad_http_handler header file
#define HTTP_CODE_NOT_FOUND
void * ad_conn_set_extra(ad_conn_t *conn, const void *extra, ad_userdata_free_cb free_cb)
Set extra userdata into the connection.
#define HTTP_CODE_METHOD_NOT_ALLOWED
int ad_http_set_response_code(ad_conn_t *conn, int code, const char *reason)
enum ad_http_request_status_e ad_http_get_status(ad_conn_t *conn)
Return the request status.
struct evbuffer * ad_http_get_inbuf(ad_conn_t *conn)
size_t ad_http_send_header(ad_conn_t *conn)
#define HTTP_CODE_CONTINUE
int ad_http_set_response_header(ad_conn_t *conn, const char *name, const char *value)
Set response header.
#define HTTP_CODE_INTERNAL_SERVER_ERROR
size_t ad_http_send_data(ad_conn_t *conn, const void *data, size_t size)
#define HTTP_CODE_NOT_IMPLEMENTED
void * ad_conn_get_extra(ad_conn_t *conn)
Get extra userdata attached in this connection.
off_t ad_http_get_content_length(ad_conn_t *conn)
Return the size of content from the request.
#define HTTP_CODE_MOVED_TEMPORARILY
struct ad_http_s::@0 request