|
36 | 36 | #include <arpa/inet.h> |
37 | 37 | #include <sys/wait.h> |
38 | 38 |
|
39 | | -#define DEF_PORT 80 |
40 | | -#define DEF_CONTENT "text/html" |
| 39 | +#define DEF_PORT 80 |
| 40 | +#define DEF_CONTENT "text/html" |
41 | 41 |
|
42 | | -#define WS(c) ( ((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n') ) |
| 42 | +#define WS(c) ( ((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n') ) |
43 | 43 |
|
44 | | -int listen_sock; |
45 | | -char buf[1536]; |
| 44 | +#define errmsg(str) write(STDERR_FILENO, str, sizeof(str) - 1) |
46 | 45 |
|
47 | 46 | char* get_mime_type(char *name) |
48 | 47 | { |
49 | | - char* dot; |
| 48 | + char *dot; |
50 | 49 |
|
51 | 50 | dot = strrchr( name, '.' ); |
52 | 51 | if ( dot == (char*) 0 ) |
53 | | - return "text/plain"; |
| 52 | + return "text/plain"; |
54 | 53 | if ( strcmp( dot, ".html" ) == 0 || strcmp( dot, ".htm" ) == 0 ) |
55 | | - return "text/html"; |
| 54 | + return "text/html"; |
56 | 55 | if ( strcmp( dot, ".jpg" ) == 0 || strcmp( dot, ".jpeg" ) == 0 ) |
57 | | - return "image/jpeg"; |
| 56 | + return "image/jpeg"; |
58 | 57 | if ( strcmp( dot, ".gif" ) == 0 ) |
59 | | - return "image/gif"; |
| 58 | + return "image/gif"; |
60 | 59 | if ( strcmp( dot, ".png" ) == 0 ) |
61 | | - return "image/png"; |
| 60 | + return "image/png"; |
62 | 61 | if ( strcmp( dot, ".css" ) == 0 ) |
63 | | - return "text/css"; |
| 62 | + return "text/css"; |
64 | 63 | if ( strcmp( dot, ".vrml" ) == 0 || strcmp( dot, ".wrl" ) == 0 ) |
65 | | - return "model/vrml"; |
| 64 | + return "model/vrml"; |
66 | 65 | if ( strcmp( dot, ".midi" ) == 0 || strcmp( dot, ".mid" ) == 0 ) |
67 | | - return "audio/midi"; |
| 66 | + return "audio/midi"; |
68 | 67 | return "text/plain"; |
69 | 68 | } |
70 | 69 |
|
71 | 70 | void send_header(int fd, char *ct) |
72 | 71 | { |
73 | | - buf[0] = 0; |
74 | | - sprintf(buf, "HTTP/1.0 200 OK\r\nServer: nanoHTTPd/0.1\r\nDate: Thu Apr 26 15:37:46 GMT 2001\r\nContent-Type: %s\r\n",ct); |
75 | | - write(fd, buf, strlen(buf)); |
| 72 | + char buf[128]; |
| 73 | + |
| 74 | + sprintf(buf, "HTTP/1.0 200 OK\r\nServer: nanoHTTPd/0.1\r\n" |
| 75 | + "Date: Thu Apr 26 15:37:46 GMT 2001\r\n" |
| 76 | + "Content-Type: %s\r\n",ct); |
| 77 | + write(fd, buf, strlen(buf)); |
76 | 78 | } |
77 | 79 |
|
78 | 80 | void send_error(int fd, int errnum, char *str) |
79 | 81 | { |
80 | | - sprintf(buf,"HTTP/1.0 %d %s\r\nContent-type: %s\r\n", errnum, str, DEF_CONTENT); |
81 | | - write(fd, buf, strlen(buf)); |
82 | | - sprintf(buf,"Connection: close\r\nDate: Thu Apr 26 15:37:46 GMT 2001\r\n\r\n%s\r\n",str); |
83 | | - write(fd, buf, strlen(buf)); |
| 82 | + char buf[128]; |
| 83 | + |
| 84 | + sprintf(buf,"HTTP/1.0 %d %s\r\nContent-type: %s\r\n", errnum, str, DEF_CONTENT); |
| 85 | + write(fd, buf, strlen(buf)); |
| 86 | + sprintf(buf,"Connection: close\r\n" |
| 87 | + "Date: Thu Apr 26 15:37:46 GMT 2001\r\n" |
| 88 | + "\r\n%s\r\n", str); |
| 89 | + write(fd, buf, strlen(buf)); |
84 | 90 | } |
85 | 91 |
|
86 | 92 | void process_request(int fd) |
87 | 93 | { |
88 | | - int fin, ret; |
89 | | - off_t size; |
90 | | - char *c, *file, fullpath[PATH_MAX]; |
91 | | - struct stat st; |
92 | | - |
93 | | - ret = read(fd, buf, sizeof(buf)); |
94 | | - |
95 | | - c = buf; |
96 | | - while (*c && !WS(*c) && c < (buf + sizeof(buf))){ |
97 | | - c++; |
98 | | - } |
99 | | - *c = 0; |
100 | | - |
101 | | - if (strcasecmp(buf, "get")){ |
102 | | - send_error(fd, 404, "Method not supported"); |
103 | | - return; |
104 | | - } |
105 | | - |
106 | | - file = ++c; |
107 | | - while (*c && !WS(*c) && c < (buf + sizeof(buf))){ |
108 | | - c++; |
109 | | - } |
110 | | - *c = 0; |
111 | | - |
112 | | - /* TODO : Use strncat when security is the only problem of this server! */ |
113 | | - strcpy(fullpath, _PATH_DOCBASE); |
114 | | - strcat(fullpath, file); |
115 | | - |
116 | | - if (!stat(fullpath, &st) && (st.st_mode & S_IFMT) == S_IFDIR) { |
117 | | - if (file[strlen(fullpath) - 1] != '/'){ |
118 | | - strcat(fullpath, "/"); |
119 | | - } |
120 | | - strcat(fullpath, "index.html"); |
121 | | - } |
122 | | - |
123 | | - fin = open(fullpath, O_RDONLY); |
124 | | - if (fin < 0){ |
125 | | - send_error(fd, 404, "Document (probably) not found"); |
126 | | - return; |
127 | | - } |
128 | | - size = lseek(fin, (off_t)0, SEEK_END); |
129 | | - lseek(fin, (off_t)0, SEEK_SET); |
130 | | - send_header(fd, get_mime_type(fullpath)); |
131 | | - sprintf(buf,"Content-Length: %ld\r\n\r\n", size); |
132 | | - write(fd, buf, strlen(buf)); |
133 | | - |
134 | | - do { |
135 | | - ret = read(fin, buf, sizeof(buf)); |
136 | | - if (ret > 0) |
137 | | - ret = write(fd, buf, ret); |
138 | | - } while (ret == sizeof(buf)); |
139 | | - |
140 | | - close(fin); |
141 | | - |
| 94 | + int fin, ret; |
| 95 | + char *c, *file; |
| 96 | + off_t size; |
| 97 | + struct stat st; |
| 98 | + char fullpath[PATH_MAX]; |
| 99 | + char buf[1536+1]; |
| 100 | + |
| 101 | + if ((ret = read(fd, buf, sizeof(buf)-1)) <= 0) |
| 102 | + return; |
| 103 | + c = buf; |
| 104 | + while (*c && !WS(*c) && (c - buf) < ret) |
| 105 | + c++; |
| 106 | + *c = '\0'; |
| 107 | + |
| 108 | + if (strcasecmp(buf, "get")) { |
| 109 | + send_error(fd, 404, "Method not supported"); |
| 110 | + return; |
| 111 | + } |
| 112 | + |
| 113 | + file = ++c; |
| 114 | + while (*c && !WS(*c) && (c - buf) < ret) |
| 115 | + c++; |
| 116 | + *c = '\0'; |
| 117 | + |
| 118 | + /* TODO : Use strncat when security is the only problem of this server! */ |
| 119 | + strcpy(fullpath, _PATH_DOCBASE); |
| 120 | + strcat(fullpath, file); |
| 121 | + |
| 122 | + if (!stat(fullpath, &st) && (st.st_mode & S_IFMT) == S_IFDIR) { |
| 123 | + if (file[strlen(fullpath) - 1] != '/') |
| 124 | + strcat(fullpath, "/"); |
| 125 | + strcat(fullpath, "index.html"); |
| 126 | + } |
| 127 | + |
| 128 | + fin = open(fullpath, O_RDONLY); |
| 129 | + if (fin < 0) { |
| 130 | + send_error(fd, 404, "Document (probably) not found"); |
| 131 | + return; |
| 132 | + } |
| 133 | + size = lseek(fin, 0, SEEK_END); |
| 134 | + lseek(fin, 0, SEEK_SET); |
| 135 | + send_header(fd, get_mime_type(fullpath)); |
| 136 | + sprintf(buf,"Content-Length: %ld\r\n\r\n", size); |
| 137 | + write(fd, buf, strlen(buf)); |
| 138 | + |
| 139 | + do { |
| 140 | + ret = read(fin, buf, sizeof(buf)); |
| 141 | + if (ret > 0) |
| 142 | + ret = write(fd, buf, ret); |
| 143 | + } while (ret == sizeof(buf)); |
| 144 | + close(fin); |
142 | 145 | } |
143 | 146 |
|
144 | 147 | int main(int argc, char **argv) |
145 | 148 | { |
146 | | - int ret, conn_sock; |
147 | | - struct sockaddr_in localadr; |
148 | | - |
149 | | - if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
150 | | - perror("httpd"); |
151 | | - return -1; |
152 | | - } |
153 | | - |
154 | | - /* set local port reuse, allows server to be restarted in less than 10 secs */ |
155 | | - ret = 1; |
156 | | - if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof(int)) < 0) |
157 | | - perror("SO_REUSEADDR"); |
158 | | - |
159 | | - /* set small listen buffer to save ktcp memory */ |
160 | | - ret = SO_LISTEN_BUFSIZ; |
161 | | - if (setsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF, &ret, sizeof(int)) < 0) |
162 | | - perror("SO_RCVBUF"); |
163 | | - |
164 | | - localadr.sin_family = AF_INET; |
165 | | - localadr.sin_port = htons(DEF_PORT); |
166 | | - localadr.sin_addr.s_addr = INADDR_ANY; |
167 | | - |
168 | | - if (bind(listen_sock, (struct sockaddr *)&localadr, sizeof(struct sockaddr_in)) < 0) { |
169 | | - fprintf(stderr, "httpd: bind error (may already be running)\n"); |
170 | | - return 1; |
171 | | - } |
172 | | - if (listen(listen_sock, 5) < 0) { |
173 | | - perror("listen"); |
174 | | - return 1; |
175 | | - } |
176 | | - |
177 | | - /* become daemon, debug output on 1 and 2*/ |
178 | | - if ((ret = fork()) == -1) { |
179 | | - perror("httpd"); |
180 | | - return 1; |
181 | | - } |
182 | | - if (ret) exit(0); |
183 | | - ret = open("/dev/null", O_RDWR); /* our log file! */ |
184 | | - dup2(ret, 0); |
185 | | - dup2(ret, 1); |
186 | | - dup2(ret, 2); |
187 | | - if (ret > 2) |
188 | | - close(ret); |
189 | | - setsid(); |
190 | | - |
191 | | - while (1) { |
192 | | - conn_sock = accept(listen_sock, NULL, NULL); |
193 | | - |
194 | | - if (conn_sock < 0) { |
195 | | - if (errno == ENOTSOCK) |
196 | | - exit(1); |
197 | | - continue; |
198 | | - } |
199 | | - |
200 | | - if ((ret = fork()) == -1) |
201 | | - perror("httpd"); |
202 | | - else if (ret == 0) { |
203 | | - close(listen_sock); |
204 | | - process_request(conn_sock); |
205 | | - close(conn_sock); |
206 | | - exit(0); |
207 | | - } else { |
208 | | - close(conn_sock); |
209 | | - waitpid(ret, NULL, 0); |
210 | | - } |
211 | | - } |
| 149 | + int ret, conn_sock, listen_sock; |
| 150 | + struct sockaddr_in localadr; |
| 151 | + |
| 152 | + if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
| 153 | + errmsg("httpd: Network is down\n"); |
| 154 | + return -1; |
| 155 | + } |
| 156 | + |
| 157 | + /* set local port reuse, allows server to be restarted in less than 10 secs */ |
| 158 | + ret = 1; |
| 159 | + if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof(int)) < 0) |
| 160 | + errmsg("http: SO_REUSEADDR"); |
| 161 | + |
| 162 | + /* set small listen buffer to save ktcp memory */ |
| 163 | + ret = SO_LISTEN_BUFSIZ; |
| 164 | + if (setsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF, &ret, sizeof(int)) < 0) |
| 165 | + errmsg("httpd: SO_RCVBUF"); |
| 166 | + |
| 167 | + localadr.sin_family = AF_INET; |
| 168 | + localadr.sin_port = htons(DEF_PORT); |
| 169 | + localadr.sin_addr.s_addr = INADDR_ANY; |
| 170 | + if (bind(listen_sock, (struct sockaddr *)&localadr, sizeof(struct sockaddr_in)) < 0) { |
| 171 | + errmsg("httpd: bind error (may already be running)\n"); |
| 172 | + return 1; |
| 173 | + } |
| 174 | + if (listen(listen_sock, 5) < 0) { |
| 175 | + errmsg("httpd: listen\n"); |
| 176 | + return 1; |
| 177 | + } |
| 178 | + |
| 179 | + /* become daemon, debug output on 1 and 2*/ |
| 180 | + if ((ret = fork()) == -1) { |
| 181 | + errmsg("httpd: No more processes\n"); |
| 182 | + return 1; |
| 183 | + } |
| 184 | + if (ret) exit(0); |
| 185 | + ret = open("/dev/null", O_RDWR); /* our log file! */ |
| 186 | + dup2(ret, 0); |
| 187 | + dup2(ret, 1); |
| 188 | + dup2(ret, 2); |
| 189 | + if (ret > 2) |
| 190 | + close(ret); |
| 191 | + setsid(); |
| 192 | + |
| 193 | + while (1) { |
| 194 | + conn_sock = accept(listen_sock, NULL, NULL); |
| 195 | + if (conn_sock < 0) { |
| 196 | + if (errno == ENOTSOCK) |
| 197 | + exit(1); |
| 198 | + continue; |
| 199 | + } |
| 200 | + |
| 201 | + if ((ret = fork()) == -1) { |
| 202 | + close(conn_sock); |
| 203 | + errmsg("httpd: No more processes\n"); |
| 204 | + } else if (ret) { |
| 205 | + close(conn_sock); |
| 206 | + waitpid(ret, NULL, 0); |
| 207 | + } else { |
| 208 | + close(listen_sock); |
| 209 | + process_request(conn_sock); |
| 210 | + close(conn_sock); |
| 211 | + exit(0); |
| 212 | + } |
| 213 | + } |
212 | 214 | } |
0 commit comments