static struct HTTPRequest *read_request(FILE *in) {
  struct HTTPRequest *req;
  struct HTTPHeaderField *h;

  req = xmalloc(sizeof(struct HTTPRequest));
  read_request_line(req, in);
  req->header = NULL;
  while (h = read_header_field(in)) {
    h->next = req->header;
    req->header = h;
  }
  req->length = content_length(req);
  if (req->length != 0) {
    if (req->length > MAX_REQUEST_BODY_LENGTH) {
      log_exit("request body too long");
    }
    req->body = xmalloc(req->length);
    if (fread(req->body, req->length, 1, in) < 1) {
      log_exit("failed to read request body");
    }
  } else {
    req->body = NULL;
  }
  return req;
}
int main()
{
    FILE *fin;
    char first_line[BUF_MAX_LEN];

    fin = stdin;

    if (fgets(first_line, BUF_MAX_LEN, fin) == NULL) {
	perror("fgets");
	return 1;
    }

    struct http_request_header *req;
    req = read_request_line(first_line);

    printf("=== result ===\n");
    printf("method:%s\n", req->method);
    printf("path:%s\n", req->path);
    printf("proto:%s\n", req->proto);

    free(req->method);
    free(req->path);
    free(req->proto);
    free(req);

    return 0;
}
std::unique_ptr<http::request> http::request_reader::accept_request() {
  std::string method;
  std::string request_uri;
  std::tie(method, request_uri) = read_request_line();
  auto headers = read_request_headers();
  return std::unique_ptr<http::request>(new http::request(method, request_uri, headers));
}
Beispiel #4
0
/***************************
read_request

リクエストのread
***************************/
HttpRequest* read_request(
	FILE *in
)
{
	HttpRequest 		*req;
	HttpHeaderField 	*h;
	int					ret = 0;

	req = xmalloc(sizeof(HttpRequest));
	read_request_line(req, in);
	req->header = NULL;

	while(NULL != (h = read_header_field(in)))
	{
		h->next = req->header;
		req->header = h;
	}

	req->length = content_length(req);

	if(req->length != 0)
	{

		if(req->length != MAX_REQUEST_BODY_LENGTH)
		{
			log_exit("request body too long");
		}

		req->body = xmalloc(req->length);

		ret = fread(req->body, req->length, 1, in);

		if(ret < 1)
		{
			log_exit("failed to read request body");
		}
		else
		{
			req->body = NULL;

		}
	}
	return req;
}
bool http_connection::loop(unsigned fd)
{
	socket_wrapper::io_vector io_vector[2];
	size_t total = 0;
	size_t count;
	bool ret;

	do {
		logger::instance().log(logger::LOG_DEBUG, "[http_connection::loop] (fd %d) State = %s.", fd, state_to_string(_M_state));

		switch (_M_state) {
			case BEGIN_REQUEST_STATE:
				if ((!_M_readable) && (_M_inp == (off_t) _M_in.count())) {
					return true;
				}

				if (!read_request_line(fd, total)) {
					return false;
				}

				break;
			case READING_HEADERS_STATE:
				if (!_M_readable) {
					return true;
				}

				if (!read_headers(fd, total)) {
					return false;
				}

				break;
			case PROCESSING_REQUEST_STATE:
				if (!process_request(fd)) {
					return false;
				}

				if (_M_error != http_error::OK) {
					total = 0;

					_M_state = PREPARING_ERROR_PAGE_STATE;
				} else {
					if ((_M_state != PREPARING_HTTP_REQUEST_STATE) && (_M_state != READING_BODY_STATE) && (_M_state != READING_CHUNKED_BODY_STATE)) {
						if (!modify(fd, tcp_server::WRITE)) {
							return false;
						}

						total = 0;
					}
				}

				break;
			case READING_BODY_STATE:
				if (!_M_readable) {
					return true;
				}

				if (!read_body(fd, total)) {
					return false;
				}

				break;
			case READING_CHUNKED_BODY_STATE:
				if (!_M_readable) {
					return true;
				}

				if (!read_chunked_body(fd, total)) {
					return false;
				}

				break;
			case PREPARING_HTTP_REQUEST_STATE:
				if (!prepare_http_request(fd)) {
					_M_state = PREPARING_ERROR_PAGE_STATE;
				} else {
					_M_state = WAITING_FOR_BACKEND_STATE;
				}

				break;
			case WAITING_FOR_BACKEND_STATE:
				return true;
			case PREPARING_ERROR_PAGE_STATE:
				if ((!prepare_error_page()) || (!modify(fd, tcp_server::WRITE))) {
					return false;
				}

				break;
			case SENDING_TWO_BUFFERS_STATE:
				if (!_M_writable) {
					return true;
				}

				io_vector[0].iov_base = _M_out.data();
				io_vector[0].iov_len = _M_out.count();

				io_vector[1].iov_base = _M_bodyp->data();
				io_vector[1].iov_len = _M_bodyp->count();

				if (!writev(fd, io_vector, 2, total)) {
					return false;
				} else if (_M_outp == (off_t) (_M_out.count() + _M_bodyp->count())) {
					_M_state = REQUEST_COMPLETED_STATE;
				}

				break;
			case SENDING_HEADERS_STATE:
				if (!_M_writable) {
					return true;
				}

				if (!write(fd, total)) {
					return false;
				} else if (_M_outp == (off_t) _M_out.count()) {
					if (_M_method == http_method::HEAD) {
						_M_state = REQUEST_COMPLETED_STATE;
					} else if (_M_error != http_error::OK) {
						_M_state = REQUEST_COMPLETED_STATE;
					} else if (_M_filesize == 0) {
						_M_state = REQUEST_COMPLETED_STATE;
					} else {
						if (_M_ranges.count() == 0) {
							_M_outp = 0;
						} else {
							const range_list::range* range = _M_ranges.get(0);
							_M_outp = range->from;
						}

						_M_state = SENDING_BODY_STATE;
					}
				}

				break;
			case SENDING_BODY_STATE:
				if (!_M_writable) {
					return true;
				}

				if (!sendfile(fd, _M_fd, _M_filesize, &_M_ranges, _M_nrange, total)) {
					return false;
				} else {
					size_t nranges = _M_ranges.count();

					if (nranges == 0) {
						if (_M_outp == _M_filesize) {
							socket_wrapper::uncork(fd);

							_M_state = REQUEST_COMPLETED_STATE;
						}
					} else {
						const range_list::range* range = _M_ranges.get(_M_nrange);
						if (_M_outp == range->to + 1) {
							if (nranges == 1) {
								socket_wrapper::uncork(fd);

								_M_state = REQUEST_COMPLETED_STATE;
							} else {
								_M_out.reset();

								// Last part?
								if (++_M_nrange == nranges) {
									if (!_M_out.format("\r\n--%0*u--\r\n", http_headers::BOUNDARY_WIDTH, _M_boundary)) {
										return false;
									}

									_M_state = SENDING_MULTIPART_FOOTER_STATE;
								} else {
									if (!build_part_header()) {
										return false;
									}

									_M_state = SENDING_PART_HEADER_STATE;
								}

								_M_outp = 0;
							}
						}
					}
				}

				break;
			case SENDING_PART_HEADER_STATE:
				if (!_M_writable) {
					return true;
				}

				if (!write(fd, total)) {
					return false;
				} else if (_M_outp == (off_t) _M_out.count()) {
					const range_list::range* range = _M_ranges.get(_M_nrange);
					_M_outp = range->from;

					_M_state = SENDING_BODY_STATE;
				}

				break;
			case SENDING_MULTIPART_FOOTER_STATE:
				if (!_M_writable) {
					return true;
				}

				if (!write(fd, total)) {
					return false;
				} else if (_M_outp == (off_t) _M_out.count()) {
					socket_wrapper::uncork(fd);

					_M_state = REQUEST_COMPLETED_STATE;
				}

				break;
			case SENDING_BACKEND_HEADERS_STATE:
				if (!_M_writable) {
					return true;
				}

				if ((!_M_payload_in_memory) || (_M_filesize == 0) || (_M_method == http_method::HEAD)) {
					count = _M_out.count();

					ret = write(fd, total);
				} else {
					io_vector[0].iov_base = _M_out.data();
					io_vector[0].iov_len = _M_out.count();

					if (_M_error == http_error::OK) {
						io_vector[1].iov_base = _M_body.data() + _M_backend_response_header_size;
					} else {
						io_vector[1].iov_base = _M_bodyp->data();
					}

					io_vector[1].iov_len = _M_filesize;

					count = io_vector[0].iov_len + io_vector[1].iov_len;

					ret = writev(fd, io_vector, 2, total);
				}

				if (!ret) {
					return false;
				} else if (_M_outp == (off_t) count) {
					if (_M_payload_in_memory) {
						_M_state = REQUEST_COMPLETED_STATE;
					} else {
						_M_outp = 0;

						_M_state = SENDING_BACKEND_BODY_STATE;
					}
				}

				break;
			case SENDING_BACKEND_BODY_STATE:
				if (!_M_writable) {
					return true;
				}

				if (!sendfile(fd, _M_tmpfile, _M_filesize, total)) {
					return false;
				} else if (_M_outp == _M_filesize) {
					socket_wrapper::uncork(fd);

					_M_state = REQUEST_COMPLETED_STATE;
				}

				break;
			case REQUEST_COMPLETED_STATE:
				if ((_M_vhost) && (_M_vhost->log_requests)) {
					_M_vhost->log->log(*this, fd);
				}

				// Close connection?
				if (!_M_keep_alive) {
					return false;
				} else {
					if (!modify(fd, tcp_server::READ)) {
						return false;
					}

					reset();

					// If there is more data in the input buffer...
					size_t left = _M_in.count() - _M_inp;
					if (left > 0) {
						// Move data at the beginning of the buffer.
						char* data = _M_in.data();
						memmove(data, data + _M_inp, left);
						_M_in.set_count(left);
					} else {
						_M_in.reset();
					}

					_M_inp = 0;
				}

				break;
		}
	} while (!_M_in_ready_list);

	return true;
}
Beispiel #6
0
/*
 * This is the main drive for each connection. As you can tell, for the
 * first few steps we are using a blocking socket. If you remember the
 * older tinyproxy code, this use to be a very confusing state machine.
 * Well, no more! :) The sockets are only switched into nonblocking mode
 * when we start the relay portion. This makes most of the original
 * tinyproxy code, which was confusing, redundant. Hail progress.
 * 	- rjkaes
 */
void
handle_connection(int fd)
{
	struct conn_s *connptr;
	struct request_s *request = NULL;
	hashmap_t hashofheaders = NULL;

	char peer_ipaddr[PEER_IP_LENGTH];
	char peer_string[PEER_STRING_LENGTH];

	getpeer_information(fd, peer_ipaddr, peer_string);

	log_message(LOG_CONN, "Connect (file descriptor %d): %s [%s]",
		    fd, peer_string, peer_ipaddr);

	connptr = initialize_conn(fd, peer_ipaddr, peer_string);
	if (!connptr) {
		close(fd);
		return;
	}

	if (check_acl(fd, peer_ipaddr, peer_string) <= 0) {
		update_stats(STAT_DENIED);
		indicate_http_error(connptr, 403, "Access denied",
				    "detail", "The administrator of this proxy has not configured it to service requests from your host.",
				    NULL);
		send_http_error_message(connptr);
		destroy_conn(connptr);
		return;
	}

	if (read_request_line(connptr) < 0) {
		update_stats(STAT_BADCONN);
		indicate_http_error(connptr, 408, "Timeout",
				    "detail", "Server timeout waiting for the HTTP request from the client.",
				    NULL);
		send_http_error_message(connptr);
		destroy_conn(connptr);
		return;
	}

	/*
	 * The "hashofheaders" store the client's headers.
	 */
	if (!(hashofheaders = hashmap_create(HEADER_BUCKETS))) {
		update_stats(STAT_BADCONN);
		indicate_http_error(connptr, 503, "Internal error",
				    "detail", "An internal server error occurred while processing your request.  Please contact the administrator.",
				    NULL);
		send_http_error_message(connptr);
		destroy_conn(connptr);
		return;
	}

	/*
	 * Get all the headers from the client in a big hash.
	 */
	if (get_all_headers(connptr->client_fd, hashofheaders) < 0) {
		log_message(LOG_WARNING, "Could not retrieve all the headers from the client");
		hashmap_delete(hashofheaders);
		update_stats(STAT_BADCONN);
		destroy_conn(connptr);
		return;
	}

	request = process_request(connptr, hashofheaders);
	if (!request) {
		if (!connptr->error_variables && !connptr->show_stats) {
			update_stats(STAT_BADCONN);
			destroy_conn(connptr);
			hashmap_delete(hashofheaders);
			return;
		}
		goto send_error;
	}

	connptr->upstream_proxy = UPSTREAM_HOST(request->host);
	if (connptr->upstream_proxy != NULL) {
		if (connect_to_upstream(connptr, request) < 0) {
			goto send_error;
		}
	} else {
		connptr->server_fd = opensock(request->host, request->port);
		if (connptr->server_fd < 0) {
			indicate_http_error(connptr, 500, "Unable to connect",
					    "detail", PACKAGE " was unable to connect to the remote web server.",
					    "error", strerror(errno),
					    NULL);
			goto send_error;
		}

		log_message(LOG_CONN,
			    "Established connection to host \"%s\" using file descriptor %d.",
			    request->host, connptr->server_fd);

		if (!connptr->connect_method)
			establish_http_connection(connptr, request);
	}

      send_error:
	free_request_struct(request);

	if (process_client_headers(connptr, hashofheaders) < 0) {
		update_stats(STAT_BADCONN);
		if (!connptr->error_variables) {
			hashmap_delete(hashofheaders);
			destroy_conn(connptr);
			return;
		}
	}
	hashmap_delete(hashofheaders);

	if (connptr->error_variables) {
		send_http_error_message(connptr);
		destroy_conn(connptr);
		return;
	} else if (connptr->show_stats) {
		showstats(connptr);
		destroy_conn(connptr);
		return;
	}

	if (!connptr->connect_method || (connptr->upstream_proxy != NULL)) {
		if (process_server_headers(connptr) < 0) {
			if (connptr->error_variables)
				send_http_error_message(connptr);

			update_stats(STAT_BADCONN);
			destroy_conn(connptr);
			return;
		}
	} else {
		if (send_ssl_response(connptr) < 0) {
			log_message(LOG_ERR,
				    "handle_connection: Could not send SSL greeting to client.");
			update_stats(STAT_BADCONN);
			destroy_conn(connptr);
			return;
		}
	}

	relay_connection(connptr);

	log_message(LOG_INFO, "Closed connection between local client (fd:%d) and remote client (fd:%d)",
		    connptr->client_fd, connptr->server_fd);

	/*
	 * All done... close everything and go home... :)
	 */
	destroy_conn(connptr);
	return;
}