Example #1
0
int write_from_pipe(request * req)
{
	int bytes_written, bytes_to_write = req->header_end - req->header_line;

	if (bytes_to_write == 0) {
		if (req->cgi_status == CGI_DONE)
			return 0;

		req->status = PIPE_READ;
		req->header_end = req->header_line = req->buffer;
		return 1;
	}

	bytes_written = write(req->fd, req->header_line, bytes_to_write);
	if (bytes_written == -1) {
		if (errno == EWOULDBLOCK || errno == EAGAIN)
			return -1;          /* request blocked at the pipe level, but keep going */
		else if (errno == EINTR)
			return 1;
		else {
			req->status = DEAD;
			send_r_error(req);  /* maybe superfluous */
			log_error_doc(req);
			perror("pipe write");
			return 0;
		}
	}

	req->header_line += bytes_written;
	req->filepos += bytes_written;

	return 1;
}
Example #2
0
int process_header_end(request * req)
{
    if (!req->logline) {
        send_r_error(req);
        return 0;
    }

    /* Percent-decode request */
    if (unescape_uri(req->request_uri, &(req->query_string)) == 0) {
        log_error_doc(req);
        fputs("Problem unescaping uri\n", stderr);
        send_r_bad_request(req);
        return 0;
    }

    /* clean pathname */
    clean_pathname(req->request_uri);

    if (req->request_uri[0] != '/') {
        send_r_bad_request(req);
        return 0;
    }

    if (translate_uri(req) == 0) { /* unescape, parse uri */
        SQUASH_KA(req);
        return 0;               /* failure, close down */
    }

    if (req->method == M_POST) {
        req->post_data_fd = create_temporary_file(1, NULL, 0);
        if (req->post_data_fd == 0)
            return(0);
        return(1); /* success */
    }

    if (req->is_cgi) {
        return init_cgi(req);
    }

    req->status = WRITE;
    return init_get(req);       /* get and head */
}
Example #3
0
/*
 * Name: boa_perror
 *
 * Description: logs an error to user and error file both
 *
 */
void boa_perror(request * req, const char *message)
{
    log_error_doc(req);
    perror(message);            /* don't need to save errno because log_error_doc does */
    send_r_error(req);
}
Example #4
0
File: get.c Project: gpg/boa
static int index_directory(request * req, char *dest_filename)
{
    DIR *request_dir;
    FILE *fdstream;
    struct dirent *dirbuf;
    off_t bytes = 0;
    char *escname = NULL;

    if (chdir(req->pathname) == -1) {
        if (errno == EACCES || errno == EPERM) {
            send_r_forbidden(req);
        } else {
            log_error_doc(req);
            perror("chdir");
            send_r_bad_request(req);
        }
        return -1;
    }

    request_dir = opendir(".");
    if (request_dir == NULL) {
        int errno_save = errno;
        send_r_error(req);
        log_error_doc(req);
        fprintf(stderr, "opendir failed on directory \"%s\": ", req->pathname);
        errno = errno_save;
        perror("opendir");
        return -1;
    }

    fdstream = fopen(dest_filename, "w");
    if (fdstream == NULL) {
        boa_perror(req, "dircache fopen");
        closedir(request_dir);
        return -1;
    }

    bytes += fprintf(fdstream,
                     "<HTML><HEAD>\n<TITLE>Index of %s</TITLE>\n</HEAD>\n\n",
                     req->request_uri);
    bytes += fprintf(fdstream, "<BODY>\n\n<H2>Index of %s</H2>\n\n<PRE>\n",
                     req->request_uri);

    while ((dirbuf = readdir(request_dir))) {
        if (!strcmp(dirbuf->d_name, "."))
            continue;

        if (!strcmp(dirbuf->d_name, "..")) {
            bytes += fprintf(fdstream,
                             " [DIR] <A HREF=\"../\">Parent Directory</A>\n");
            continue;
        }

        /* FIXME: ought to use (as-yet unwritten) html_escape_string */
        escname = escape_string(dirbuf->d_name, NULL);
        if (escname != NULL) {
            bytes += fprintf(fdstream, " <A HREF=\"%s\">%s</A>\n",
                             escname, dirbuf->d_name);
            free(escname);
            escname = NULL;
        }
    }
    closedir(request_dir);
    bytes += fprintf(fdstream, "</PRE>\n\n</BODY>\n</HTML>\n");

    fclose(fdstream);

    if (chdir(server_root) == -1)
        perror("chdir to server root failed");

    req->filesize = bytes;      /* for logging transfer size */
    return 0;                   /* success */
}
Example #5
0
File: get.c Project: gpg/boa
int init_get(request * req)
{
    int data_fd, saved_errno;
    struct stat statbuf;
    volatile off_t bytes_free;

    data_fd = open(req->pathname, O_RDONLY|O_LARGEFILE);
    saved_errno = errno;        /* might not get used */

    while (use_lang_rewrite && data_fd == -1 && errno == ENOENT) {
         /* We cannot open that file - Check whether we can rewrite it
          * to a different language suffix.  We only support filenames
          * of the format: "foo.ll.html" as an alias for "foo.html". */
        unsigned int len;

        len = strlen(req->pathname);
        if (len < 6 || strcmp (req->pathname + len - 5, ".html"))
            break;  /* does not end in ".html" */
        if (len > 8 && req->pathname[len-8] == '.'
            && req->pathname[len-7] >= 'a' && req->pathname[len-7] <= 'z'
            && req->pathname[len-6] >= 'a' && req->pathname[len-6] <= 'z') {
            /* The request was for a language dependent file.  Strip
             * it and try the generic form. */
            char save_name[8];

            strcpy (save_name, req->pathname + len - 7);
            strcpy (req->pathname + len - 7, "html");
            data_fd = open(req->pathname, O_RDONLY);
            if (data_fd == -1)
                strcpy (req->pathname + len - 7, save_name);
            break;
        }
        else if ( 0 ) {
            /* Fixme: Other items to try from the list of accepted_languages */
            data_fd = open(req->pathname, O_RDONLY);
        }
        else
            break;
    }


#ifdef GUNZIP
    if (data_fd == -1 && errno == ENOENT) {
        /* cannot open */
        /* it's either a gunzipped file or a directory */
        char gzip_pathname[MAX_PATH_LENGTH];
        unsigned int len;

        len = strlen(req->pathname);

        if (len + 4 > sizeof(gzip_pathname)) {
            log_error_doc(req);
            fprintf(stderr, "Pathname + .gz too long! (%s)\n", req->pathname);
            send_r_bad_request(req);
            return 0;
        }

        memcpy(gzip_pathname, req->pathname, len);
        memcpy(gzip_pathname + len, ".gz", 3);
        gzip_pathname[len + 3] = '\0';
        data_fd = open(gzip_pathname, O_RDONLY|O_LARGEFILE);
        if (data_fd != -1) {
            close(data_fd);

            req->response_status = R_REQUEST_OK;
            if (req->pathname)
                free(req->pathname);
            req->pathname = strdup(gzip_pathname);
            if (!req->pathname) {
                boa_perror(req, "strdup req->pathname for gzipped filename " __FILE__ ":" STR(__LINE__));
                return 0;
            }
            if (req->http_version != HTTP09) {
                req_write(req, http_ver_string(req->http_version));
                req_write(req, " 200 OK-GUNZIP" CRLF);
                print_http_headers(req);
                print_content_type(req);
                print_last_modified(req);
                req_write(req, CRLF);
                req_flush(req);
            }
            if (req->method == M_HEAD)
                return 0;

            return init_cgi(req);
        }
    }
#endif

    if (data_fd == -1) {
        log_error_doc(req);
        errno = saved_errno;
        perror("document open");

        if (saved_errno == ENOENT)
            send_r_not_found(req);
        else if (saved_errno == EACCES)
            send_r_forbidden(req);
        else
            send_r_bad_request(req);
        return 0;
    }

#ifdef ACCESS_CONTROL
    if (!access_allow(req->pathname)) {
      send_r_forbidden(req);
      return 0;
    }
#endif

    fstat(data_fd, &statbuf);

    if (S_ISDIR(statbuf.st_mode)) { /* directory */
        close(data_fd);         /* close dir */

        if (req->pathname[strlen(req->pathname) - 1] != '/') {
            char buffer[3 * MAX_PATH_LENGTH + 128];
            unsigned int len;

#ifdef ALLOW_LOCAL_REDIRECT
            len = strlen(req->request_uri);
            if (len + 2 > sizeof(buffer)) {
                send_r_error(req);
                return 0;
            }
            memcpy(buffer, req->request_uri, len);
            buffer[len] = '/';
            buffer[len+1] = '\0';
#else
            char *host = server_name;
            unsigned int l2;
            char *port = NULL;
            const char *prefix = hsts_header? "https://" : "http://";
            static unsigned int l3 = 0;
            static unsigned int l4 = 0;

            if (l4 == 0) {
                l4 = strlen(prefix);
            }
            len = strlen(req->request_uri);
            if (!port && server_port != 80 && !no_redirect_port) {
                port = strdup(simple_itoa(server_port));
                if (port == NULL) {
                    errno = ENOMEM;
                    boa_perror(req, "Unable to perform simple_itoa conversion on server port!");
                    return 0;
                }
                l3 = strlen(port);
            }
            /* l3 and l4 are done */

            if (req->host) {
                /* only shows up in vhost mode */
                /* what about the port? (in vhost_mode?) */
                /* we don't currently report ports that differ
                 * from out "bound" (listening) port, so we don't care
                 */
                host = req->host;
            }
            l2 = strlen(host);

            if (server_port != 80 && !no_redirect_port) {
                if (l4 + l2 + 1 + l3 + len + 1 > sizeof(buffer)) {
                    errno = ENOMEM;
                    boa_perror(req, "buffer not large enough for directory redirect");
                    return 0;
                }
                memcpy(buffer, prefix, l4);
                memcpy(buffer + l4, host, l2);
                buffer[l4 + l2] = ':';
                memcpy(buffer + l4 + l2 + 1, port, l3);
                memcpy(buffer + l4 + l2 + 1 + l3, req->request_uri, len);
                buffer[l4 + l2 + 1 + l3 + len] = '/';
                buffer[l4 + l2 + 1 + l3 + len + 1] = '\0';
            } else {
                if (l4 + l2 + len + 1 > sizeof(buffer)) {
                    errno = ENOMEM;
                    boa_perror(req, "buffer not large enough for directory redirect");
                    return 0;
                }
                memcpy(buffer, prefix, l4);
                memcpy(buffer + l4, host, l2);
                memcpy(buffer + l4 + l2, req->request_uri, len);
                buffer[l4 + l2 + len] = '/';
                buffer[l4 + l2 + len + 1] = '\0';
            }
#endif /* ALLOW LOCAL REDIRECT */
            send_r_moved_perm(req, buffer);
            return 0;
        }
        data_fd = get_dir(req, &statbuf); /* updates statbuf */

        if (data_fd < 0)      /* couldn't do it */
            return 0;           /* errors reported by get_dir */
        else if (data_fd == 0 || data_fd == 1)
            return data_fd;
        /* else, data_fd contains the fd of the file... */
    }

    if (!S_ISREG(statbuf.st_mode)) { /* regular file */
        log_error_doc(req);
        fprintf(stderr, "Resulting file is not a regular file.\n");
        send_r_bad_request(req);
        close(data_fd);
        return 0;
    }

    /* If-UnModified-Since asks
     *  is the file newer than date located in time_cval
     *  yes -> return 412
     *   no -> return 200
     *
     * If-Modified-Since asks
     *  is the file date less than or same as the date located in time_cval
     *  yes -> return 304
     *  no  -> return 200
     *
     * If-Unmodified-Since overrides If-Modified-Since
     */

    /*
    if (req->headers[H_IF_UNMODIFIED_SINCE] &&
        modified_since(&(statbuf.st_mtime),
                       req->headers[H_IF_UNMODIFIED_SINCE])) {
        send_r_precondition_failed(req);
        return 0;
    } else
    */
    if (req->if_modified_since &&
        !modified_since(&(statbuf.st_mtime), req->if_modified_since)) {
        send_r_not_modified(req);
        close(data_fd);
        return 0;
    }

    req->filesize = statbuf.st_size;
    req->last_modified = statbuf.st_mtime;

    /* ignore if-range without range */
    if (req->header_ifrange && !req->ranges)
        req->header_ifrange = NULL;

    /* we don't support it yet */
    req->header_ifrange = NULL;

    /* parse ranges now */
    /* we have to wait until req->filesize exists to fix them up */
    /* fixup handles handles communicating with the client */
    /* ranges_fixup logs as appropriate, and sends
     * send_r_invalid_range on error.
     */

    if (req->filesize == 0) {
        if (req->http_version < HTTP11) {
            send_r_request_ok(req);
            close(data_fd);
            return 0;
        }
        send_r_no_content(req);
        close(data_fd);
        return 0;
    }

    if (req->ranges && !ranges_fixup(req)) {
        close(data_fd);
        return 0;
    }

    /* if no range has been set, use default range */
#if 0
    DEBUG(DEBUG_RANGE) {
        log_error_time();
        fprintf(stderr, "if-range: %s\time_cval: %d\tmtime: %d\n",
                req->header_ifrange, req->time_cval, statbuf->st_mtime);
    }
#endif

    /*
     If the entity tag given in the If-Range header matches the current
     entity tag for the entity, then the server should provide the
     specified sub-range of the entity using a 206 (Partial content)
     response.

     If the entity tag does not match, then the server should
     return the entire entity using a 200 (OK) response.
     */
    /* IF we have range data *and* no if-range or if-range matches... */

#ifdef MAX_FILE_MMAP
    if (req->filesize > MAX_FILE_MMAP) {
        req->data_fd = data_fd;
        req->status = IOSHUFFLE;
    } else
#endif
    {
        /* NOTE: I (Jon Nelson) tried performing a read(2)
         * into the output buffer provided the file data would
         * fit, before mmapping, and if successful, writing that
         * and stopping there -- all to avoid the cost
         * of a mmap.  Oddly, it was *slower* in benchmarks.
         */
        req->mmap_entry_var = find_mmap(data_fd, &statbuf);
        if (req->mmap_entry_var == NULL) {
            req->data_fd = data_fd;
            req->status = IOSHUFFLE;
        } else {
            req->data_mem = req->mmap_entry_var->mmap;
            close(data_fd);             /* close data file */
        }
    }

    if (!req->ranges) {
        req->ranges = range_pool_pop();
        req->ranges->start = 0;
        req->ranges->stop = -1;
        if (!ranges_fixup(req)) {
            return 0;
        }
        send_r_request_ok(req);
    } else {
        /* FIXME: support if-range header here, by the following logic:
         * if !req->header_ifrange || st_mtime > header_ifrange,
         *   send_r_partial_content
         * else
         *   reset-ranges, etc...
         */
        if (!req->header_ifrange) {
            send_r_partial_content(req);
        } else {
            /* either no if-range or the if-range does not match */
            ranges_reset(req);
            req->ranges = range_pool_pop();
            req->ranges->start = 0;
            req->ranges->stop = -1;
            if (!ranges_fixup(req)) {
                return 0;
            }
            send_r_request_ok(req);
        }
    }

    if (req->method == M_HEAD) {
        return complete_response(req);
    }

    bytes_free = 0;
    if (req->data_mem) {
        /* things can really go tilt if req->buffer_end > BUFFER_SIZE,
         * but basically that can't happen
         */

        /* We lose statbuf here, so make sure response has been sent */
        bytes_free = BUFFER_SIZE - req->buffer_end;
        /* 256 bytes for the **trailing** headers */

        /* bytes is now how much the buffer can hold
         * after the headers
         */
    }

    if (req->data_mem && bytes_free > 256) {
        unsigned int want;
        Range *r;

        r = req->ranges;

        want = (r->stop - r->start) + 1;

        if (bytes_free > want)
            bytes_free = want;
        else {
            /* bytes_free <= want */
            ;
        }

        if (setjmp(env) == 0) {
            handle_sigbus = 1;
            memcpy(req->buffer + req->buffer_end,
                   req->data_mem + r->start, bytes_free);
            handle_sigbus = 0;
            /* OK, SIGBUS **after** this point is very bad! */
        } else {
            /* sigbus! */
            log_error_doc(req);
            reset_output_buffer(req);
            send_r_error(req);
            log_error("Got SIGBUS in memcpy\n");
            return 0;
        }
        req->buffer_end += bytes_free;
        req->bytes_written += bytes_free;
        r->start += bytes_free;
        if (bytes_free == want) {
            /* this will fit due to the 256 extra bytes_free */
            return complete_response(req);
        }
    }

    /* We lose statbuf here, so make sure response has been sent */
    return 1;
}
Example #6
0
int process_header_end(request * req)
{
#ifdef CHECK_IP_MAC
	char mac[18];  /*Naughty, assuming we are on ethernet!!!*/
#endif /*CHECK_IP_MAC*/

	if (!req->logline) {
		send_r_error(req);
		return 0;
	}

	/*MATT2 - I figured this was a good place to check for the MAC address*/
#ifdef CHECK_IP_MAC
	if(get_mac_from_IP(mac, req->remote_ip_addr))
		do_mac_crap(req->remote_ip_addr, mac);
	else;
		/*they could be on a remote lan, or just not in the arp cache*/
#endif



#ifdef USE_BROWSERMATCH
       browser_match_request(req);
#endif

#ifndef NO_REFERER_LOG
	if (req->referer)
		log_referer(req);
#endif

#ifndef NO_AGENT_LOG
	if (req->user_agent)
		log_user_agent(req);
#endif

        if (translate_uri(req) == 0) {  /* unescape, parse uri */
                SQUASH_KA(req);
                return 0;               /* failure, close down */
        }
#ifdef USE_NLS
#ifdef USE_NLS_REFERER_REDIR
				if (!req->cp_name)
				{
					if (!nls_try_redirect(req))
						return 0;
				}
#endif
				nls_set_codepage(req);
#endif				
				
#ifdef USE_AUTH
				closelog();
				openlog("boa", LOG_PID, LOG_AUTHPRIV);
				if (!auth_authorize(req)) {
					openlog("boa", LOG_PID, 0);
					return 0;
				}
#endif				
  
	if (req->method == M_POST) {
		char *tmpfilep = (char *) tmpnam(NULL);

		if (!tmpfilep) {
#if 0
			boa_perror(req, "tmpnam");
#endif
			return 0;
		}
		/* open temp file for post data */
		if ((req->post_data_fd = open(tmpfilep, O_RDWR | O_CREAT)) == -1) {
#if 0
			boa_perror(req, "tmpfile open");
#endif
			return 0;
		}
		req->post_file_name = strdup(tmpfilep);
		return 1;
	}
	if (req->is_cgi)
		return init_cgi(req);
	req->status = WRITE;
	return init_get(req);		/* get and head */
}
Example #7
0
void process_requests(void)
{
	int retval = 0;
	request *current, *trailer;

	current = request_ready;

	while (current) {
#ifdef CRASHDEBUG
		crashdebug_current = current;
#endif		
		if (current->buffer_end) {
			req_flush(current);
			if (current->status == CLOSE)
				retval = 0;
			else
				retval = 1;
		} else {
			switch (current->status) {
			case READ_HEADER:
			case ONE_CR:
			case ONE_LF:
			case TWO_CR:
				retval = read_header(current);
				break;
			case BODY_READ:
				retval = read_body(current);
				break;
			case BODY_WRITE:
				retval = write_body(current);
				break;
			case WRITE:
				retval = process_get(current);
				break;
			case PIPE_READ:
				retval = read_from_pipe(current);
				break;
			case PIPE_WRITE:
				retval = write_from_pipe(current);
				break;
			default:
				retval = 0;
#if 0
				fprintf(stderr, "Unknown status (%d), closing!\n",
						current->status);
#endif
				break;
			}
		}
		
		if (lame_duck_mode)
			SQUASH_KA(current);

		switch (retval) {
		case -1:				/* request blocked */
			trailer = current;
			current = current->next;
			block_request(trailer);
			break;
		default:			/* everything else means an error, jump ship */
			send_r_error(current);
			/* fall-through */
		case 0:				/* request complete */
			trailer = current;
			current = current->next;
			free_request(&request_ready, trailer);
			break;
		case 1:				/* more to do */
			current->time_last = time_counter;
			current = current->next;
			break;
		}
	}
#ifdef CRASHDEBUG
		crashdebug_current = current;
#endif
}
Example #8
0
int init_cgi(request * req)
{
	int child_pid;
	int pipes[2];
	int use_pipes = 0;

	SQUASH_KA(req);

	if (req->is_cgi) {
		if (complete_env(req) == 0) {
			return 0;
		}
	}

	if (req->is_cgi == CGI || 1) {
		use_pipes = 1;
		if (pipe(pipes) == -1) {
			log_error_time();
			perror("pipe");
			return 0;
		}

		/* set the read end of the socket to non-blocking */
		if (set_nonblock_fd(pipes[0]) == -1) {
			log_error_time();
			perror("cgi-fcntl");
			close(pipes[0]);
			close(pipes[1]);
			return 0;
		}
	}

	child_pid = fork();
	switch(child_pid) {
		case -1:
			/* fork unsuccessful */
			log_error_time();
			perror("fork");

			if (use_pipes) {
				close(pipes[0]);
				close(pipes[1]);
			}
			send_r_error(req);
			/* FIXME: There is aproblem here. send_r_error would work
			   for NPH and CGI, but not for GUNZIP.  Fix that. */
			/* i'd like to send_r_error, but.... */
			return 0;
			break;
		case 0:
			/* child */
			if (req->is_cgi == CGI || req->is_cgi == NPH) {
				char *foo = strdup(req->pathname);
				char *c;

				if (!foo) {
					WARN("unable to strdup pathname for req->pathname");
					_exit(1);
				}
				c = strrchr(foo, '/');
				if (c) {
					++c;
					*c = '\0';
				} else {
					/* we have a serious problem */
					log_error_time();
					perror("chdir");
					if (use_pipes)
						close(pipes[1]);
					_exit(1);
				}
				if (chdir(foo) != 0) {
					log_error_time();
					perror("chdir");
					if (use_pipes)
						close(pipes[1]);
					_exit(1);
				}
			}
			if (use_pipes) {
				close(pipes[0]);
				/* tie cgi's STDOUT to it's write end of pipe */
				if (dup2(pipes[1], STDOUT_FILENO) == -1) {
					log_error_time();
					perror("dup2 - pipes");
					close(pipes[1]);
					_exit(1);
				}
				close(pipes[1]);
				if (set_block_fd(STDOUT_FILENO) == -1) {
					log_error_time();
					perror("cgi-fcntl");
					_exit(1);
				}
			} else {
				/* tie stdout to socket */
				if (dup2(req->fd, STDOUT_FILENO) == -1) {
					log_error_time();
					perror("dup2 - fd");
					_exit(1);
				}
				/* Switch socket flags back to blocking */
				if (set_block_fd(req->fd) == -1) {
					log_error_time();
					perror("cgi-fcntl");
					_exit(1);
				}
			}
			/* tie post_data_fd to POST stdin */
			if (req->method == M_POST) { /* tie stdin to file */
				lseek(req->post_data_fd, SEEK_SET, 0);
				dup2(req->post_data_fd, STDIN_FILENO);
				close(req->post_data_fd);
			}
			/* Close access log, so CGI program can't scribble
			 * where it shouldn't
			 */
			close_access_log();

			/*
			 * tie STDERR to cgi_log_fd
			 * cgi_log_fd will automatically close, close-on-exec rocks!
			 * if we don't tied STDERR (current log_error) to cgi_log_fd,
			 *  then we ought to close it.
			 */
			//if (!cgi_log_fd)
			//	dup2(devnullfd, STDERR_FILENO);
			//else
			//	dup2(cgi_log_fd, STDERR_FILENO);

			if (req->is_cgi) {
				char *aargv[CGI_ARGC_MAX + 1];
				create_argv(req, aargv);
				execve(req->pathname, aargv, req->cgi_env);
			} else {
				if (req->pathname[strlen(req->pathname) - 1] == '/')
					execl(dirmaker, dirmaker, req->pathname, req->request_uri,
							NULL);
#ifdef GUNZIP
				else
					execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
							req->pathname, NULL);
#endif
			}
			/* execve failed */
			WARN(req->pathname);
			_exit(1);
			break;

		default:
			/* parent */
			/* if here, fork was successful */
			if (verbose_cgi_logs) {
				log_error_time();
				fprintf(stderr, "Forked child \"%s\" pid %d\n",
						req->pathname, child_pid);
			}

			if (req->method == M_POST) {
				close(req->post_data_fd); /* child closed it too */
				req->post_data_fd = 0;
			}

			/* NPH, GUNZIP, etc... all go straight to the fd */
			if (!use_pipes)
				return 0;

			close(pipes[1]);
			req->data_fd = pipes[0];

			req->status = PIPE_READ;
			if (req->is_cgi == CGI) {
				req->cgi_status = CGI_PARSE; /* got to parse cgi header */
				/* for cgi_header... I get half the buffer! */
				req->header_line = req->header_end =
					(req->buffer + BUFFER_SIZE / 2);
			} else {
				req->cgi_status = CGI_BUFFER;
				/* I get all the buffer! */
				req->header_line = req->header_end = req->buffer;
			}

			/* reset req->filepos for logging (it's used in pipe.c) */
			/* still don't know why req->filesize might be reset though */
			req->filepos = 0;
			break;
	}

	return 1;
}
Example #9
0
int get_dir(request * req, struct stat *statbuf)
{

    char pathname_with_index[MAX_PATH_LENGTH];
    int data_fd;

    if (directory_index) {      /* look for index.html first?? */
        strcpy(pathname_with_index, req->pathname);
        strcat(pathname_with_index, directory_index);
        /*
           sprintf(pathname_with_index, "%s%s", req->pathname, directory_index);
         */

        data_fd = open(pathname_with_index, O_RDONLY);

        if (data_fd != -1) {    /* user's index file */
            strcpy(req->request_uri, directory_index); /* for mimetype */
            fstat(data_fd, statbuf);
            return data_fd;
        }
        if (errno == EACCES) {
            send_r_forbidden(req);
            return -1;
        } else if (errno != ENOENT) {
            /* if there is an error *other* than EACCES or ENOENT */
            send_r_not_found(req);
            return -1;
        }

#ifdef GUNZIP
        /* if we are here, trying index.html didn't work
         * try index.html.gz
         */
        strcat(pathname_with_index, ".gz");
        data_fd = open(pathname_with_index, O_RDONLY);
        if (data_fd != -1) {    /* user's index file */
            close(data_fd);

            req->response_status = R_REQUEST_OK;
            SQUASH_KA(req);
            if (req->pathname)
                free(req->pathname);
            req->pathname = strdup(pathname_with_index);
            if (!req->pathname) {
                log_error_time();
                perror("strdup");
                send_r_error(req);
                return 0;
            }
            if (!req->simple) {
                req_write(req, "HTTP/1.0 200 OK-GUNZIP\r\n");
                print_http_headers(req);
                print_last_modified(req);
                req_write(req, "Content-Type: ");
                req_write(req, get_mime_type(directory_index));
                req_write(req, "\r\n\r\n");
                req_flush(req);
            }
            if (req->method == M_HEAD)
                return 0;
            return init_cgi(req);
        }
#endif
    }

    /* only here if index.html, index.html.gz don't exist */
    if (dirmaker != NULL) {     /* don't look for index.html... maybe automake? */
        req->response_status = R_REQUEST_OK;
        SQUASH_KA(req);

        /* the indexer should take care of all headers */
        if (!req->simple) {
            req_write(req, "HTTP/1.0 200 OK\r\n");
            print_http_headers(req);
            print_last_modified(req);
            req_write(req, "Content-Type: text/html\r\n\r\n");
            req_flush(req);
        }
        if (req->method == M_HEAD)
            return 0;

        return init_cgi(req);
        /* in this case, 0 means success */
    } else if (cachedir) {
        return get_cachedir_file(req, statbuf);
    } else {                    /* neither index.html nor autogenerate are allowed */
        send_r_forbidden(req);
        return -1;              /* nothing worked */
    }
}
Example #10
0
int init_get(request * req)
{
    int data_fd, saved_errno, dynamic=0;
    struct stat statbuf;
    volatile int bytes;

    data_fd = open(req->pathname, O_RDONLY);
    saved_errno = errno; /* might not get used */

#ifdef GUNZIP
    if (data_fd == -1 && errno == ENOENT) {
        /* cannot open */
        /* it's either a gunzipped file or a directory */
        char gzip_pathname[MAX_PATH_LENGTH];
        int len;

        len = strlen(req->pathname);

        memcpy(gzip_pathname, req->pathname, len);
        memcpy(gzip_pathname + len, ".gz", 3);
        gzip_pathname[len + 3] = '\0';
        data_fd = open(gzip_pathname, O_RDONLY);
        if (data_fd != -1) {
            close(data_fd);

            req->response_status = R_REQUEST_OK;
            if (req->pathname)
                free(req->pathname);
            req->pathname = strdup(gzip_pathname);
            if (!req->pathname) {
                log_error_time();
                perror("strdup");
                send_r_error(req);
                return 0;
            }
            if (!req->simple) {
                req_write(req, "HTTP/1.0 200 OK-GUNZIP\r\n");
                print_http_headers(req);
                print_content_type(req);
                print_last_modified(req);
                req_write(req, "\r\n");
                req_flush(req);
            }
            if (req->method == M_HEAD)
                return 0;

            return init_cgi(req);
        }
    }
#endif

    if (data_fd == -1) {
        log_error_doc(req);
        errno = saved_errno;
        perror("document open");

        if (saved_errno == ENOENT)
            send_r_not_found(req);
        else if (saved_errno == EACCES)
            send_r_forbidden(req);
        else
            send_r_bad_request(req);
        return 0;
    }

    fstat(data_fd, &statbuf);

    if (S_ISDIR(statbuf.st_mode)) { /* directory */
        close(data_fd);         /* close dir */

        if (req->pathname[strlen(req->pathname) - 1] != '/') {
            char buffer[3 * MAX_PATH_LENGTH + 128];

            if (server_port != 80)
                sprintf(buffer, "http://%s:%d%s/", server_name,
                        server_port, req->request_uri);
            else
                sprintf(buffer, "http://%s%s/", server_name,
                        req->request_uri);
            send_r_moved_perm(req, buffer);
            return 0;
        }
        data_fd = get_dir(req, &statbuf); /* updates statbuf */

        if (data_fd == -1)      /* couldn't do it */
            return 0;           /* errors reported by get_dir */
        else if (data_fd <= 1)
            /* data_fd == 0 -> close it down, 1 -> continue */
            return data_fd;
        /* else, data_fd contains the fd of the file... */
    }
#ifdef DAVINCI_IPCAM
    if (req->http_uri && (req->http_uri->uri_flag & URI_FLAG_NEED_PARSE))
        dynamic = 1;
#endif
    if (req->if_modified_since && !dynamic &&
        !modified_since(&(statbuf.st_mtime), req->if_modified_since)) {
        send_r_not_modified(req);
        close(data_fd);
        return 0;
    }
    req->filesize = statbuf.st_size;
    req->last_modified = statbuf.st_mtime;

    if (req->method == M_HEAD || req->filesize == 0) {
        send_r_request_ok(req);
        close(data_fd);
        return 0;
    }

    if (req->filesize > MAX_FILE_MMAP) {
        send_r_request_ok(req); /* All's well */
        req->status = PIPE_READ;
        req->cgi_status = CGI_BUFFER;
        req->data_fd = data_fd;
        req_flush(req);         /* this should *always* complete due to
                                   the size of the I/O buffers */
        req->header_line = req->header_end = req->buffer;
        return 1;
    }

    if (req->filesize == 0) {  /* done */
        send_r_request_ok(req);     /* All's well *so far* */
        close(data_fd);
        return 1;
    }

    /* NOTE: I (Jon Nelson) tried performing a read(2)
     * into the output buffer provided the file data would
     * fit, before mmapping, and if successful, writing that
     * and stopping there -- all to avoid the cost
     * of a mmap.  Oddly, it was *slower* in benchmarks.
     */
    req->mmap_entry_var = find_mmap(data_fd, &statbuf);
    if (req->mmap_entry_var == NULL) {
        req->buffer_end = 0;
        if (errno == ENOENT)
            send_r_not_found(req);
        else if (errno == EACCES)
            send_r_forbidden(req);
        else
            send_r_bad_request(req);
        close(data_fd);
        return 0;
    }
    req->data_mem = req->mmap_entry_var->mmap;
    close(data_fd);             /* close data file */

    if ((long) req->data_mem == -1) {
        boa_perror(req, "mmap");
        return 0;
    }

#ifdef DAVINCI_IPCAM
    if (dynamic) {
            char *addr = (char *)malloc(req->filesize + 1025);
            if (addr) {
                req->mem_flag |= MFLAG_IS_MEMORY;
                req->mmap_ptr = req->data_mem;
                req->mmap_size = req->filesize;
                memcpy(addr+1024, req->data_mem, req->filesize);
                addr[req->filesize+1024] = '\0';
                req->data_mem = addr;
                req->filesize = html_argument_parse(req->authority, addr+1024, req->data_mem);
                send_request_ok_no_cache(req);     /* All's well */
                return 1;
            }
    }
#endif  // DAVINCI_IPCAM

    send_r_request_ok(req);     /* All's well */

    bytes = BUFFER_SIZE - req->buffer_end;

    /* bytes is now how much the buffer can hold
     * after the headers
     */

    if (bytes > 0) {
        if (bytes > req->filesize)
            bytes = req->filesize;

        if (sigsetjmp(env, 1) == 0) {
            handle_sigbus = 1;
            memcpy(req->buffer + req->buffer_end, req->data_mem, bytes);
            handle_sigbus = 0;
            /* OK, SIGBUS **after** this point is very bad! */
        } else {
            /* sigbus! */
            log_error_doc(req);
            reset_output_buffer(req);
            send_r_error(req);
            fprintf(stderr, "%sGot SIGBUS in memcpy!\n", get_commonlog_time());
            return 0;
        }
        req->buffer_end += bytes;
        req->filepos += bytes;
        if (req->filesize == req->filepos) {
            req_flush(req);
            req->status = DONE;
        }
    }

    /* We lose statbuf here, so make sure response has been sent */
    return 1;
}
Example #11
0
int process_header_end(request * req)
{
    if (!req->logline) {
        log_error_doc(req);
        fputs("No logline in process_header_end\n", stderr);
        send_r_error(req);
        return 0;
    }

    /* Percent-decode request */
    if (unescape_uri(req->request_uri, &(req->query_string)) == 0) {
        log_error_doc(req);
        fputs("URI contains bogus characters\n", stderr);
        send_r_bad_request(req);
        return 0;
    }

    /* clean pathname */
    clean_pathname(req->request_uri);

    if (req->request_uri[0] != '/') {
        log_error("URI does not begin with '/'\n");
        send_r_bad_request(req);
        return 0;
    }

    if (vhost_root) {
        char *c;
        if (!req->header_host) {
            req->host = strdup(default_vhost);
        } else {
            req->host = strdup(req->header_host);
        }
        if (!req->host) {
            log_error_doc(req);
            fputs("unable to strdup default_vhost/req->header_host\n", stderr);
            send_r_error(req);
            return 0;
        }
        strlower(req->host);
        /* check for port, and remove
         * we essentially ignore the port, because we cannot
         * as yet report a different port than the one we are
         * listening on
         */
        c = strchr(req->host, ':');
        if (c)
            *c = '\0';

        if (check_host(req->host) < 1) {
            log_error_doc(req);
            fputs("host invalid!\n", stderr);
            send_r_bad_request(req);
            return 0;
        }
    }

    if (translate_uri(req) == 0) { /* unescape, parse uri */
        /* errors already logged */
        SQUASH_KA(req);
        return 0;               /* failure, close down */
    }

    if (req->method == M_POST) {
        req->post_data_fd = create_temporary_file(1, NULL, 0);
        if (req->post_data_fd == 0) {
            /* errors already logged */
            send_r_error(req);
            return 0;
        }
        if (fcntl(req->post_data_fd, F_SETFD, 1) == -1) {
            log_error_doc(req);
            fputs("unable to set close-on-exec for req->post_data_fd!\n", stderr);
            close(req->post_data_fd);
            req->post_data_fd = 0;
            send_r_error(req);
            return 0;
        }
        return 1;             /* success */
    }

    if (req->cgi_type) {
        return init_cgi(req);
    }
    
    req->status = WRITE;
//    return complete_response(req);
    return init_control(req);
//    return init_get(req);       /* get and head */
}
Example #12
0
File: request.c Project: gpg/boa
int process_header_end(request * req)
{
    if (!req->logline) {
        log_error_doc(req);
        fputs("No logline in process_header_end\n", stderr);
        send_r_error(req);
        return 0;
    }

    /* Percent-decode request */
    if (unescape_uri(req->request_uri, &(req->query_string)) == 0) {
        log_error_doc(req);
        fputs("URI contains bogus characters\n", stderr);
        send_r_bad_request(req);
        return 0;
    }

    /* clean pathname */
    clean_pathname(req->request_uri);

    if (req->request_uri[0] != '/') {
        log_error("URI does not begin with '/'\n");
        send_r_bad_request(req);
        return 0;
    }


    if (use_caudium_hack) {
        /* We check whether the path is of the form "/(ll)/foo/..."
           which is used by the Caudium webserver for caching purposes
           and people have bookmarked it.  To cope with this we simply
           strip it of. */
        if (req->request_uri[0] == '/'
            && req->request_uri[1] == '('
            && req->request_uri[2] >= 'a' && req->request_uri[2] <= 'z'
            && req->request_uri[3] >= 'a' && req->request_uri[3] <= 'z'
            && req->request_uri[4] == ')'
            && req->request_uri[5] == '/'
            && req->request_uri[6] ) {
            unsigned int len = strlen(req->request_uri);
            memmove (req->request_uri, req->request_uri+5, len - 5 + 1);
        }
    }

    if (vhost_root) {
        char *c;
        if (!req->header_host) {
            req->host = strdup(default_vhost);
        } else {
            req->host = strdup(req->header_host);
        }
        if (!req->host) {
            log_error_doc(req);
            fputs("unable to strdup default_vhost/req->header_host\n", stderr);
            send_r_error(req);
            return 0;
        }
        strlower(req->host);
        /* check for port, and remove
         * we essentially ignore the port, because we cannot
         * as yet report a different port than the one we are
         * listening on
         */
        c = strchr(req->host, ':');
        if (c)
            *c = '\0';

        if (check_host(req->host) < 1) {
            log_error_doc(req);
            fputs("host invalid!\n", stderr);
            send_r_bad_request(req);
            return 0;
        }
    }

    if (translate_uri(req) == 0) { /* unescape, parse uri */
        /* errors already logged */
        SQUASH_KA(req);
        return 0;               /* failure, close down */
    }

    if (req->method == M_POST) {
        req->post_data_fd = create_temporary_file(1, NULL, 0);
        if (req->post_data_fd == 0) {
            /* errors already logged */
            send_r_error(req);
            return 0;
        }
        if (fcntl(req->post_data_fd, F_SETFD, 1) == -1) {
            boa_perror(req, "unable to set close-on-exec for req->post_data_fd!");
            close(req->post_data_fd);
            req->post_data_fd = 0;
            return 0;
        }
        return 1;             /* success */
    }

    if (req->cgi_type) {
        return init_cgi(req);
    }

    req->status = WRITE;

    return init_get(req);       /* get and head */
}
Example #13
0
int init_cgi(request * req)
{
    int child_pid;
    int pipes[2];
    int use_pipes = 0;

    SQUASH_KA(req);

    if (req->is_cgi) {
        if (complete_env(req) == 0) {
            return 0;
        }
    }
#ifdef FASCIST_LOGGING
    {
        int i;
        for (i = 0; i < req->cgi_env_index; ++i)
            fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",
                    __FILE__, req->cgi_env[i]);
    }
#endif

    if (req->is_cgi == CGI || 1) {
        use_pipes = 1;
        if (pipe(pipes) == -1) {
            log_error_time();
            perror("pipe");
            return 0;
        }

        
        if (set_nonblock_fd(pipes[0]) == -1) {
            log_error_time();
            perror("cgi-fcntl");
            close(pipes[0]);
            close(pipes[1]);
            return 0;
        }
    }

    child_pid = fork();
    switch(child_pid) {
    case -1:
        
        log_error_time();
        perror("fork");

        if (use_pipes) {
            close(pipes[0]);
            close(pipes[1]);
        }
        send_r_error(req);
        /* FIXME: There is aproblem here. send_r_error would work
           for NPH and CGI, but not for GUNZIP.  Fix that. */
        
        return 0;
        break;
    case 0:
        
        if (req->is_cgi == CGI || req->is_cgi == NPH) {
            char *foo = strdup(req->pathname);
            char *c;

            if (!foo) {
                WARN("unable to strdup pathname for req->pathname");
                _exit(1);
            }
            c = strrchr(foo, '/');
            if (c) {
                ++c;
                *c = '\0';
            } else {
                
                log_error_time();
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(1);
            }
            if (chdir(foo) != 0) {
                log_error_time();
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(1);
            }
        }
        if (use_pipes) {
            close(pipes[0]);
            
            if (dup2(pipes[1], STDOUT_FILENO) == -1) {
                log_error_time();
                perror("dup2 - pipes");
                close(pipes[1]);
                _exit(1);
            }
            close(pipes[1]);
            if (set_block_fd(STDOUT_FILENO) == -1) {
                log_error_time();
                perror("cgi-fcntl");
                _exit(1);
            }
        } else {
            
            if (dup2(req->fd, STDOUT_FILENO) == -1) {
                log_error_time();
                perror("dup2 - fd");
                _exit(1);
            }
            
            if (set_block_fd(req->fd) == -1) {
                log_error_time();
                perror("cgi-fcntl");
                _exit(1);
            }
        }
        
        if (req->method == M_POST) { 
            lseek(req->post_data_fd, SEEK_SET, 0);
            dup2(req->post_data_fd, STDIN_FILENO);
            close(req->post_data_fd);
        }
        /* Close access log, so CGI program can't scribble
         * where it shouldn't
         */
        close_access_log();

        /*
         * tie STDERR to cgi_log_fd
         * cgi_log_fd will automatically close, close-on-exec rocks!
         * if we don't tied STDERR (current log_error) to cgi_log_fd,
         *  then we ought to close it.
         */
        if (!cgi_log_fd)
            dup2(devnullfd, STDERR_FILENO);
        else
            dup2(cgi_log_fd, STDERR_FILENO);

        if (req->is_cgi) {
            char *aargv[CGI_ARGC_MAX + 1];
            create_argv(req, aargv);
            execve(req->pathname, aargv, req->cgi_env);
        } else {
            if (req->pathname[strlen(req->pathname) - 1] == '/')
                execl(dirmaker, dirmaker, req->pathname, req->request_uri,
                      NULL);
#ifdef GUNZIP
            else
                execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
                      req->pathname, NULL);
#endif
        }
        
        WARN(req->pathname);
        _exit(1);
        break;

    default:
        
        
        if (verbose_cgi_logs) {
            log_error_time();
            fprintf(stderr, "Forked child \"%s\" pid %d\n",
                    req->pathname, child_pid);
        }

        if (req->method == M_POST) {
            close(req->post_data_fd); 
            req->post_data_fd = 0;
        }

        
        if (!use_pipes)
            return 0;

        close(pipes[1]);
        req->data_fd = pipes[0];

        req->status = PIPE_READ;
        if (req->is_cgi == CGI) {
            req->cgi_status = CGI_PARSE; 
            
            req->header_line = req->header_end =
                (req->buffer + BUFFER_SIZE / 2);
        } else {
            req->cgi_status = CGI_BUFFER;
            
            req->header_line = req->header_end = req->buffer;
        }

        
        
        req->filepos = 0;
        break;
    }

    return 1;
}
Example #14
0
int init_get(request * req)
{
    int data_fd;
    struct stat statbuf;

    data_fd = open(req->pathname, O_RDONLY);

    if (data_fd == -1) {        /* cannot open */
        /* it's either a gunzipped file or a directory */

#ifdef GUNZIP
        char gzip_pathname[MAX_PATH_LENGTH];
        int len;

        len = strlen(req->pathname);

        memcpy(gzip_pathname, req->pathname, len);
        memcpy(gzip_pathname + len, ".gz", 3);
        gzip_pathname[len + 3] = '\0';
        data_fd = open(gzip_pathname, O_RDONLY);
        if (data_fd == -1) {
#endif
            int errno_save = errno;
            log_error_doc(req);
            errno = errno_save;
            perror("document open");
            errno = errno_save;

            if (errno == ENOENT)
                send_r_not_found(req);
            else if (errno == EACCES)
                send_r_forbidden(req);
            else
                send_r_bad_request(req);
            return 0;
#ifdef GUNZIP
        }
        close(data_fd);

        req->response_status = R_REQUEST_OK;
        if (!req->simple) {
            req_write(req, "HTTP/1.0 200 OK-GUNZIP\r\n");
            print_http_headers(req);
            print_content_type(req);
            print_last_modified(req);
            req_write(req, "\r\n");
            req_flush(req);
        }
        if (req->method == M_HEAD)
            return 0;
        if (req->pathname)
            free(req->pathname);
        req->pathname = strdup(gzip_pathname);
        return init_cgi(req);
#endif
    }
    fstat(data_fd, &statbuf);

    if (S_ISDIR(statbuf.st_mode)) { /* directory */
        close(data_fd);         /* close dir */

        if (req->pathname[strlen(req->pathname) - 1] != '/') {
            char buffer[3 * MAX_PATH_LENGTH + 128];

            if (server_port != 80)
                sprintf(buffer, "http://%s:%d%s/", server_name,
                        server_port, req->request_uri);
            else
                sprintf(buffer, "http://%s%s/", server_name,
                        req->request_uri);
            send_redirect_perm(req, buffer);
            return 0;
        }
        data_fd = get_dir(req, &statbuf); /* updates statbuf */

        if (data_fd == -1)      /* couldn't do it */
            return 0;           /* errors reported by get_dir */
        else if (data_fd <= 1)
            /* data_fd == 0 -> close it down, 1 -> continue */
            return data_fd;
        /* else, data_fd contains the fd of the file... */
    }
    if (req->if_modified_since &&
        !modified_since(&(statbuf.st_mtime), req->if_modified_since)) {
        send_r_not_modified(req);
        close(data_fd);
        return 0;
    }
    req->filesize = statbuf.st_size;
    req->last_modified = statbuf.st_mtime;

    if (req->method == M_HEAD) {
        send_r_request_ok(req);
        close(data_fd);
        return 0;
    }

    if (req->filesize > MAX_FILE_MMAP) {
        send_r_request_ok(req); /* All's well */
        req->status = PIPE_READ;
        req->cgi_status = CGI_BUFFER;
        req->data_fd = data_fd;
        req_flush(req);         /* this should *always* complete due to
                                   the size of the I/O buffers */
        req->header_line = req->header_end = req->buffer;
        return 1;
    }

    req->mmap_entry_var = find_mmap(data_fd, &statbuf);
    if (req->mmap_entry_var == NULL) {
        send_r_error(req);
        close(data_fd);
        return 0;
    }
    req->data_mem = req->mmap_entry_var->mmap;
    close(data_fd);             /* close data file */

    if ((long) req->data_mem == -1) {
        boa_perror(req, "mmap");
        return 0;
    }

    send_r_request_ok(req);     /* All's well */
    {                           /* combine first part of file with headers */
        int bob;

        bob = BUFFER_SIZE - req->buffer_end;
        /* bob is now how much the buffer can hold
         * after the headers
         */

        if (bob > 0) {
            if (bob > req->filesize)
                bob = req->filesize;

            memcpy(req->buffer + req->buffer_end, req->data_mem, bob);
            req->buffer_end += bob;
            req->filepos += bob;
            if (req->filesize == req->filepos) {
                req_flush(req);
                req->status = DONE;
                return 1;       /* get it flushed next time around if need be */
            }
        }
    }

    /* We lose statbuf here, so make sure response has been sent */
    return 1;
}
Example #15
0
int init_get(request * req)
{
    int data_fd, saved_errno;
    struct stat statbuf;
    volatile int bytes;

    data_fd = open(req->pathname, O_RDONLY);
    saved_errno = errno; 

#ifdef GUNZIP
    if (data_fd == -1 && errno == ENOENT) {
        
        
        char gzip_pathname[MAX_PATH_LENGTH];
        int len;

        len = strlen(req->pathname);

        memcpy(gzip_pathname, req->pathname, len);
        memcpy(gzip_pathname + len, ".gz", 3);
        gzip_pathname[len + 3] = '\0';
        data_fd = open(gzip_pathname, O_RDONLY);
        if (data_fd != -1) {
            close(data_fd);

            req->response_status = R_REQUEST_OK;
            if (req->pathname)
                free(req->pathname);
            req->pathname = strdup(gzip_pathname);
            if (!req->pathname) {
                log_error_time();
                perror("strdup");
                send_r_error(req);
                return 0;
            }
            if (!req->simple) {
                req_write(req, "HTTP/1.0 200 OK-GUNZIP\r\n");
                print_http_headers(req);
                print_content_type(req);
                print_last_modified(req);
                req_write(req, "\r\n");
                req_flush(req);
            }
            if (req->method == M_HEAD)
                return 0;

            return init_cgi(req);
        }
    }
#endif

    if (data_fd == -1) {
        log_error_doc(req);
        errno = saved_errno;
        perror("document open");

        if (saved_errno == ENOENT)
            send_r_not_found(req);
        else if (saved_errno == EACCES)
            send_r_forbidden(req);
        else
            send_r_bad_request(req);
        return 0;
    }

    fstat(data_fd, &statbuf);

    if (S_ISDIR(statbuf.st_mode)) { 
        close(data_fd);         

        if (req->pathname[strlen(req->pathname) - 1] != '/') {
            char buffer[3 * MAX_PATH_LENGTH + 128];

            if (server_port != 80)
                sprintf(buffer, "http://%s:%d%s/", server_name,
                        server_port, req->request_uri);
            else
                sprintf(buffer, "http://%s%s/", server_name,
                        req->request_uri);
            send_r_moved_perm(req, buffer);
            return 0;
        }
        data_fd = get_dir(req, &statbuf); 

        if (data_fd == -1)      
            return 0;           
        else if (data_fd <= 1)
            
            return data_fd;
        
    }
    if (req->if_modified_since &&
        !modified_since(&(statbuf.st_mtime), req->if_modified_since)) {
        send_r_not_modified(req);
        close(data_fd);
        return 0;
    }
    req->filesize = statbuf.st_size;
    req->last_modified = statbuf.st_mtime;

    if (req->method == M_HEAD || req->filesize == 0) {
        send_r_request_ok(req);
        close(data_fd);
        return 0;
    }

    if (req->filesize > MAX_FILE_MMAP) {
        send_r_request_ok(req); 
        req->status = PIPE_READ;
        req->cgi_status = CGI_BUFFER;
        req->data_fd = data_fd;
        req_flush(req);         /* this should *always* complete due to
                                   the size of the I/O buffers */
        req->header_line = req->header_end = req->buffer;
        return 1;
    }

    if (req->filesize == 0) {  
        send_r_request_ok(req);     
        close(data_fd);
        return 1;
    }

    /* NOTE: I (Jon Nelson) tried performing a read(2)
     * into the output buffer provided the file data would
     * fit, before mmapping, and if successful, writing that
     * and stopping there -- all to avoid the cost
     * of a mmap.  Oddly, it was *slower* in benchmarks.
     */
    req->mmap_entry_var = find_mmap(data_fd, &statbuf);
    if (req->mmap_entry_var == NULL) {
        req->buffer_end = 0;
        if (errno == ENOENT)
            send_r_not_found(req);
        else if (errno == EACCES)
            send_r_forbidden(req);
        else
            send_r_bad_request(req);
        close(data_fd);
        return 0;
    }
    req->data_mem = req->mmap_entry_var->mmap;
    close(data_fd);             

    if ((long) req->data_mem == -1) {
        boa_perror(req, "mmap");
        return 0;
    }

    send_r_request_ok(req);     

    bytes = BUFFER_SIZE - req->buffer_end;

    /* bytes is now how much the buffer can hold
     * after the headers
     */

    if (bytes > 0) {
        if (bytes > req->filesize)
            bytes = req->filesize;

        if (sigsetjmp(env, 1) == 0) {
            handle_sigbus = 1;
            memcpy(req->buffer + req->buffer_end, req->data_mem, bytes);
            handle_sigbus = 0;
            
        } else {
            
            log_error_doc(req);
            reset_output_buffer(req);
            send_r_error(req);
            fprintf(stderr, "%sGot SIGBUS in memcpy!\n", get_commonlog_time());
            return 0;
        }
        req->buffer_end += bytes;
        req->filepos += bytes;
        if (req->filesize == req->filepos) {
            req_flush(req);
            req->status = DONE;
        }
    }

    
    return 1;
}
Example #16
0
int get_dir(request * req, struct stat *statbuf)
{

    char pathname_with_index[MAX_PATH_LENGTH];
    int data_fd;

    if (directory_index) {      
        strcpy(pathname_with_index, req->pathname);
        strcat(pathname_with_index, directory_index);
        /*
           sprintf(pathname_with_index, "%s%s", req->pathname, directory_index);
         */

        data_fd = open(pathname_with_index, O_RDONLY);

        if (data_fd != -1) {    
            strcpy(req->request_uri, directory_index); 
            fstat(data_fd, statbuf);
            return data_fd;
        }
        if (errno == EACCES) {
            send_r_forbidden(req);
            return -1;
        } else if (errno != ENOENT) {
            
            send_r_not_found(req);
            return -1;
        }

#ifdef GUNZIP
        /* if we are here, trying index.html didn't work
         * try index.html.gz
         */
        strcat(pathname_with_index, ".gz");
        data_fd = open(pathname_with_index, O_RDONLY);
        if (data_fd != -1) {    
            close(data_fd);

            req->response_status = R_REQUEST_OK;
            SQUASH_KA(req);
            if (req->pathname)
                free(req->pathname);
            req->pathname = strdup(pathname_with_index);
            if (!req->pathname) {
                log_error_time();
                perror("strdup");
                send_r_error(req);
                return 0;
            }
            if (!req->simple) {
                req_write(req, "HTTP/1.0 200 OK-GUNZIP\r\n");
                print_http_headers(req);
                print_last_modified(req);
                req_write(req, "Content-Type: ");
                req_write(req, get_mime_type(directory_index));
                req_write(req, "\r\n\r\n");
                req_flush(req);
            }
            if (req->method == M_HEAD)
                return 0;
            return init_cgi(req);
        }
#endif
    }

    
    if (dirmaker != NULL) {     
        req->response_status = R_REQUEST_OK;
        SQUASH_KA(req);

        
        if (!req->simple) {
            req_write(req, "HTTP/1.0 200 OK\r\n");
            print_http_headers(req);
            print_last_modified(req);
            req_write(req, "Content-Type: text/html\r\n\r\n");
            req_flush(req);
        }
        if (req->method == M_HEAD)
            return 0;

        return init_cgi(req);
        
    } else if (cachedir) {
        return get_cachedir_file(req, statbuf);
    } else {                    
        send_r_forbidden(req);
        return -1;              
    }
}