Added body transmitted directly in the API.
This commit is contained in:
parent
b3bb857f3a
commit
5941a3593a
2 changed files with 97 additions and 22 deletions
96
core/api.c
96
core/api.c
|
@ -19,6 +19,59 @@ pthread_t listen_thread = 0;
|
||||||
|
|
||||||
struct s_list api_list;
|
struct s_list api_list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write two strings on one write.
|
||||||
|
* @param fd file descriptor to write.
|
||||||
|
* @param str1 first string to write.
|
||||||
|
* @param str2 second string to write.
|
||||||
|
*/
|
||||||
|
size_t write_dual(int fd, char *str1, char *str2)
|
||||||
|
{
|
||||||
|
struct iovec iov[2];
|
||||||
|
|
||||||
|
iov[0].iov_base = str1;
|
||||||
|
iov[0].iov_len = strlen(str1);
|
||||||
|
iov[1].iov_base = str2;
|
||||||
|
iov[1].iov_len = strlen(str2);
|
||||||
|
|
||||||
|
return writev(fd, iov, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_all(int fd, struct s_request *req, char *already, size_t alread_size)
|
||||||
|
{
|
||||||
|
char buf[MAX_READ], *p;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
if (alread_size > 0) {
|
||||||
|
p = realloc(req->buf, req->size + alread_size);
|
||||||
|
if (!p) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
req->buf = p;
|
||||||
|
req->size += alread_size;
|
||||||
|
memcpy(req->buf + req->body + req->body_size, already, alread_size);
|
||||||
|
req->body_size += alread_size;
|
||||||
|
}
|
||||||
|
for(;;) {
|
||||||
|
if (socket_read_select4(fd, 5) <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size = read(fd, buf, sizeof buf);
|
||||||
|
if (size <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = realloc(req->buf, req->size + size);
|
||||||
|
if (!p) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
req->buf = p;
|
||||||
|
req->size += size;
|
||||||
|
memcpy(req->buf + req->body + req->body_size, buf, size);
|
||||||
|
req->body_size += size;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pthread to take care of each client connection.
|
* Pthread to take care of each client connection.
|
||||||
* @param ptr is the connection index in api_list, integer not pointer, cast required.
|
* @param ptr is the connection index in api_list, integer not pointer, cast required.
|
||||||
|
@ -28,9 +81,10 @@ void *api_connection_thread (void *ptr)
|
||||||
{
|
{
|
||||||
int timeout, s, r;
|
int timeout, s, r;
|
||||||
const INT_TYPE i = (INT_TYPE) ptr;
|
const INT_TYPE i = (INT_TYPE) ptr;
|
||||||
char buf[MAX_READ+1], *p;
|
char buf[MAX_READ+1], *p, *body;
|
||||||
char client[INET_ADDRSTRLEN];
|
char client[INET_ADDRSTRLEN];
|
||||||
struct s_request req;
|
struct s_request req;
|
||||||
|
int (*read_func)(int, struct s_request*, char*, size_t) = read_all;
|
||||||
|
|
||||||
req.buf = NULL; // sanity.
|
req.buf = NULL; // sanity.
|
||||||
|
|
||||||
|
@ -53,6 +107,8 @@ void *api_connection_thread (void *ptr)
|
||||||
p = strstr(buf, "\r\n\r\n");
|
p = strstr(buf, "\r\n\r\n");
|
||||||
|
|
||||||
if (p) {
|
if (p) {
|
||||||
|
body = p + 4;
|
||||||
|
|
||||||
req.size = p - buf + 1;
|
req.size = p - buf + 1;
|
||||||
req.buf = malloc(req.size);
|
req.buf = malloc(req.size);
|
||||||
if (!req.buf) {
|
if (!req.buf) {
|
||||||
|
@ -64,42 +120,58 @@ void *api_connection_thread (void *ptr)
|
||||||
memcpy(req.buf, buf, req.size - 1);
|
memcpy(req.buf, buf, req.size - 1);
|
||||||
req.buf[req.size-1] = '\0';
|
req.buf[req.size-1] = '\0';
|
||||||
|
|
||||||
req.method = req.buf;
|
req.method = 0;
|
||||||
p = strchr(req.method, ' ');
|
p = strchr(req.buf + req.method, ' ');
|
||||||
if (!p) {
|
if (!p) {
|
||||||
write_cstr (s, HTTP_400);
|
write_cstr (s, HTTP_400);
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
*p++ = '\0'; // End of method.
|
*p++ = '\0'; // End of method.
|
||||||
req.path = p;
|
req.path = p - req.buf;
|
||||||
p = strchr(req.path, ' ');
|
p = strchr(p, ' ');
|
||||||
if (!p) {
|
if (!p) {
|
||||||
write_cstr (s, HTTP_400);
|
write_cstr (s, HTTP_400);
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
*p++ = '\0'; // End of path.
|
*p++ = '\0'; // End of path.
|
||||||
req.http_ver = p;
|
req.http_ver = p - req.buf;
|
||||||
p = strchr(req.http_ver, '\r');
|
p = strchr(req.buf + req.http_ver, '\r');
|
||||||
if (!p) {
|
if (!p) {
|
||||||
write_cstr (s, HTTP_400);
|
write_cstr (s, HTTP_400);
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
*p++ = '\0'; // End of http version.
|
*p++ = '\0'; // End of http version.
|
||||||
while (*p == '\r' || *p == '\n') p++;
|
while (*p == '\r' || *p == '\n') p++;
|
||||||
req.header = p;
|
req.header = p - req.buf;
|
||||||
req.body = req.buf + req.size;
|
req.body = req.size;
|
||||||
req.body_size = 0;
|
req.body_size = 0;
|
||||||
|
|
||||||
|
p = strstr(req.buf + req.header, "Transfer-Encoding:");
|
||||||
|
if (p) {
|
||||||
|
p += strlen("Transfer-Encoding:");
|
||||||
|
while(*p == ' ') p++;
|
||||||
|
if (cstrstart(p, "chunked\r\n") || strcmp(p, "chunked")==0) {
|
||||||
|
write_cstr (s, HTTP_501);
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!read_func(s, &req, body, r - (body - buf))) {
|
||||||
|
write_cstr (s, HTTP_500);
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
|
||||||
libp2p_logger_error("api", "method = '%s'\n"
|
libp2p_logger_error("api", "method = '%s'\n"
|
||||||
"path = '%s'\n"
|
"path = '%s'\n"
|
||||||
"http_ver = '%s'\n"
|
"http_ver = '%s'\n"
|
||||||
"header {\n%s\n}\n"
|
"header {\n%s\n}\n"
|
||||||
"body_size = %d\n",
|
"body_size = %d\n",
|
||||||
req.method, req.path, req.http_ver, req.header, req.body_size);
|
req.buf+req.method, req.buf+req.path, req.buf+req.http_ver,
|
||||||
|
req.buf+req.header, req.body_size);
|
||||||
|
|
||||||
if (strcmp(req.method, "GET")==0) {
|
if (strcmp(req.buf + req.method, "GET")==0) {
|
||||||
// just an error message, because it's not used.
|
// just an error message, because it's not used.
|
||||||
write_cstr (s, HTTP_404);
|
write_dual (s, req.buf + req.http_ver, strchr (HTTP_404, ' '));
|
||||||
//} else if (cstrstart(buf, "POST ")) {
|
//} else if (cstrstart(buf, "POST ")) {
|
||||||
// TODO: Handle chunked/gzip/form-data/json POST requests.
|
// TODO: Handle chunked/gzip/form-data/json POST requests.
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,11 @@ struct s_request {
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
char *method;
|
int method;
|
||||||
char *path;
|
int path;
|
||||||
char *http_ver;
|
int http_ver;
|
||||||
char *header;
|
int header;
|
||||||
char *body;
|
int body;
|
||||||
size_t body_size;
|
size_t body_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,18 +39,21 @@ struct s_request {
|
||||||
"Connection: close\r\n\r\n" \
|
"Connection: close\r\n\r\n" \
|
||||||
"400 Bad Request"
|
"400 Bad Request"
|
||||||
|
|
||||||
|
|
||||||
#define HTTP_404 "HTTP/1.1 404 Not Found\r\n" \
|
#define HTTP_404 "HTTP/1.1 404 Not Found\r\n" \
|
||||||
"Content-Type: text/plain; charset=utf-8\r\n" \
|
"Content-Type: text/plain\r\n" \
|
||||||
"X-Content-Type-Options: nosniff\r\n" \
|
"Connection: close\r\n\r\n" \
|
||||||
"Content-Length: 19\r\n\r\n" \
|
"404 page not found"
|
||||||
"404 page not found\n"
|
|
||||||
|
|
||||||
#define HTTP_500 "HTTP/1.1 500 Internal server error\r\n" \
|
#define HTTP_500 "HTTP/1.1 500 Internal server error\r\n" \
|
||||||
"Content-Type: text/plain\r\n" \
|
"Content-Type: text/plain\r\n" \
|
||||||
"Connection: close\r\n\r\n" \
|
"Connection: close\r\n\r\n" \
|
||||||
"500 Internal server error"
|
"500 Internal server error"
|
||||||
|
|
||||||
|
#define HTTP_501 "HTTP/1.1 501 Not Implemented\r\n" \
|
||||||
|
"Content-Type: text/plain\r\n" \
|
||||||
|
"Connection: close\r\n\r\n" \
|
||||||
|
"501 Not Implemented"
|
||||||
|
|
||||||
#define write_cstr(f,s) write(f,s,sizeof(s)-1)
|
#define write_cstr(f,s) write(f,s,sizeof(s)-1)
|
||||||
#define write_str(f,s) write(f,s,strlen(s))
|
#define write_str(f,s) write(f,s,strlen(s))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue