This commit is contained in:
John Jones 2017-07-31 06:43:28 -05:00
commit 45c997cd9a
2 changed files with 97 additions and 22 deletions

View file

@ -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.
} }

View file

@ -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))