1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
/* fakehttp - A fake HTTP server used by the nmh test suite
*
* This code is Copyright (c) 2014, by the authors of nmh. See the
* COPYRIGHT file in the root directory of the nmh distribution for
* complete copyright information.
*/
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "server.h"
#define PIDFN "/tmp/fakehttp.pid"
static void
strip_cr(char *buf, ssize_t *len)
{
ssize_t src, dst;
for (src = dst = 0; src < *len; src++) {
buf[dst] = buf[src];
if (buf[src] != '\r') {
dst++;
}
}
*len -= src - dst;
}
static void
save_req(int conn, FILE *req)
{
char buf[BUFSIZ];
ssize_t r;
int e; /* used to save errno */
int started = 0; /* whether the request has started coming in */
if (fcntl(conn, F_SETFL, O_NONBLOCK) < 0) {
fprintf(stderr, "Unable to make socket non-blocking: %s\n",
strerror(errno));
exit(1);
}
for (;;) {
r = read(conn, buf, sizeof buf);
if (!started) {
/* First keep trying until some data is ready; for testing, don't
* bother with using select to wait for input. */
if (r < 0) {
e = errno;
if (e == EAGAIN || e == EWOULDBLOCK) {
continue; /* keep waiting */
}
fclose(req);
fprintf(stderr, "Unable to read socket: %s\n", strerror(e));
exit(1);
}
/* Request is here. Fall through to the fwrite below and keep
* reading. */
started = 1;
}
if (r < 0) {
e = errno;
putc('\n', req); /* req body usually has no newline */
fclose(req);
if (e != EAGAIN && e != EWOULDBLOCK) {
fprintf(stderr, "Unable to read socket: %s\n", strerror(e));
exit(1);
}
/* For testing, we can get away without understand the HTTP request
* and just treating the would-block case as meaning the request is
* all done. */
return;
}
strip_cr(buf, &r);
fwrite(buf, 1, r, req);
}
}
static void
send_res(int conn, FILE *res)
{
size_t size;
ssize_t len;
char *res_line = NULL;
while ((len = getline(&res_line, &size, res)) > 0) {
res_line[len - 1] = '\0';
putcrlf(conn, res_line);
}
free(res_line);
if (!feof(res)) {
fprintf(stderr, "read response failed: %s\n", strerror(errno));
exit(1);
}
}
int
main(int argc, char *argv[])
{
struct st;
int conn;
FILE *req, *res;
if (argc != 4) {
fprintf(stderr, "Usage: %s output-filename port response\n",
argv[0]);
exit(1);
}
if (!(req = fopen(argv[1], "w"))) {
fprintf(stderr, "Unable to open output file \"%s\": %s\n",
argv[1], strerror(errno));
exit(1);
}
if (!(res = fopen(argv[3], "r"))) {
fprintf(stderr, "Unable to open response \"%s\": %s\n",
argv[3], strerror(errno));
exit(1);
}
conn = serve(PIDFN, argv[2]);
save_req(conn, req);
send_res(conn, res);
close(conn);
return 0;
}
|