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)",
175 size_t inbuflen = evbuffer_get_length(http->
request.
inbuf);
178 inbuflen : ((inbuflen < maxsize) ? inbuflen : maxsize);
182 void *data = malloc(readlen + 1);
186 size_t removedlen = evbuffer_remove(http->
request.
inbuf, data, readlen);
187 ((
char*)data)[removedlen] =
'\0';
189 *storedsize = removedlen;
208 if (connection != NULL && !strcmp(connection,
"close")) {
214 if (connection != NULL
215 && (!strcmp(connection,
"Keep-Alive")
216 || !strcmp(connection,
"TE"))) {
290 conn,
"Content-Type",
293 char clenval[20 + 1];
294 sprintf(clenval,
"%jd", size);
309 const void *data, off_t size) {
348 bzero((
void*) &obj,
sizeof(obj));
351 while (tbl->getnext(tbl, &obj, NULL,
false)) {
353 (
char*) obj.name, (
char*) obj.data);
371 WARN(
"Content-Length is not set. Invalid usage.");
376 WARN(
"Trying to send more data than supposed to");
385 if (data != NULL && size > 0) {
398 WARN(
"Content-Length is set. Invalid usage.");
419 WARN(
"Failed to add data to out-buffer. (size:%jd)", size);
423 size_t bytesout = evbuffer_get_length(http->
response.
outbuf) - beforesize;
439 return "Partial Content";
441 return "Multi Status";
443 return "Moved Temporarily";
445 return "Not Modified";
447 return "Bad Request";
449 return "Authorization Required";
455 return "Method Not Allowed";
457 return "Request Time Out";
461 return "Request URI Too Long";
465 return "Internal Server Error";
467 return "Not Implemented";
469 return "Service Unavailable";
472 WARN(
"Undefined code found. %d", code);
479 #ifndef _DOXYGEN_SKIP
481 static ad_http_t *http_new(
struct evbuffer *out) {
490 QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
492 QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
539 static void http_free_cb(
ad_conn_t *conn,
void *userdata) {
543 static size_t http_add_inbuf(
struct evbuffer *buffer,
ad_http_t *http,
545 if (maxsize == 0 || evbuffer_get_length(buffer) == 0) {
549 return evbuffer_remove_buffer(buffer, http->
request.
inbuf, maxsize);
552 static int http_parser(
ad_http_t *http,
struct evbuffer *in) {
553 ASSERT(http != NULL && in != NULL);
556 char *line = evbuffer_readln(in, NULL, EVBUFFER_EOL_CRLF);
595 static int parse_requestline(
ad_http_t *http,
char *line) {
598 char *method = strtok_r(line,
" ", &saveptr);
599 char *uri = strtok_r(NULL,
" ", &saveptr);
600 char *httpver = strtok_r(NULL,
" ", &saveptr);
601 char *tmp = strtok_r(NULL,
" ", &saveptr);
603 if (method == NULL || uri == NULL || httpver == NULL || tmp != NULL) {
604 DEBUG(
"Invalid request line. %s", line);
623 }
else if ((tmp = strstr(uri,
"://"))) {
625 char *path = strstr(tmp + CONST_STRLEN(
"://"),
"/");
628 tmp + CONST_STRLEN(
"://"));
633 tmp + CONST_STRLEN(
"://"));
638 DEBUG(
"Invalid URI format. %s", uri);
654 if (isValidPathname(http->
request.
path) ==
false) {
655 DEBUG(
"Invalid URI format : %s", http->
request.
uri);
665 static int parse_headers(
ad_http_t *http,
struct evbuffer *in) {
667 while ((line = evbuffer_readln(in, NULL, EVBUFFER_EOL_CRLF))) {
668 if (IS_EMPTY_STR(line)) {
677 char *tmp = strstr(line,
":");
680 name = qstrtrim(line);
681 value = qstrtrim(tmp + 1);
683 name = qstrtrim(line);
695 static int parse_body(
ad_http_t *http,
struct evbuffer *in) {
702 if (maxread > 0 && evbuffer_get_length(in) > 0) {
713 if (tranenc != NULL && !strcmp(tranenc,
"chunked")) {
716 ssize_t chunksize = parse_chunked_body(http, in);
719 }
else if (chunksize == 0) {
721 }
else if (chunksize == -1) {
740 static ssize_t parse_chunked_body(
ad_http_t *http,
struct evbuffer *in) {
743 char *line = evbuffer_peekln(in, &crlf_len, EVBUFFER_EOL_CRLF);
746 size_t linelen = strlen(line);
750 sscanf(line,
"%x", &chunksize);
756 size_t datalen = linelen + crlf_len + chunksize + crlf_len;
757 size_t inbuflen = evbuffer_get_length(in);
758 if (inbuflen < datalen) {
763 evbuffer_drainln(in, NULL, EVBUFFER_EOL_CRLF);
764 http_add_inbuf(in, http, chunksize);
765 evbuffer_drainln(in, NULL, EVBUFFER_EOL_CRLF);
773 static bool isValidPathname(
const char *path) {
777 int len = strlen(path);
778 if (len == 0 || len >= PATH_MAX)
780 else if (path[0] !=
'/')
782 else if (strpbrk(path,
"\\:*?\"<>|") != NULL)
788 for (n = 0, t = (
char *) path; *t !=
'\0'; t++) {
793 if (n >= FILENAME_MAX) {
794 DEBUG(
"Filename too long.");
809 static void correctPathname(
char *path) {
814 while (strstr(path,
"//") != NULL)
815 qstrreplace(
"sr", path,
"//",
"/");
818 int len = strlen(path);
821 if (path[len - 1] ==
'/')
822 path[len - 1] =
'\0';
825 static char *evbuffer_peekln(
struct evbuffer *buffer,
size_t *n_read_out,
826 enum evbuffer_eol_style eol_style) {
828 struct evbuffer_ptr ptr = evbuffer_search_eol(buffer, NULL, n_read_out,
833 char *line = (
char *) malloc(ptr.pos + 1);
839 char *bufferptr = (
char *) evbuffer_pullup(buffer, ptr.pos);
840 ASSERT(bufferptr != NULL);
841 strncpy(line, bufferptr, ptr.pos);
843 line[ptr.pos] =
'\0';
848 static ssize_t evbuffer_drainln(
struct evbuffer *buffer,
size_t *n_read_out,
849 enum evbuffer_eol_style eol_style) {
850 char *line = evbuffer_readln(buffer, n_read_out, eol_style);
854 size_t linelen = strlen(line);
859 #endif // _DOXYGEN_SKIP
void ad_conn_set_method(ad_conn_t *conn, char *method)
Set method name on this connection.
#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.
size_t ad_http_get_content_length_stored(ad_conn_t *conn)
Return the actual size of data stored in 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
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