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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
@ -31,9 +32,13 @@
|
||||
#define HOST "::1"
|
||||
#define PORT 7070
|
||||
|
||||
#define RESP_TERM ".\r\n"
|
||||
#define RESP_TERM_LEN 3 /* strlen(".\r\n") */
|
||||
|
||||
#define PBUF_SIZE 1024
|
||||
#define RBUF_SIZE 1024
|
||||
#define SBUF_SIZE 1024
|
||||
#define FBUF_SIZE 1024
|
||||
|
||||
/*
|
||||
* Enumeration of directory entry types.
|
||||
@ -87,7 +92,8 @@ int main(int argc, char *argv[])
|
||||
(void)argv;
|
||||
|
||||
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.
|
||||
@ -211,7 +217,7 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* 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
|
||||
* to make sure that none of the path's parts are "..", as
|
||||
* 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)) {
|
||||
/*
|
||||
* 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";
|
||||
if (retrying_write(cfd, resp, strlen(resp)) == -1) {
|
||||
fprintf(stderr, "Couldn't write to client socket\n");
|
||||
FILE *rf;
|
||||
do {
|
||||
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;
|
||||
}
|
||||
} else if (S_ISDIR(rstat.st_mode)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user