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