9 #include <event2/buffer.h>
10 #include "qlibc/qlibc.h"
22 static ad_http_t *http_new(
struct evbuffer *out);
24 static void http_free_cb(
ad_conn_t *conn,
void *userdata);
25 static size_t http_add_inbuf(
struct evbuffer *buffer,
ad_http_t *http,
size_t maxsize);
27 static int http_parser(
ad_http_t *http,
struct evbuffer *in);
28 static int parse_requestline(
ad_http_t *http,
char *line);
29 static int parse_headers(
ad_http_t *http,
struct evbuffer *in);
30 static int parse_body(
ad_http_t *http,
struct evbuffer *in);
31 static ssize_t parse_chunked_body(
ad_http_t *http,
struct evbuffer *in);
33 static bool isValidPathname(
const char *path);
34 static void correctPathname(
char *path);
35 static char *evbuffer_peekln(
struct evbuffer *buffer,
size_t *n_read_out,
enum evbuffer_eol_style eol_style);
36 static ssize_t evbuffer_drainln(
struct evbuffer *buffer,
size_t *n_read_out,
enum evbuffer_eol_style eol_style);
55 DEBUG(
"==> HTTP INIT");
61 DEBUG(
"==> HTTP READ");
63 int status = http_parser(http, conn->
in);
69 DEBUG(
"==> HTTP WRITE");
72 DEBUG(
"==> HTTP CLOSE=%x (TIMEOUT=%d, SHUTDOWN=%d)",
115 size_t inbuflen = evbuffer_get_length(http->
request.
inbuf);
116 size_t readlen = (maxsize == 0) ? inbuflen : ((inbuflen < maxsize) ? inbuflen : maxsize);
117 if (readlen == 0)
return NULL;
119 void *data = malloc(readlen);
120 if (data == NULL)
return NULL;
122 size_t removedlen = evbuffer_remove(http->
request.
inbuf, data, readlen);
123 if (storedsize) *storedsize = removedlen;
178 sprintf(clenval,
"%jd", size);
219 bzero((
void*)&obj,
sizeof(obj));
222 while(tbl->getnext(tbl, &obj, NULL,
false)) {
241 WARN(
"Content-Length is not set. Invalid usage.");
246 WARN(
"Trying to send more data than supposed to");
255 if (data != NULL && size > 0) {
267 WARN(
"Content-Length is set. Invalid usage.");
285 WARN(
"Failed to add data to out-buffer. (size:%jd)", size);
289 size_t bytesout = evbuffer_get_length(http->
response.
outbuf) - beforesize;
318 WARN(
"Undefined code found. %d", code);
327 #ifndef _DOXYGEN_SKIP
329 static ad_http_t *http_new(
struct evbuffer *out) {
332 if (http == NULL)
return NULL;
336 http->
request.
headers = qlisttbl(QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
337 http->
response.
headers = qlisttbl(QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
372 static void http_free_cb(
ad_conn_t *conn,
void *userdata) {
376 static size_t http_add_inbuf(
struct evbuffer *buffer,
ad_http_t *http,
size_t maxsize) {
377 if (maxsize == 0 || evbuffer_get_length(buffer) == 0) {
381 return evbuffer_remove_buffer(buffer, http->
request.
inbuf, maxsize);
384 static int http_parser(
ad_http_t *http,
struct evbuffer *in) {
385 ASSERT(http != NULL && in != NULL);
388 char *line = evbuffer_readln(in, NULL, EVBUFFER_EOL_CRLF);
427 static int parse_requestline(
ad_http_t *http,
char *line) {
430 char *method = strtok_r(line,
" ", &saveptr);
431 char *uri = strtok_r(NULL,
" ", &saveptr);
432 char *httpver = strtok_r(NULL,
" ", &saveptr);
433 char *tmp = strtok_r(NULL,
" ", &saveptr);
435 if (method == NULL || uri == NULL || httpver == NULL || tmp != NULL) {
436 DEBUG(
"Invalid request line. %s", line);
456 }
else if ((tmp = strstr(uri,
"://"))) {
458 char *path = strstr(tmp + CONST_STRLEN(
"://"),
"/");
469 DEBUG(
"Invalid URI format. %s", uri);
485 if (isValidPathname(http->
request.
path) ==
false) {
486 DEBUG(
"Invalid URI format : %s", http->
request.
uri);
496 static int parse_headers(
ad_http_t *http,
struct evbuffer *in) {
498 while ((line = evbuffer_readln(in, NULL, EVBUFFER_EOL_CRLF))) {
499 if (IS_EMPTY_STR(line)) {
506 char *tmp = strstr(line,
":");
509 name = qstrtrim(line);
510 value = qstrtrim(tmp + 1);
512 name = qstrtrim(line);
524 static int parse_body(
ad_http_t *http,
struct evbuffer *in) {
531 if (maxread > 0 && evbuffer_get_length(in) > 0) {
541 if (tranenc != NULL && !strcmp(tranenc,
"chunked")) {
544 ssize_t chunksize = parse_chunked_body(http, in);
547 }
else if (chunksize == 0) {
549 }
else if (chunksize == -1) {
568 static ssize_t parse_chunked_body(
ad_http_t *http,
struct evbuffer *in) {
571 char *line = evbuffer_peekln(in, &crlf_len, EVBUFFER_EOL_CRLF);
572 if (line == NULL)
return -1;
573 size_t linelen = strlen(line);
577 sscanf(line,
"%x", &chunksize);
579 if (chunksize < 0)
return -2;
582 size_t datalen = linelen + crlf_len + chunksize + crlf_len;
583 size_t inbuflen = evbuffer_get_length(in);
584 if (inbuflen < datalen) {
589 evbuffer_drainln(in, NULL, EVBUFFER_EOL_CRLF);
590 http_add_inbuf(in, http, chunksize);
591 evbuffer_drainln(in, NULL, EVBUFFER_EOL_CRLF);
599 static bool isValidPathname(
const char *path) {
600 if (path == NULL)
return false;
602 int len = strlen(path);
603 if (len == 0 || len >= PATH_MAX)
return false;
604 else if (path[0] !=
'/')
return false;
605 else if (strpbrk(path,
"\\:*?\"<>|") != NULL)
return false;
610 for (n = 0, t = (
char *)path; *t !=
'\0'; t++) {
615 if (n >= FILENAME_MAX) {
616 DEBUG(
"Filename too long.");
631 static void correctPathname(
char *path) {
636 while (strstr(path,
"//") != NULL) qstrreplace(
"sr", path,
"//",
"/");
639 int len = strlen(path);
640 if (len <= 1)
return;
641 if (path[len - 1] ==
'/') path[len - 1] =
'\0';
644 static char *evbuffer_peekln(
struct evbuffer *buffer,
size_t *n_read_out,
enum evbuffer_eol_style eol_style) {
646 struct evbuffer_ptr ptr = evbuffer_search_eol(buffer, NULL, n_read_out, eol_style);
647 if (ptr.pos == -1)
return NULL;
649 char *line = (
char *)malloc(ptr.pos + 1);
650 if (line == NULL)
return NULL;
654 char *bufferptr = (
char *)evbuffer_pullup(buffer, ptr.pos);
655 ASSERT(bufferptr != NULL);
656 strncpy(line, bufferptr, ptr.pos);
658 line[ptr.pos] =
'\0';
663 static ssize_t evbuffer_drainln(
struct evbuffer *buffer,
size_t *n_read_out,
enum evbuffer_eol_style eol_style) {
664 char *line = evbuffer_readln(buffer, n_read_out, eol_style);
665 if (line == NULL)
return -1;
667 size_t linelen = strlen(line);