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