/* * 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 #include #include #include #include #include #include #include #define PIDFN "/tmp/fakehttp.pid" int serve(const char *, const char *); void putcrlf(int, char *); 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; }