* httpd -p 80 -u 80 -h /www -c /etc/httpd.conf -r "Web Server Authentication"
*
*
- * When a url starts by "/cgi-bin/" it is assumed to be a cgi script. The
+ * When an url starts by "/cgi-bin/" it is assumed to be a cgi script. The
* server changes directory to the location of the script and executes it
* after setting QUERY_STRING and other environment variables.
*
* Doc:
* "CGI Environment Variables": http://hoohoo.ncsa.uiuc.edu/cgi/env.html
*
- * The applet can also be invoked as a url arg decoder and html text encoder
+ * The applet can also be invoked as an url arg decoder and html text encoder
* as follows:
* foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World"
* bar=`httpd -e "<Hello World>"` # encode as "<Hello World>"
* Note that url encoding for arguments is not the same as html encoding for
- * presentation. -d decodes a url-encoded argument while -e encodes in html
+ * presentation. -d decodes an url-encoded argument while -e encodes in html
* for page display.
*
* httpd.conf has the following format:
* server exits with an error.
*
*/
+ /* TODO: use TCP_CORK, parse_config() */
#include "libbb.h"
#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
#endif
};
+static const char index_html[] ALIGN1 = "index.html";
+
struct globals {
int verbose; /* must be int (used by getopt32) */
SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
bind_addr_or_port = "80"; \
- index_page = "index.html"; \
+ index_page = index_html; \
file_size = -1; \
} while (0)
ch = (buf[0] & ~0x20); /* toupper if it's a letter */
if (ch == 'I') {
+ if (index_page != index_html)
+ free((char*)index_page);
index_page = xstrdup(after_colon);
continue;
}
/* form "/path/file" */
sprintf(cur->before_colon, "/%s%.*s",
path,
- after_colon - buf - 1, /* includes "/", but not ":" */
+ (int) (after_colon - buf - 1), /* includes "/", but not ":" */
buf);
/* canonicalize it */
p = bb_simplify_abs_path_inplace(cur->before_colon);
strftime(tmp_str, sizeof(tmp_str), RFC1123FMT, gmtime(&last_mod));
#if ENABLE_FEATURE_HTTPD_RANGES
if (responseNum == HTTP_PARTIAL_CONTENT) {
- len += sprintf(iobuf + len, "Content-Range: bytes %"OFF_FMT"d-%"OFF_FMT"d/%"OFF_FMT"d\r\n",
+ len += sprintf(iobuf + len, "Content-Range: bytes %"OFF_FMT"u-%"OFF_FMT"u/%"OFF_FMT"u\r\n",
range_start,
range_end,
file_size);
#if ENABLE_FEATURE_HTTPD_RANGES
"Accept-Ranges: bytes\r\n"
#endif
- "Last-Modified: %s\r\n%s %"OFF_FMT"d\r\n",
+ "Last-Modified: %s\r\n%s %"OFF_FMT"u\r\n",
tmp_str,
"Content-length:",
file_size
break;
}
- if (pfd[TO_CGI].revents) {
+ if (pfd[TO_CGI].revents & POLLOUT) {
/* hdr_cnt > 0 here due to the way pfd[TO_CGI].events set */
/* Have data from peer and can write to CGI */
count = safe_write(toCgi_wr, hdr_ptr, hdr_cnt);
}
}
- if (pfd[0].revents) {
+ if (pfd[0].revents & POLLIN) {
/* post_len > 0 && hdr_cnt == 0 here */
/* We expect data, prev data portion is eaten by CGI
* and there *is* data to read from the peer
}
}
- if (pfd[FROM_CGI].revents) {
+ if (pfd[FROM_CGI].revents & POLLIN) {
/* There is something to read from CGI */
char *rbuf = iobuf;
/* Check for [dirs/]script.cgi/PATH_INFO */
script = (char*)url;
while ((script = strchr(script + 1, '/')) != NULL) {
- struct stat sb;
-
*script = '\0';
- if (!is_directory(url + 1, 1, &sb)) {
+ if (!is_directory(url + 1, 1, NULL)) {
/* not directory, found script.cgi/PATH_INFO */
*script = '/';
break;
*/
static NOINLINE void send_file_and_exit(const char *url, int what)
{
- static const char *const suffixTable[] = {
- /* Warning: shorter equivalent suffix in one line must be first */
- ".htm.html", "text/html",
- ".jpg.jpeg", "image/jpeg",
- ".gif", "image/gif",
- ".png", "image/png",
- ".txt.h.c.cc.cpp", "text/plain",
- ".css", "text/css",
- ".wav", "audio/wav",
- ".avi", "video/x-msvideo",
- ".qt.mov", "video/quicktime",
- ".mpe.mpeg", "video/mpeg",
- ".mid.midi", "audio/midi",
- ".mp3", "audio/mpeg",
-#if 0 /* unpopular */
- ".au", "audio/basic",
- ".pac", "application/x-ns-proxy-autoconfig",
- ".vrml.wrl", "model/vrml",
-#endif
- NULL
- };
-
char *suffix;
int fd;
- const char *const *table;
- const char *try_suffix;
ssize_t count;
fd = open(url, O_RDONLY);
send_headers_and_exit(HTTP_NOT_FOUND);
log_and_exit();
}
-
- if (DEBUG)
- bb_error_msg("sending file '%s' content-type: %s",
- url, found_mime_type);
-
/* If you want to know about EPIPE below
* (happens if you abort downloads from local httpd): */
signal(SIGPIPE, SIG_IGN);
- suffix = strrchr(url, '.');
-
- /* If not found, set default as "application/octet-stream"; */
+ /* If not found, default is "application/octet-stream" */
found_mime_type = "application/octet-stream";
+ suffix = strrchr(url, '.');
if (suffix) {
+ static const char suffixTable[] ALIGN1 =
+ /* Shorter suffix must be first:
+ * ".html.htm" will fail for ".htm"
+ */
+ ".txt.h.c.cc.cpp\0" "text/plain\0"
+ /* .htm line must be after .h line */
+ ".htm.html\0" "text/html\0"
+ ".jpg.jpeg\0" "image/jpeg\0"
+ ".gif\0" "image/gif\0"
+ ".png\0" "image/png\0"
+ /* .css line must be after .c line */
+ ".css\0" "text/css\0"
+ ".wav\0" "audio/wav\0"
+ ".avi\0" "video/x-msvideo\0"
+ ".qt.mov\0" "video/quicktime\0"
+ ".mpe.mpeg\0" "video/mpeg\0"
+ ".mid.midi\0" "audio/midi\0"
+ ".mp3\0" "audio/mpeg\0"
+#if 0 /* unpopular */
+ ".au\0" "audio/basic\0"
+ ".pac\0" "application/x-ns-proxy-autoconfig\0"
+ ".vrml.wrl\0" "model/vrml\0"
+#endif
+ /* compiler adds another "\0" here */
+ ;
Htaccess *cur;
- for (table = suffixTable; *table; table += 2) {
- try_suffix = strstr(table[0], suffix);
- if (try_suffix) {
- try_suffix += strlen(suffix);
- if (*try_suffix == '\0' || *try_suffix == '.') {
- found_mime_type = table[1];
- break;
- }
+
+ /* Examine built-in table */
+ const char *table = suffixTable;
+ const char *table_next;
+ for (; *table; table = table_next) {
+ const char *try_suffix;
+ const char *mime_type;
+ mime_type = table + strlen(table) + 1;
+ table_next = mime_type + strlen(mime_type) + 1;
+ try_suffix = strstr(table, suffix);
+ if (!try_suffix)
+ continue;
+ try_suffix += strlen(suffix);
+ if (*try_suffix == '\0' || *try_suffix == '.') {
+ found_mime_type = mime_type;
+ break;
}
+ /* Example: strstr(table, ".av") != NULL, but it
+ * does not match ".avi" after all and we end up here.
+ * The table is arranged so that in this case we know
+ * that it can't match anything in the following lines,
+ * and we stop the search: */
+ break;
}
+ /* ...then user's table */
for (cur = mime_a; cur; cur = cur->next) {
if (strcmp(cur->before_colon, suffix) == 0) {
found_mime_type = cur->after_colon;
}
}
}
+
+ if (DEBUG)
+ bb_error_msg("sending file '%s' content-type: %s",
+ url, found_mime_type);
+
#if ENABLE_FEATURE_HTTPD_RANGES
if (what == SEND_BODY)
range_start = 0; /* err pages and ranges don't mix */
/* If URL is a directory, add '/' */
if (urlp[-1] != '/') {
- if (is_directory(urlcopy + 1, 1, &sb)) {
+ if (is_directory(urlcopy + 1, 1, NULL)) {
found_moved_temporarily = urlcopy;
}
}
while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) {
/* have path1/path2 */
*tptr = '\0';
- if (is_directory(urlcopy + 1, 1, &sb)) {
+ if (is_directory(urlcopy + 1, 1, NULL)) {
/* may have subdir config */
parse_conf(urlcopy + 1, SUBDIR_PARSE);
ip_allowed = checkPermIP();
header_ptr += 2;
write(proxy_fd, header_buf, header_ptr - header_buf);
free(header_buf); /* on the order of 8k, free it */
- /* cgi_io_loop_and_exit needs to have two disctinct fds */
+ /* cgi_io_loop_and_exit needs to have two distinct fds */
cgi_io_loop_and_exit(proxy_fd, dup(proxy_fd), length);
}
#endif
}
send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type);
}
+#endif
+
+ if (urlp[-1] == '/')
+ strcpy(urlp, index_page);
+ if (stat(tptr, &sb) == 0) {
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
- {
char *suffix = strrchr(tptr, '.');
if (suffix) {
Htaccess *cur;
}
}
}
- }
#endif
- if (prequest != request_GET && prequest != request_HEAD) {
- send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
- }
-#endif /* FEATURE_HTTPD_CGI */
-
- if (urlp[-1] == '/')
- strcpy(urlp, index_page);
- if (stat(tptr, &sb) == 0) {
file_size = sb.st_size;
last_mod = sb.st_mtime;
}
send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type);
}
}
-#endif
- /* else {
- * fall through to send_file, it errors out if open fails
- * }
- */
+ /* else fall through to send_file, it errors out if open fails: */
+ if (prequest != request_GET && prequest != request_HEAD) {
+ /* POST for files does not make sense */
+ send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
+ }
send_file_and_exit(tptr,
-#if ENABLE_FEATURE_HTTPD_CGI
(prequest != request_HEAD ? SEND_HEADERS_AND_BODY : SEND_HEADERS)
+ );
#else
- SEND_HEADERS_AND_BODY
+ send_file_and_exit(tptr, SEND_HEADERS_AND_BODY);
#endif
- );
}
/*
#endif
#if ENABLE_FEATURE_HTTPD_AUTH_MD5
if (opt & OPT_MD5) {
- puts(pw_encrypt(pass, "$1$", 1));
+ char salt[sizeof("$1$XXXXXXXX")];
+ salt[0] = '$';
+ salt[1] = '1';
+ salt[2] = '$';
+ crypt_make_salt(salt + 3, 4, 0);
+ puts(pw_encrypt(pass, salt, 1));
return 0;
}
#endif