#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1)
/* Prototypes */
-static void send_file_and_exit(const char *url, int headers) ATTRIBUTE_NORETURN;
+enum {
+ SEND_HEADERS = (1 << 0),
+ SEND_BODY = (1 << 1),
+ SEND_HEADERS_AND_BODY = SEND_HEADERS + SEND_BODY,
+};
+static void send_file_and_exit(const char *url, int what) ATTRIBUTE_NORETURN;
static void free_llist(has_next_ptr **pptr)
{
const char *infoString = NULL;
const char *mime_type;
#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
- const char *error_page = 0;
+ const char *error_page = NULL;
#endif
unsigned i;
time_t timer = time(0);
full_write(1, iobuf, len);
if (DEBUG)
fprintf(stderr, "writing error page: '%s'\n", error_page);
- return send_file_and_exit(error_page, FALSE);
+ return send_file_and_exit(error_page, SEND_BODY);
}
#endif
* Send a file response to a HTTP request, and exit
*
* Parameters:
- * const char *url The requested URL (with leading /).
- * headers Don't send headers before if FALSE.
+ * const char *url The requested URL (with leading /).
+ * what What to send (headers/body/both).
*/
-static void send_file_and_exit(const char *url, int headers)
+static 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 */
off_t offset;
#endif
+ /* 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 (f < 0) {
if (DEBUG)
bb_perror_msg("cannot open '%s'", url);
- if (headers)
+ /* Error pages are sent by using send_file_and_exit(SEND_BODY).
+ * IOW: it is unsafe to call send_headers_and_exit
+ * if what is SEND_BODY! Can recurse! */
+ if (what != SEND_BODY)
send_headers_and_exit(HTTP_NOT_FOUND);
+ log_and_exit();
}
#if ENABLE_FEATURE_HTTPD_RANGES
- if (!headers)
+ if (what == SEND_BODY)
range_start = 0; /* err pages and ranges don't mix */
range_len = MAXINT(off_t);
if (range_start) {
} else {
range_len = range_end - range_start + 1;
send_headers(HTTP_PARTIAL_CONTENT);
- headers = 0;
+ what = SEND_BODY;
}
}
#endif
- if (headers)
+ if (what & SEND_HEADERS)
send_headers(HTTP_OK);
- /* If you want to know about EPIPE below
- * (happens if you abort downloads from local httpd): */
- signal(SIGPIPE, SIG_IGN);
-
#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
offset = range_start;
do {
static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
{
static const char request_GET[] ALIGN1 = "GET";
-
struct stat sb;
char *urlcopy;
char *urlp;
char *tptr;
int ip_allowed;
#if ENABLE_FEATURE_HTTPD_CGI
+ static const char request_HEAD[] ALIGN1 = "HEAD";
const char *prequest;
char *cookie = NULL;
char *content_type = NULL;
#if ENABLE_FEATURE_HTTPD_CGI
prequest = request_GET;
if (strcasecmp(iobuf, prequest) != 0) {
- prequest = "POST";
- if (strcasecmp(iobuf, prequest) != 0)
- send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
+ prequest = request_HEAD;
+ if (strcasecmp(iobuf, prequest) != 0) {
+ prequest = "POST";
+ if (strcasecmp(iobuf, prequest) != 0)
+ send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
+ }
}
#else
if (strcasecmp(iobuf, request_GET) != 0)
/* Try and do our best to parse more lines */
if ((STRNCASECMP(iobuf, "Content-length:") == 0)) {
/* extra read only for POST */
- if (prequest != request_GET) {
+ if (prequest != request_GET && prequest != request_HEAD) {
tptr = iobuf + sizeof("Content-length:") - 1;
if (!tptr[0])
send_headers_and_exit(HTTP_BAD_REQUEST);
- errno = 0;
/* not using strtoul: it ignores leading minus! */
- length = strtol(tptr, &tptr, 10);
+ length = bb_strtou(tptr, NULL, 10);
/* length is "ulong", but we need to pass it to int later */
- /* so we check for negative or too large values in one go: */
- /* (long -> ulong conv caused negatives to be seen as > INT_MAX) */
- if (tptr[0] || errno || length > INT_MAX)
+ if (errno || length > INT_MAX)
send_headers_and_exit(HTTP_BAD_REQUEST);
}
}
}
}
#endif
- if (prequest != request_GET) {
+ if (prequest != request_GET && prequest != request_HEAD) {
send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
}
#endif /* FEATURE_HTTPD_CGI */
* }
*/
- send_file_and_exit(tptr, TRUE);
+ send_file_and_exit(tptr,
+ (prequest != request_HEAD ? SEND_HEADERS_AND_BODY : SEND_HEADERS));
}
/*