Example #1
0
/* R_SERVICE_UNAVAILABLE: 503 */
void send_r_service_unavailable(request * req) /* 503 */
{
    static char body[] =
        "<HTML><HEAD><TITLE>503 Service Unavailable</TITLE></HEAD>\n"
        "<BODY><H1>503 Service Unavailable</H1>\n"
        "There are too many connections in use right now.\r\n"
        "Please try again later.\r\n</BODY></HTML>\n";
    static int _body_len;
    static char *body_len;

    if (!_body_len)
        _body_len = strlen(body);
    if (!body_len)
        body_len = strdup(simple_itoa(_body_len));


    SQUASH_KA(req);
    req->response_status = R_SERVICE_UNAV;
    if (!req->simple) {
        req_write(req, "HTTP/1.0 503 Service Unavailable\r\n");
        print_http_headers(req);
        req_write(req, "Content-Length: ");
        req_write(req, body_len);
        req_write(req, "\r\nContent-Type: " HTML "\r\n\r\n"); /* terminate header
                                                               */
    }
    if (req->method != M_HEAD) {
        req_write(req, body);
    }
    req_flush(req);
}
Example #2
0
/* R_MOVED_TEMP: 302 */
void send_redirect_temp(request * req, char *url, char *more_hdr)
{
    SQUASH_KA(req);
    req->response_status = R_MOVED_TEMP;
    if (!req->simple) {
        req_write(req, "HTTP/1.0 302 Moved Temporarily\r\n");
        print_http_headers(req);
        req_write(req, "Content-Type: " HTML "\r\n");

        req_write(req, "Location: ");
        req_write_escape_http(req, url);
        req_write(req, "\r\n");
        req_write(req, more_hdr);
        req_write(req, "\r\n\r\n");
    }
    if (req->method != M_HEAD) {
        req_write(req,
                  "<HTML><HEAD><TITLE>302 Moved Temporarily</TITLE></HEAD>\n"
                  "<BODY>\n<H1>302 Moved</H1>The document has moved\n"
                  "<A HREF=\"");
        req_write_escape_html(req, url);
        req_write(req, "\">here</A>.\n</BODY></HTML>\n");
    }
    req_flush(req);
}
Example #3
0
/* R_NOT_MODIFIED: 304 */
void send_r_not_modified(request * req)
{
    SQUASH_KA(req);
    req->response_status = R_NOT_MODIFIED;
    req_write(req, "HTTP/1.0 304 Not Modified\r\n");
    print_http_headers(req);
    print_content_type(req);
    req_write(req, "\r\n");
    req_flush(req);
}
Example #4
0
/* R_BAD_REQUEST: 400 */
void send_r_bad_request(request * req)
{
    SQUASH_KA(req);
    req->response_status = R_BAD_REQUEST;
    if (!req->simple) {
        req_write(req, "HTTP/1.0 400 Bad Request\r\n");
        print_http_headers(req);
        req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
    }
    if (req->method != M_HEAD)
        req_write(req,
                  "<HTML><HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n"
                  "<BODY><H1>400 Bad Request</H1>\nYour client has issued "
                  "a malformed or illegal request.\n</BODY></HTML>\n");
    req_flush(req);
}
Example #5
0
/* R_NOT_FOUND: 404 */
void send_r_not_found(request * req)
{
    SQUASH_KA(req);
    req->response_status = R_NOT_FOUND;
    if (!req->simple) {
        req_write(req, "HTTP/1.0 404 Not Found\r\n");
        print_http_headers(req);
        req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
    }
    if (req->method != M_HEAD) {
        req_write(req, "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
                  "<BODY><H1>404 Not Found</H1>\nThe requested URL ");
        req_write_escape_html(req, req->request_uri);
        req_write(req, " was not found on this server.\n</BODY></HTML>\n");
    }
    req_flush(req);
}
Example #6
0
/* R_BAD_GATEWAY: 502 */
void send_r_bad_gateway(request * req)
{
    SQUASH_KA(req);
    req->response_status = R_BAD_GATEWAY;
    if (!req->simple) {
        req_write(req, "HTTP/1.0 502 Bad Gateway" CRLF);
        print_http_headers(req);
        req_write(req, "Content-Type: " HTML CRLF CRLF); /* terminate header */
    }
    if (req->method != M_HEAD) {
        req_write(req,
                  "<HTML><HEAD><TITLE>502 Bad Gateway</TITLE></HEAD>\n"
                  "<BODY><H1>502 Bad Gateway</H1>\nThe CGI was "
                  "not CGI/1.1 compliant.\n" "</BODY></HTML>\n");
    }
    req_flush(req);
}
Example #7
0
/* R_NOT_IMP: 501 */
void send_r_not_implemented(request * req)
{
    SQUASH_KA(req);
    req->response_status = R_NOT_IMP;
    if (!req->simple) {
        req_write(req, "HTTP/1.0 501 Not Implemented\r\n");
        print_http_headers(req);
        req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
    }
    if (req->method != M_HEAD) {
        req_write(req,
                  "<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>\n"
                  "<BODY><H1>501 Not Implemented</H1>\nPOST to non-script "
                  "is not supported in Boa.\n</BODY></HTML>\n");
    }
    req_flush(req);
}
Example #8
0
/* R_ERROR: 500 */
void send_r_error(request * req)
{
    SQUASH_KA(req);
    req->response_status = R_ERROR;
    if (!req->simple) {
        req_write(req, "HTTP/1.0 500 Server Error\r\n");
        print_http_headers(req);
        req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
    }
    if (req->method != M_HEAD) {
        req_write(req,
                  "<HTML><HEAD><TITLE>500 Server Error</TITLE></HEAD>\n"
                  "<BODY><H1>500 Server Error</H1>\nThe server encountered "
                  "an internal error and could not complete your request.\n"
                  "</BODY></HTML>\n");
    }
    req_flush(req);
}
Example #9
0
/* R_FORBIDDEN: 403 */
void send_r_forbidden(request * req)
{
    SQUASH_KA(req);
    req->response_status = R_FORBIDDEN;
    if (!req->simple) {
        req_write(req, "HTTP/1.0 403 Forbidden\r\n");
        print_http_headers(req);
        req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
    }
    if (req->method != M_HEAD) {
        req_write(req, "<HTML><HEAD><TITLE>403 Forbidden</TITLE></HEAD>\n"
                  "<BODY><H1>403 Forbidden</H1>\nYour client does not "
                  "have permission to get URL ");
        req_write_escape_html(req, req->request_uri);
        req_write(req, " from this server.\n</BODY></HTML>\n");
    }
    req_flush(req);
}
Example #10
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 #11
0
/* R_NOT_IMP: 505 */
void send_r_bad_version(request * req)
{
    SQUASH_KA(req);
    req->response_status = R_BAD_VERSION;
    if (!req->simple) {
        req_write(req, "HTTP/1.0 505 HTTP Version Not Supported\r\n");
        print_http_headers(req);
        req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
    }
    if (req->method != M_HEAD) {
        req_write(req,
                  "<HTML><HEAD><TITLE>505 HTTP Version Not Supported</TITLE></HEAD>\n"
                  "<BODY><H1>505 HTTP Version Not Supported</H1>\nHTTP versions "
                  "other than 0.9 and 1.0 "
                  "are not supported in Boa.\n<p><p>Version encountered: ");
        req_write(req, req->http_version);
        req_write(req, "<p><p></BODY></HTML>\n");
    }
    req_flush(req);
}
Example #12
0
int init_form(request * req)
{
#ifndef NEW_POST
	struct stat statbuf;
#endif
	SQUASH_KA(req);
	complete_env(req);

// davidhsu --------------------------------
#ifndef NEW_POST
	fstat(req->post_data_fd, &statbuf);
	if (req->method == M_POST)
	{
//		char *buf;
//		buf=(char *)malloc(statbuf.st_size+1);
//		lseek(req->post_data_fd, SEEK_SET, 0);
		lseek(req->post_data_fd, SEEK_END, 0);
//		read(req->post_data_fd,buf,statbuf.st_size);
//		buf[statbuf.st_size]=0;
//		free(buf);	
	}
#else
	if (req->method == M_POST)
		req->post_data_idx = req->post_data_len;		
#endif	
//-------------------------------------
	
	
//	req->status = CLOSE;		
	handleForm(req);
#if 0
	if(memcmp(req->buffer,"HTTP/1.0 301",12)==0) 		
	{
		return 0;
	}
#endif	
// davidhsu
//	return 1;
return 0;
}
Example #13
0
/* R_UNAUTHORIZED: 401 */
void send_r_unauthorized(request * req, char *realm_name)
{
    SQUASH_KA(req);
    req->response_status = R_UNAUTHORIZED;
    if (!req->simple) {
        req_write(req, "HTTP/1.0 401 Unauthorized\r\n");
        print_http_headers(req);
        req_write(req, "WWW-Authenticate: Basic realm=\"");
        req_write(req, realm_name);
        req_write(req, "\"\r\n");
        req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
    }
    if (req->method != M_HEAD) {
        req_write(req,
                  "<HTML><HEAD><TITLE>401 Unauthorized</TITLE></HEAD>\n"
                  "<BODY><H1>401 Unauthorized</H1>\nYour client does not "
                  "have permission to get URL ");
        req_write_escape_html(req, req->request_uri);
        req_write(req, " from this server.\n</BODY></HTML>\n");
    }
    req_flush(req);
}
Example #14
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 #15
0
void free_request(request ** list_head_addr, request * req)
{
	if (req->buffer_end)
		return;

	dequeue(list_head_addr, req);	/* dequeue from ready or block list */

	if (req->buffer_end)
		FD_CLR(req->fd, &block_write_fdset);
	else {
		switch (req->status) {
		case PIPE_WRITE:
		case WRITE:
			FD_CLR(req->fd, &block_write_fdset);
			break;
		case PIPE_READ:
			FD_CLR(req->data_fd, &block_read_fdset);
			break;
		case BODY_WRITE:
			FD_CLR(req->post_data_fd, &block_write_fdset);
			break;
		default:
			FD_CLR(req->fd, &block_read_fdset);
		}
	}

	if (req->logline)			/* access log */
		log_access(req);

	if (req->data_mem)
		munmap(req->data_mem, req->filesize);
	
	if (req->data_fd)
		close(req->data_fd);
	
	if (req->response_status >= 400)
		status.errors++;

	if ((req->keepalive == KA_ACTIVE) &&
		(req->response_status < 400) &&
		(++req->kacount < ka_max)) {

		request *conn;

		conn = new_request();
		conn->fd = req->fd;
		conn->status = READ_HEADER;
		conn->header_line = conn->client_stream;
		conn->time_last = time_counter;
		conn->kacount = req->kacount;
#ifdef SERVER_SSL
		conn->ssl = req->ssl; /*MN*/
#endif /*SERVER_SSL*/
		
		/* we don't need to reset the fd parms for conn->fd because
		   we already did that for req */
		/* for log file and possible use by CGI programs */
		
		strcpy(conn->remote_ip_addr, req->remote_ip_addr);

		/* for possible use by CGI programs */
		conn->remote_port = req->remote_port;
		
		if (req->local_ip_addr)
			conn->local_ip_addr = strdup(req->local_ip_addr);

		status.requests++;
		
		if (conn->kacount + 1 == ka_max)
			SQUASH_KA(conn);
				
		conn->pipeline_start = req->client_stream_pos - 
								req->pipeline_start;
		
		if (conn->pipeline_start) {
			memcpy(conn->client_stream,
				req->client_stream + req->pipeline_start,
				conn->pipeline_start);			
			enqueue(&request_ready, conn);				
		} else
			block_request(conn);
	} else{
		if (req->fd != -1) {
			status.connections--;
			safe_close(req->fd);
		}
		req->fd = -1;
#ifdef SERVER_SSL
		SSL_free(req->ssl);
#endif /*SERVER_SSL*/
	}

	if (req->cgi_env) {
		int i = COMMON_CGI_VARS;
		req->cgi_env[req->cgi_env_index]=0;
		while (req->cgi_env[i])
		{
			free(req->cgi_env[i++]);
		}
		free(req->cgi_env);
	}
	if (req->pathname)
		free(req->pathname);
	if (req->path_info)
		free(req->path_info);
	if (req->path_translated)
		free(req->path_translated);
	if (req->script_name)
		free(req->script_name);
	if (req->query_string)
		free(req->query_string);
	if (req->local_ip_addr)
		free(req->local_ip_addr);
/*
 *	need to clean up if anything went wrong
 */
	if (req->post_file_name) {
		unlink(req->post_file_name);
		free(req->post_file_name);
		close(req->post_data_fd);
		req->post_data_fd = -1;
		req->post_file_name = NULL;
	}

	enqueue(&request_free, req);	/* put request on the free list */

	return;
}
Example #16
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 #17
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;              
    }
}
Example #18
0
int read_header(request * req)
{
	int bytes, buf_bytes_left;
	char *check, *buffer;

	if (req->pipeline_start){
		buffer = req->client_stream;
		bytes = req->client_stream_pos = req->pipeline_start;
		req->pipeline_start = 0;
	} else { /* first from free_request */
		buffer = req->client_stream + req->client_stream_pos;
		buf_bytes_left = CLIENT_STREAM_SIZE - req->client_stream_pos;
		if (buf_bytes_left < 0) {
#ifdef BOA_TIME_LOG
			log_error_time();
			fputs("buffer overrun - read.c, read_header - closing\n", stderr);
#endif
			return 0;
		}
		/*MN stuff to support ssl*/
#ifdef SERVER_SSL
		if(req->ssl == NULL){
#endif /*SERVER_SSL*/
			bytes = read(req->fd, buffer, buf_bytes_left);
#ifdef SERVER_SSL
		}
		else{
			char tmp;
			bytes = SSL_read(req->ssl, buffer, buf_bytes_left);
#if 0
			printf("SSL_read 1\n");
			if(bytes > 0){
				tmp = buffer[bytes-1];
				buffer[bytes-1] = '\0';
				printf("buffer-\n %s\n----------\n", buffer);
				buffer[bytes-1] = tmp;
			}
#endif /*0*/
		}
#endif /*SERVER_SSL*/

		if (bytes == -1) {
			if (errno == EINTR)
				return 1;
			if (errno == EAGAIN || errno == EWOULDBLOCK)	/* request blocked */
				return -1;
			else if (errno == EBADF || errno == EPIPE) {
				SQUASH_KA(req);		/* force close fd */
				return 0;
			} else {
#if 0
				boa_perror(req, "header read");
#endif
				return 0;
			}
		} else if (bytes == 0)
			return 0;
		req->client_stream_pos += bytes;
	}

	check = buffer;

	while (check < (buffer + bytes)) {
		switch (req->status) {
		case READ_HEADER:
			if (*check == '\r') {
				req->status = ONE_CR;
				req->header_end = check;
			} else if (*check == '\n') {
				req->status = ONE_LF;
				req->header_end = check;
			}
			break;

		case ONE_CR:
			if (*check == '\n')
				req->status = ONE_LF;
			else
				req->status = READ_HEADER;
			break;

		case ONE_LF:			/* if here, we've found the end (for sure) of a header */
			if (*check == '\r')	/* could be end o headers */
				req->status = TWO_CR;
			else if (*check == '\n')
				req->status = BODY_READ;
			else
				req->status = READ_HEADER;
			break;

		case TWO_CR:
			if (*check == '\n')
				req->status = BODY_READ;
			else
				req->status = READ_HEADER;
			break;

		default:
			break;
		}

		++check;

		if (req->status == ONE_LF) {
			*req->header_end = '\0';
			/* terminate string that begins at req->header_line */
			/* (or at req->data_mem, if we've never been here before */

			/* the following logic still needs work, esp. after req->simple */
			if (req->logline)
				process_option_line(req);
			else {
				if (process_logline(req) == 0)
					return 0;
				if (req->simple)
					return process_header_end(req);
			}
			req->header_line = check; /* start of unprocessed data */
		} else if (req->status == BODY_READ) {
			int retval = process_header_end(req);
			/* process_header_end inits non-POST cgi's */
			
			req->pipeline_start = (check - req->client_stream);

			if (retval && req->method == M_POST) {

				/* rest of non-header data is contained in
				   the area following check

				   check now points to data 
				 */

				if (req->content_length)
					req->filesize = atoi(req->content_length);
				else {
#ifdef BOA_TIME_LOG
					log_error_time();
					fprintf(stderr, "Unknown Content-Length POST\n");
#endif
				}
				
				/* buffer + bytes is 1 past the end of the data */
				req->filepos = (buffer + bytes) - check;

				/* copy the remainder into req->buffer, otherwise
				 * we don't have a full BUFFER_SIZE to play with,
				 * and buffer overruns occur */
				memcpy(req->buffer, check, req->filepos);
				req->header_line = req->buffer;
				req->header_end = req->buffer + req->filepos;				

				if (req->filepos >= req->filesize)
					req->cgi_status = CGI_CLOSE;	/* close after write */
			}
			return retval;		/* 0 - close it done, 1 - keep on ready */
		}
	}

	/* check for bogus requests */
	if (req->status == READ_HEADER && request_type(req) == M_INVALID) {
		syslog(LOG_ERR, "malformed request: \"%s\"\n", req->logline);
		send_r_bad_request(req);
		return 0;
	}

	/* only reached if request is split across more than one packet */
	return 1;
}
Example #19
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 #20
0
int init_get2(request * req)
{
	int data_fd;
	//Brad add begin for update content length
	char *content_length_orig1;
	char *content_length_orig2;
	int orig_char_length=0;
	int exact_char_length=0;
	int byte_shift=0;
	int exact_size=0;
	int total_length_shift=0;
	char *exact_content=NULL;
	int head_offset=0;
	int first_offset=0;
	int antecedent_segment=0;
	int subsequent_segment=0;
	//Brad add end for update content length
#ifdef GUNZIP
	char buf[MAX_PATH_LENGTH];
#endif
	struct stat statbuf;
	SQUASH_KA(req);

	complete_env(req);

	middle_segment=0;
	req->cgi_env[req->cgi_env_index] = NULL;     /* terminate cgi env */
	if ((strstr(req->request_uri,".htm")==NULL) &&
	    (strstr(req->request_uri,".asp")==NULL)) {
			return 1;
	}

	data_fd = open(req->pathname, O_RDONLY);
	if (data_fd == -1) {		/* cannot open */
#ifdef GUNZIP
		sprintf(buf, "%s.gz", req->pathname);
		data_fd = open(buf, O_RDONLY);
		if (data_fd == -1) {
#endif
			int errno_save = errno;
			log_error_doc(req);
			errno = errno_save;
#if 0
			perror("document open");
#endif
//			syslog(LOG_ERR, "Error opening %s for %s: %s\n", req->pathname,
//					req->remote_ip_addr, strerror(errno_save));
			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(buf);
		return init_cgi(req);	/* 1 - OK, 2 - die */
#endif
	}
	fstat(data_fd, &statbuf);
	if (S_ISDIR(statbuf.st_mode)) {
		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/", req->host?req->host:server_name, server_port,
						req->request_uri);
			else
				sprintf(buffer, "http://%s%s/", req->host?req->host: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 == 0) {
			return 1;
		}
	}

//start modify here : tony
#if 0	
	if (req->if_modified_since &&
		!modified_since(&(statbuf.st_mtime), req->if_modified_since)) {
		send_r_not_modified(req);
		close(data_fd);
		return 0;
	}
#endif


	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;
	}
	/* MAP_OPTIONS: see compat.h */
	req->data_mem = mmap(0, req->filesize, 
#ifdef USE_NLS			
			PROT_READ|PROT_WRITE
#else
			PROT_READ
#endif
			, MAP_OPTIONS,data_fd, 0);

	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 */

	{
		//parse and send asp page
		char *left,*right,*last_right=req->data_mem;
		int bob;
		first_offset=req->buffer_end;     //Brad add for update content length
		while (1) {
			left=strstr(last_right,"<%");
			if (left!=NULL)
				right=strstr(left,"%>");

			if ((left!=NULL) && (right!=NULL)) {
				bob=(unsigned int)left-(unsigned int)last_right;
#ifdef SUPPORT_ASP
				while((bob+req->buffer_end+10)>(req->max_buffer_size)) {    //Brad modify
					int ret;
					ret=allocNewBuffer(req);	
					if (ret==-1) {
						bob=req->max_buffer_size- req->buffer_end;
						printf("will break\n");
						break;
					}
				}
#endif
				antecedent_segment =antecedent_segment+bob;		//Brad add for update content length
				if (bob>=0) {
					memcpy(req->buffer + req->buffer_end, req->data_mem + req->filepos, bob);
					last_right=right+2;
					req->buffer_end += bob;
					req->filepos += (bob+(unsigned int)last_right-(unsigned int)left);
					handleScript(req,left,right);
				}
			}
			else {
				bob=(unsigned int)req->data_mem+req->filesize-(unsigned int)last_right;
#ifdef SUPPORT_ASP
				while((bob+req->buffer_end+10)>req->max_buffer_size) {  //Brad modify
					int ret;
					ret=allocNewBuffer(req);
					if (ret==-1) {
						bob=req->max_buffer_size- req->buffer_end;
						break;
					}
				}
#endif				
				subsequent_segment = subsequent_segment+bob;    //Brad add for update content length
				if (bob > 0) {
					memcpy(req->buffer + req->buffer_end, req->data_mem + req->filepos, bob);
					req->buffer_end += bob;
					req->filepos += bob;
				}
				break;
			}
		}
	}
//Brad add begin for update content length
	exact_content = req->buffer+first_offset;
	exact_size = antecedent_segment+middle_segment+subsequent_segment;
	//fprintf(stderr, "the exact total length of asp file=%d\n", exact_size);
	
	content_length_orig1 = strstr(req->buffer, "Content-Length:");
	content_length_orig2 = strstr(content_length_orig1, "\r\n");
	content_length_orig1 = content_length_orig1 + strlen("Content-Length: ");
	orig_char_length = content_length_orig2 - content_length_orig1;
	//fprintf(stderr, "the orig_char_length=%d\n", orig_char_length);
	exact_char_length = strlen(simple_itoa(exact_size));
	//fprintf(stderr, "the exact_char_length=%d\n", exact_char_length);
	if(orig_char_length == exact_char_length) {
		//fprintf(stderr, "Update the content length with the same char length!\n");
		memcpy(content_length_orig1, simple_itoa(exact_size),exact_char_length); 
	}else if(orig_char_length < exact_char_length) {
		//fprintf(stderr, " Update the content length with shift to later bytes!\n");
		byte_shift = exact_char_length - orig_char_length;
		head_offset = first_offset- (content_length_orig2 - req->buffer);
		total_length_shift = head_offset+exact_size;
		memmove((content_length_orig2+byte_shift), content_length_orig2, total_length_shift);
		memcpy(content_length_orig1, simple_itoa(exact_size),exact_char_length); 
		req->buffer_end = req->buffer_end+byte_shift; 
	}else {
		//fprintf(stderr, "Update the content length with shift to preceding bytes!\n");
		byte_shift = orig_char_length - exact_char_length;
		head_offset = first_offset- (content_length_orig2 - req->buffer);
		total_length_shift = head_offset+exact_size;
		memmove((content_length_orig2-byte_shift), content_length_orig2, total_length_shift);
		memcpy(content_length_orig1, simple_itoa(exact_size),exact_char_length); 
		req->buffer_end = req->buffer_end-byte_shift;  
	}	
//Brad add end for update content length
	if (req->filepos == req->filesize) {
//		req->status = CLOSE;
		return 0; /* done! */
	}

	/* We lose statbuf here, so make sure response has been sent */
	return 1;
}
Example #21
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 #22
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 #23
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 #24
0
void process_requests(int server_sock)
{
    int retval = 0;
    request *current, *trailer;

    if (pending_requests) {
        get_request(server_sock);
#ifdef ORIGINAL_BEHAVIOR
        pending_requests = 0;
#endif
    }

    current = request_ready;

    while (current) {
        time(&current_time);
        retval = 1;             /* emulate "success" in case we don't have to flush */

        if (current->buffer_end && /* there is data in the buffer */
            current->status < TIMED_OUT) {
            retval = req_flush(current);
            /*
             * retval can be -2=error, -1=blocked, or bytes left
             */
            if (retval == -2) { /* error */
                current->status = DEAD;
                retval = 0;
            } else if (retval >= 0) {
                /* notice the >= which is different from below?
                   Here, we may just be flushing headers.
                   We don't want to return 0 because we are not DONE
                   or DEAD */
                retval = 1;
            }
        }

        if (retval == 1) {
            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;
            case IOSHUFFLE:
#ifdef HAVE_SENDFILE
                retval = io_shuffle_sendfile(current);
#else
                retval = io_shuffle(current);
#endif
                break;
            case DONE:
                /* a non-status that will terminate the request */
                retval = req_flush(current);
                /*
                 * retval can be -2=error, -1=blocked, or bytes left
                 */
                if (retval == -2) { /* error */
                    current->status = DEAD;
                    retval = 0;
                } else if (retval > 0) {
                    retval = 1;
                }
                break;
            case TIMED_OUT:
            case DEAD:
                retval = 0;
                current->buffer_end = 0;
                SQUASH_KA(current);
                break;
            default:
                retval = 0;
                fprintf(stderr, "Unknown status (%d), "
                        "closing!\n", current->status);
                current->status = DEAD;
                break;
            }

        }

        if (sigterm_flag)
        {
          SQUASH_KA(current);
        }

        /* we put this here instead of after the switch so that
         * if we are on the last request, and get_request is successful,
         * current->next is valid!
         */
        if (pending_requests)
            get_request(server_sock);

        switch (retval) {
        case -1:               /* request blocked */
            trailer = current;
            current = current->next;
            block_request(trailer);
            break;
        case 0:                /* request complete */
            current->time_last = current_time;
            trailer = current;
            current = current->next;
            free_request(trailer);
            break;
        case 1:                /* more to do */
            current->time_last = current_time;
            current = current->next;
            break;
        default:
            log_error_doc(current);
            fprintf(stderr, "Unknown retval in process.c - "
                    "Status: %d, retval: %d\n", current->status, retval);
            current->status = DEAD;
            current = current->next;
            break;
        }
    }
}
Example #25
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 #26
0
int init_cgi(request * req)
{
	int child_pid;
	int p[2];

	SQUASH_KA(req);

	complete_env(req);

	if (req->is_cgi == CGI) {
		if (pipe(p) == -1) {
#ifdef BOA_TIME_LOG
			log_error_time();
			perror("pipe");
#endif
			syslog(LOG_ERR, "pipe: %d.\n", errno);
			return 0;
		}
		if (fcntl(p[0], F_SETFL, O_NONBLOCK) == -1) {
#ifdef BOA_TIME_LOG
			fprintf(stderr, "Unable to do something: %d.\n", errno);
#endif
			syslog(LOG_ERR, "Unable to do something: %d.\n", errno);
			close(p[0]);
			close(p[1]);
			return 0;
		}
	}
#ifdef EMBED
	if ((child_pid = vfork()) == -1) {	/* vfork unsuccessful */
#else
	if ((child_pid = fork()) == -1) {	/* fork unsuccessful */
#endif
		if (req->is_cgi == CGI) {
			close(p[0]);
			close(p[1]);
		}
#ifdef BOA_TIME_LOG
		log_error_time();
		perror("fork");
#endif
		return 0;
	}
	/* if here, fork was successful */

	if (!child_pid) {			/* 0 == child */
		int newstdin = -1, newstdout = -1, newstderr = -1;

		if (req->is_cgi != CGI) {	/* nph or gunzip, etc... */
			newstdout = req->fd;
		} else {
			/* tie stdout to write end of pipe */
			close(p[0]);
			newstdout = p[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);
			newstdin = 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 */
		if (cgi_log_fd)
			newstderr = cgi_log_fd;
		else
			newstderr = open("/dev/null", O_WRONLY);

		/* Set up stdin/out/err without trampling over each other. */
		if (newstdin >= 0 && newstdin != STDIN_FILENO) {
			if (newstdout == STDIN_FILENO)
				newstdout = dup(newstdout);
			if (newstderr == STDIN_FILENO)
				newstderr = dup(newstderr);
			dup2(newstdin, STDIN_FILENO);
			close(newstdin);
		}
		if (newstdout >= 0 && newstdout != STDOUT_FILENO) {
			if (newstderr == STDOUT_FILENO)
				newstderr = dup(newstderr);
			dup2(newstdout, STDOUT_FILENO);
			close(newstdout);
			/* Switch socket flags back to blocking */
			if (fcntl(STDOUT_FILENO, F_SETFL, 0) == -1) {
#ifdef BOA_TIME_LOG
				perror("cgi-fcntl");
#endif
			}
		}
		if (newstderr >= 0 && newstderr != STDERR_FILENO) {
			dup2(newstderr, STDERR_FILENO);
			close(newstderr);
		}

		if (req->is_cgi) {
			char *aargv[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);
			else {
#if 0
				execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
					  req->pathname, NULL);
#endif
				syslog(LOG_ERR, "gunzip not found");
				
			}
		}
		/* execve failed */
		log_error_time();
		perror(req->pathname);
		_exit(1);
	}
	/* if here, fork was successful */

	if (verbose_cgi_logs) {
#ifdef BOA_TIME_LOG
		log_error_time();
		fprintf(stderr, "Forked child \"%s\" pid %d\n",
				req->pathname, child_pid);
#endif
		syslog(LOG_INFO, "Forked child \"%s\" pid %d\n",
				req->pathname, child_pid);
	}
	if (req->is_cgi != CGI)
		return 0;

	req->data_fd = p[0];

	/* close duplicate write end of pipe */
	close(p[1]);
	
	req->status = PIPE_READ;
	req->filesize = req->filepos = 0; /* why is this here??? */

	if (req->is_cgi == CGI) {		/* cgi */
		/* for cgi_header... I get half the buffer! */
		req->header_line = req->header_end = 
 			(req->buffer + BUFFER_SIZE / 2);
		req->cgi_status = CGI_READ;	/* got to parse cgi header */
	} else	{					/* gunzip or similar */
		req->header_line = req->header_end = req->buffer;
		req->cgi_status = CGI_WRITE;	/* don't do it. */
	}
	
	return 1;					/* success */
}
Example #27
0
File: get.c Project: gpg/boa
int process_get(request * req)
{
    off_t bytes_written;
    volatile off_t bytes_to_write;

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

    bytes_to_write = (req->ranges->stop - req->ranges->start) + 1;

    if (bytes_to_write > system_bufsize)
        bytes_to_write = system_bufsize;

    if (setjmp(env) == 0) {
        handle_sigbus = 1;
        bytes_written = write(req->fd, req->data_mem + req->ranges->start,
                              bytes_to_write);
        handle_sigbus = 0;
        /* OK, SIGBUS **after** this point is very bad! */
    } else {
        /* sigbus! */
        req->status = DEAD;
        log_error_doc(req);
        fprintf(stderr, "%sGot SIGBUS in write(2)!\n",
                get_commonlog_time());
        /* sending an error here is inappropriate
         * if we are here, the file is mmapped, and thus,
         * a content-length has been sent. If we send fewer bytes
         * the client knows there has been a problem.
         * We run the risk of accidentally sending the right number
         * of bytes (or a few too many) and the client
         * won't be the wiser.
         */
        return 0;
    }

    if (bytes_written < 0) {
        if (errno == EWOULDBLOCK || errno == EAGAIN)
            return -1;
        /* request blocked at the pipe level, but keep going */
        else {
#ifdef QUIET_DISCONNECT
            if (errno != EPIPE) {
#else
            if (1) {
#endif
                log_error_doc(req);
                /* Can generate lots of log entries, */
                perror("write");
                /* OK to disable if your logs get too big */
            }
            req->status = DEAD;
            return 0;
        }
    }

    req->bytes_written += bytes_written;
    req->ranges->start += bytes_written;

    if ((req->ranges->stop + 1 - req->ranges->start) == 0) {
        return complete_response(req);
    }

    return 1;               /* more to do */
}

/*
 * Name: get_dir
 * Description: Called from process_get if the request is a directory.
 * statbuf must describe directory on input, since we may need its
 *   device, inode, and mtime.
 * statbuf is updated, since we may need to check mtimes of a cache.
 * returns:
 *  -1 error
 *  0  cgi (either gunzip or auto-generated)
 *  >0  file descriptor of file
 */

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?? */
        unsigned int l1, l2;

        l1 = strlen(req->pathname);
        l2 = strlen(directory_index);
#ifdef GUNZIP
        if (l1 + l2 + 3 + 1 > sizeof(pathname_with_index)) { /* for .gz */
#else
        if (l1 + l2 + 1 > sizeof(pathname_with_index)) {
#endif

            errno = ENOMEM;
            boa_perror(req, "pathname_with_index not large enough for pathname + index");
            return -1;
        }
        memcpy(pathname_with_index, req->pathname, l1); /* doesn't copy NUL */
        memcpy(pathname_with_index + l1, directory_index, l2 + 1); /* does */

        data_fd = open(pathname_with_index, O_RDONLY|O_LARGEFILE);

        if (data_fd != -1) {    /* user's index file */
            /* We have to assume that directory_index will fit, because
             * if it doesn't, well, that's a huge configuration problem.
             * this is only the 'index.html' pathname for mime type
             */
            memcpy(req->request_uri, directory_index, l2 + 1); /* 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|O_LARGEFILE);
        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) {
                boa_perror(req, "strdup of pathname_with_index for .gz files " __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_last_modified(req);
                req_write(req, "Content-Type: ");
                req_write(req, get_mime_type(directory_index));
                req_write(req, CRLF CRLF);
                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->http_version != HTTP09) {
            req_write(req, http_ver_string(req->http_version));
            req_write(req, " 200 OK" CRLF);
            print_http_headers(req);
            print_last_modified(req);
            req_write(req, "Content-Type: text/html" CRLF CRLF);
            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 */
    }
}

static int get_cachedir_file(request * req, struct stat *statbuf)
{

    char pathname_with_index[MAX_PATH_LENGTH];
    int data_fd;
    time_t real_dir_mtime;

    real_dir_mtime = statbuf->st_mtime;
    /* the sizeof() doesn't need a -1 because snprintf will
     * include the NUL when calculating if the size is enough
     */
    snprintf(pathname_with_index, sizeof(pathname_with_index),
             "%s/dir.%d." PRINTF_OFF_T_ARG, cachedir,
             (int) statbuf->st_dev, statbuf->st_ino);
    data_fd = open(pathname_with_index, O_RDONLY|O_LARGEFILE);

    if (data_fd != -1) {        /* index cache */

        fstat(data_fd, statbuf);
        if (statbuf->st_mtime > real_dir_mtime) {
            statbuf->st_mtime = real_dir_mtime; /* lie */
            strcpy(req->request_uri, directory_index); /* for mimetype */
            return data_fd;
        }
        close(data_fd);
        unlink(pathname_with_index); /* cache is stale, delete it */
    }
    if (index_directory(req, pathname_with_index) == -1)
        return -1;

    data_fd = open(pathname_with_index, O_RDONLY|O_LARGEFILE); /* Last chance */
    if (data_fd != -1) {
        strcpy(req->request_uri, directory_index); /* for mimetype */
        fstat(data_fd, statbuf);
        statbuf->st_mtime = real_dir_mtime; /* lie */
        return data_fd;
    }

    boa_perror(req, "re-opening dircache");
    return -1;                  /* Nothing worked. */

}
Example #28
0
int init_cgi(request * req)
{
#ifndef EXCLUDE_CGI
    int child_pid;
    int pipes[2];
    int use_pipes = 0;
#endif

    SQUASH_KA(req);

#ifndef EXCLUDE_CGI
    if (req->cgi_type) {
        if (complete_env(req) == 0) {
            return 0;
        }
    }
    DEBUG(DEBUG_CGI_ENV) {
        int i;
        for (i = 0; i < req->cgi_env_index; ++i)
            log_error_time();
            fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",
                    __FILE__, req->cgi_env[i]);
    }

    /* we want to use pipes whenever it's a CGI or directory */
    /* otherwise (NPH, gunzip) we want no pipes */
    if (req->cgi_type == CGI ||
        (!req->cgi_type &&
         (req->pathname[strlen(req->pathname) - 1] == '/'))) {
        use_pipes = 1;
        if (pipe(pipes) == -1) {
            log_error_doc(req);
            perror("pipe");
            return 0;
        }

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

    child_pid = fork();
    switch (child_pid) {
    case -1:
        /* fork unsuccessful */
        /* FIXME: There is a problem here. send_r_error (called by
         * boa_perror) would work for NPH and CGI, but not for GUNZIP.  
         * Fix that. 
         */
        boa_perror(req, "fork failed");
        if (use_pipes) {
            close(pipes[0]);
            close(pipes[1]);
        }
        return 0;
        break;
    case 0:
        /* child */
        reset_signals();

        if (req->cgi_type == CGI || req->cgi_type == NPH) {
            char *c;
            unsigned int l;
            char *newpath, *oldpath;

            c = strrchr(req->pathname, '/');
            if (!c) {
                /* there will always be a '.' */
                log_error_doc(req);
                fprintf(stderr,
                        "unable to find '/' in req->pathname: \"%s\"\n",
                        req->pathname);
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }

            *c = '\0';

            if (chdir(req->pathname) != 0) {
                int saved_errno = errno;
                log_error_doc(req);
                fprintf(stderr, "Could not chdir to \"%s\":",
                        req->pathname);
                errno = saved_errno;
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }

            oldpath = req->pathname;
            req->pathname = ++c;
            l = strlen(req->pathname) + 3;
            /* prefix './' */
            newpath = malloc(sizeof (char) * l);
            if (!newpath) {
                /* there will always be a '.' */
                log_error_doc(req);
                perror("unable to malloc for newpath");
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }
            newpath[0] = '.';
            newpath[1] = '/';
            memcpy(&newpath[2], req->pathname, l - 2); /* includes the trailing '\0' */
            free(oldpath);
            req->pathname = newpath;
        }
        if (use_pipes) {
            /* close the 'read' end of the pipes[] */
            close(pipes[0]);
            /* tie CGI's STDOUT to our write end of pipe */
            if (dup2(pipes[1], STDOUT_FILENO) == -1) {
                log_error_doc(req);
                perror("dup2 - pipes");
                _exit(EXIT_FAILURE);
            }
            close(pipes[1]);
        } else {
            /* tie stdout to socket */
            if (dup2(req->fd, STDOUT_FILENO) == -1) {
                log_error_doc(req);
                perror("dup2 - fd");
                _exit(EXIT_FAILURE);
            }
            close(req->fd);
        }
        /* Switch socket flags back to blocking */
        if (set_block_fd(STDOUT_FILENO) == -1) {
            log_error_doc(req);
            perror("cgi-fcntl");
            _exit(EXIT_FAILURE);
        }
        /* tie post_data_fd to POST stdin */
        if (req->method == M_POST) { /* tie stdin to file */
// davidhsu ----------------------
#ifndef NEW_POST
            lseek(req->post_data_fd, SEEK_SET, 0);
            dup2(req->post_data_fd, STDIN_FILENO);
            close(req->post_data_fd);
#endif
//-------------------------------	
			
        }

#ifdef USE_SETRLIMIT
        /* setrlimit stuff.
         * This is neat!
         * RLIMIT_STACK    max stack size
         * RLIMIT_CORE     max core file size
         * RLIMIT_RSS      max resident set size
         * RLIMIT_NPROC    max number of processes
         * RLIMIT_NOFILE   max number of open files
         * RLIMIT_MEMLOCK  max locked-in-memory address space
         * RLIMIT_AS       address space (virtual memory) limit
         *
         * RLIMIT_CPU      CPU time in seconds
         * RLIMIT_DATA     max data size
         *
         * Currently, we only limit the CPU time and the DATA segment
         * We also "nice" the process.
         *
         * This section of code adapted from patches sent in by Steve Thompson
         * (no email available)
         */

        {
            struct rlimit rl;
            int retval;

            if (cgi_rlimit_cpu) {
                rl.rlim_cur = rl.rlim_max = cgi_rlimit_cpu;
                retval = setrlimit(RLIMIT_CPU, &rl);
                if (retval == -1) {
                    log_error_time();
                    fprintf(stderr,
                            "setrlimit(RLIMIT_CPU,%d): %s\n",
                            rlimit_cpu, strerror(errno));
                    _exit(EXIT_FAILURE);
                }
            }

            if (cgi_limit_data) {
                rl.rlim_cur = rl.rlim_max = cgi_rlimit_data;
                retval = setrlimit(RLIMIT_DATA, &rl);
                if (retval == -1) {
                    log_error_time();
                    fprintf(stderr,
                            "setrlimit(RLIMIT_DATA,%d): %s\n",
                            rlimit_data, strerror(errno));
                    _exit(EXIT_FAILURE);
                }
            }

            if (cgi_nice) {
                retval = nice(cgi_nice);
                if (retval == -1) {
                    log_error_time();
                    perror("nice");
                    _exit(EXIT_FAILURE);
                }
            }
        }
#endif

        umask(cgi_umask);       /* change umask *again* u=rwx,g=rxw,o= */

        /*
         * tie STDERR to cgi_log_fd
         * cgi_log_fd will automatically close, close-on-exec rocks!
         * if we don't tie STDERR (current log_error) to cgi_log_fd,
         *  then we ought to tie it to /dev/null
         *  FIXME: we currently don't tie it to /dev/null, we leave it
         *  tied to whatever 'error_log' points to.  This means CGIs can
         *  scribble on the error_log, probably a bad thing.
         */
        if (cgi_log_fd) {
            dup2(cgi_log_fd, STDERR_FILENO);
        }

        if (req->cgi_type) {
            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,
                      (void *) NULL);
#ifdef GUNZIP
            else
                execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
                      req->pathname, (void *) NULL);
#endif
        }
        /* execve failed */
        log_error_doc(req);
        fprintf(stderr, "Unable to execve/execl pathname: \"%s\"",
                req->pathname);
        perror("");
        _exit(EXIT_FAILURE);
        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) {

// davidhsu ----------------
#ifndef NEW_POST
             close(req->post_data_fd); /* child closed it too */
             req->post_data_fd = 0;
#else			 
		if (req->post_data) {
			free(req->post_data);
			req->post_data = NULL;
		}
		req->post_data_len = 0;
		req->post_data_idx = 0;
#endif		
//------------------------

        }

        /* 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->cgi_type == 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;
    }
#endif //!EXCLUDE_CGI

    return 1;
}
Example #29
0
void process_requests(int server_s, struct soap *soap)/*by SeanHou*/
{
    /* :TODO:Monday, December 01, 2014 11:17:36 HKT:SeanHou:  */
    int OnvifEN = 0;
    int lookupindex = 0;
    char service_uri[100] = "";

    memset((void*)&soap->peer, 0, sizeof(soap->peer));
    soap->socket = SOAP_INVALID_SOCKET;
    soap->error  = SOAP_OK;
    soap->errmode = 0;
    soap->keep_alive = 0;

    fprintf(stderr, "Warning:" \
            "(==>%s).\n", __func__);

    /* :TODO:End---  */
    int retval = 0;
    request *current, *trailer;

    if (pending_requests) {
        get_request(server_s);
#ifdef ORIGINAL_BEHAVIOR
        pending_requests = 0;
#endif
    }

    current = request_ready;

    while (current) {
        /* :TODO:Monday, December 01, 2014 11:18:42 HKT:SeanHou: juge is onvif */
        OnvifEN = isonvif(current->client_stream, service_uri, &lookupindex);
        if(OnvifEN == 1)
        {
            fprintf(stderr, "[boa:onvif] Warning: is onvif line[%d]remote port[%d]h2ns[%d]remote ip[%s]\n", __LINE__, current->remote_port, htons(current->remote_port), current->remote_ip_addr);
            struct sockaddr_in onvif_client_addr;
            memset(&onvif_client_addr, 0, sizeof(onvif_client_addr));
            onvif_client_addr.sin_family = AF_INET;
            onvif_client_addr.sin_port = htons(current->remote_port);//随机端口
            onvif_client_addr.sin_addr.s_addr = inet_addr(current->remote_ip_addr);//

            soap->socket = current->fd;
            soap->peer = onvif_client_addr;
            if (soap_valid_socket(soap->socket))
            {
                soap->ip = ntohl(soap->peer.sin_addr.s_addr);
                soap->port = (int)ntohs(soap->peer.sin_port);
                soap->keep_alive = (((soap->imode | soap->omode) & SOAP_IO_KEEPALIVE) != 0);
            }


            g_onvif_buffer = (char *)soap_malloc(soap, sizeof(current->client_stream));
            strcpy(g_onvif_buffer, current->client_stream);//mark

            soap_begin_recv(soap);
            if (soap_envelope_begin_in(soap))
            {
                soap_send_fault(soap);
            }
            if (soap_recv_header(soap))
            {
                soap_send_fault(soap);
            }
            if (soap_body_begin_in(soap))
            {
                soap_send_fault(soap);
            }

            int errorCode = 0;
            if (errorCode = soap_serve_request(soap))
            {
                fprintf(stderr, "[boa:onvif]soap_serve_request fail, errorCode %d \n", errorCode);
                soap_send_fault(soap);
            }

            memset(current->client_stream, 0, CLIENT_STREAM_SIZE );

            soap_dealloc(soap, NULL);
            soap_destroy(soap);      
            soap_end(soap);
            current->status = DONE;
            close(soap->socket);
            continue;
        }
        /* :TODO:End---  */
        time(&current_time);
        if (current->buffer_end && /* there is data in the buffer */
                current->status != DEAD && current->status != DONE) {
            retval = req_flush(current);
            /*
             * retval can be -2=error, -1=blocked, or bytes left
             */
            if (retval == -2) { /* error */
                current->status = DEAD;
                retval = 0;
            } else if (retval >= 0) {
                /* notice the >= which is different from below?
                   Here, we may just be flushing headers.
                   We don't want to return 0 because we are not DONE
                   or DEAD */

                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;
                case DONE:
                    /* a non-status that will terminate the request */
                    retval = req_flush(current);
                    /*
                     * retval can be -2=error, -1=blocked, or bytes left
                     */
                    if (retval == -2) { /* error */
                        current->status = DEAD;
                        retval = 0;
                    } else if (retval > 0) {
                        retval = 1;
                    }
                    break;
                case DEAD:
                    retval = 0;
                    current->buffer_end = 0;
                    SQUASH_KA(current);
                    break;
                default:
                    retval = 0;
                    fprintf(stderr, "Unknown status (%d), "
                            "closing!\n", current->status);
                    current->status = DEAD;
                    break;
            }

        }

        if (sigterm_flag)
            SQUASH_KA(current);

        /* we put this here instead of after the switch so that
         * if we are on the last request, and get_request is successful,
         * current->next is valid!
         */
        if (pending_requests)
            get_request(server_s);

        switch (retval) {
            case -1:               /* request blocked */
                trailer = current;
                current = current->next;
                block_request(trailer);
                break;
            case 0:                /* request complete */
                current->time_last = current_time;
                trailer = current;
                current = current->next;
                free_request(&request_ready, trailer);
                break;
            case 1:                /* more to do */
                current->time_last = current_time;
                current = current->next;
                break;
            default:
                log_error_time();
                fprintf(stderr, "Unknown retval in process.c - "
                        "Status: %d, retval: %d\n", current->status, retval);
                current = current->next;
                break;
        }
    }
}