Handle file requests
This commit is contained in:
parent
5c21a0a8e2
commit
06d92b3d25
78
main.c
78
main.c
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -31,9 +32,13 @@
|
|||||||
#define HOST "::1"
|
#define HOST "::1"
|
||||||
#define PORT 7070
|
#define PORT 7070
|
||||||
|
|
||||||
|
#define RESP_TERM ".\r\n"
|
||||||
|
#define RESP_TERM_LEN 3 /* strlen(".\r\n") */
|
||||||
|
|
||||||
#define PBUF_SIZE 1024
|
#define PBUF_SIZE 1024
|
||||||
#define RBUF_SIZE 1024
|
#define RBUF_SIZE 1024
|
||||||
#define SBUF_SIZE 1024
|
#define SBUF_SIZE 1024
|
||||||
|
#define FBUF_SIZE 1024
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enumeration of directory entry types.
|
* Enumeration of directory entry types.
|
||||||
@ -87,7 +92,8 @@ int main(int argc, char *argv[])
|
|||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
int res = EXIT_SUCCESS;
|
int res = EXIT_SUCCESS;
|
||||||
static char pbuf[PBUF_SIZE], rbuf[RBUF_SIZE], sbuf[SBUF_SIZE];
|
static char pbuf[PBUF_SIZE], rbuf[RBUF_SIZE], sbuf[SBUF_SIZE],
|
||||||
|
fbuf[FBUF_SIZE];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get srvroot path from arguments and copy into pbuf.
|
* Get srvroot path from arguments and copy into pbuf.
|
||||||
@ -211,7 +217,7 @@ int main(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Construct the full path to the requested resource.
|
* Construct the full path to the requested resource.
|
||||||
*
|
*
|
||||||
* This is needed in order to pass it to stat() and open() or
|
* This is needed in order to pass it to stat() and fopen() or
|
||||||
* opendir() later. It must be null-terminated. We also need
|
* opendir() later. It must be null-terminated. We also need
|
||||||
* to make sure that none of the path's parts are "..", as
|
* to make sure that none of the path's parts are "..", as
|
||||||
* this could be used to escape the srvroot directory.
|
* this could be used to escape the srvroot directory.
|
||||||
@ -254,11 +260,71 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
if (S_ISREG(rstat.st_mode)) {
|
if (S_ISREG(rstat.st_mode)) {
|
||||||
/*
|
/*
|
||||||
* Send hard-coded response for files for now.
|
* Open the file.
|
||||||
|
*
|
||||||
|
* The path is already null-terminated from the earlier call
|
||||||
|
* to stat().
|
||||||
*/
|
*/
|
||||||
const char *resp = "Files don't work yet\r\n.\r\n";
|
FILE *rf;
|
||||||
if (retrying_write(cfd, resp, strlen(resp)) == -1) {
|
do {
|
||||||
fprintf(stderr, "Couldn't write to client socket\n");
|
errno = 0;
|
||||||
|
rf = fopen(pbuf, "r");
|
||||||
|
} while (errno == EINTR);
|
||||||
|
if (rf == NULL) {
|
||||||
|
fprintf(stderr, "Failed to open %s\n", pbuf);
|
||||||
|
goto close_client_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct response in rbuf.
|
||||||
|
*
|
||||||
|
* The response should be the file contents, but with CRLF
|
||||||
|
* line endings instead of just LF. Replacing the line
|
||||||
|
* endings is done with a buffered reading approach to
|
||||||
|
* minimize syscalls (as opposed to using fgetc()).
|
||||||
|
*/
|
||||||
|
unsigned rpos = 0;
|
||||||
|
while (true) {
|
||||||
|
/* Fill fbuf from file. */
|
||||||
|
n = fread(fbuf, sizeof(*fbuf), FBUF_SIZE, rf);
|
||||||
|
if (n != FBUF_SIZE && ferror(rf)) {
|
||||||
|
fprintf(stderr, "Failed to read from file %s\n", pbuf);
|
||||||
|
goto close_client_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy from fbuf to rbuf, replacing LF with CRLF. */
|
||||||
|
for (unsigned fpos = 0; fpos < n; ++fpos) {
|
||||||
|
if (fbuf[fpos] == '\n') {
|
||||||
|
if (RBUF_SIZE - rpos < 2) {
|
||||||
|
fprintf(stderr, "Response buffer is too small");
|
||||||
|
goto close_client_socket;
|
||||||
|
}
|
||||||
|
rbuf[rpos++] = '\r';
|
||||||
|
rbuf[rpos++] = '\n';
|
||||||
|
} else {
|
||||||
|
if (RBUF_SIZE - rpos < 1) {
|
||||||
|
fprintf(stderr, "Response buffer is too small");
|
||||||
|
goto close_client_socket;
|
||||||
|
}
|
||||||
|
rbuf[rpos++] = fbuf[fpos];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (feof(rf))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Terminate and send the response.
|
||||||
|
*/
|
||||||
|
if (RBUF_SIZE - rpos < RESP_TERM_LEN) {
|
||||||
|
fprintf(stderr, "Response buffer is too small");
|
||||||
|
goto close_client_socket;
|
||||||
|
}
|
||||||
|
memcpy(&rbuf[rpos], RESP_TERM, RESP_TERM_LEN);
|
||||||
|
rpos += RESP_TERM_LEN;
|
||||||
|
if (retrying_write(cfd, rbuf, rpos) == -1) {
|
||||||
|
fprintf(stderr, "Failed to write response to client\n");
|
||||||
goto close_client_socket;
|
goto close_client_socket;
|
||||||
}
|
}
|
||||||
} else if (S_ISDIR(rstat.st_mode)) {
|
} else if (S_ISDIR(rstat.st_mode)) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user