Выбрать главу

     записывающего этот код в указанный файл. */

  (*module->generate_function)(connection_fd);

  /* Работа с модулем окончена. */

  module_close(module);

 }

}

/* Обработка клиентского запроса на подключение. */

static void handle_connection(int connection_fd) {

 char buffer[256];

 ssize_t bytes_read;

 /* Получение данных от клиента. */

 bytes_read =

  read(connection_fd, buffer, sizeof(buffer) — 1);

 if (bytes_read > 0) {

  char method[sizeof(buffer)];

  char url[sizeof(buffer)];

  char protocol[sizeof(buffer)];

  /* Часть данных успешно прочитана. Завершаем буфер

     нулевым символом, чтобы его можно было использовать

     в строковых операциях. */

  buffer[bytes_read] = '\0';

  /* Первая строка, посылаемая клиентом, -- это HTTP-запрос.

     В запросе указаны метод, запрашиваемая страница и

     версия протокола. */

  sscanf(buffer, "%s %s %s", method, url, protocol);

  /* В заголовке, стоящем после запроса, может находиться

     любая информация. В данной реализации HTTP-сервера

     эта информация не учитывается. Тем не менее необходимо

     прочитать все данные, посылаемые клиентом. Данные читаются

     до тех пор, пока не встретится конец заголовка,

     обозначаемый пустой строкой. В HTTP пустой строке

     соответствуют символы CR/LF. */

  while (strstr(buffer, " \r\n\r\n") == NULL)

   bytes_read = read(connection_fd, buffer, sizeof(buffer));

  /* Проверка правильности последней операции чтения.

     Если она не завершилась успешно, произошел разрыв

     соединения, поэтому завершаем работу. */

  if (bytes_read == -1) {

   close(connection_fd);

   return;

  }

  /* Проверка поля версии. Сервер понимает протокол HTTP

     версий 1.0 и 1.1. */

  if (strcmp(protocol, "HTTP/1.0") &&

   strcmp(protocol, "HTTP/1.1")) {

   /* Протокол не поддерживается. */

   write(connection_fd, bad_request_response,

    sizeof(bad_request_response));

  } else if (strcmp (method, "GET")) {

   /* Сервер реализует только метод GET, а клиент указал

      другой метод. */

   char response[1024];

   snprintf(response, sizeof(response),

    bad_method_response_template, method);

   write(connection_fd, response, strlen(response));

  } else

   /* Корректный запрос. Обрабатываем его. */

   handle_get(connection_fd, url);

 } else if (bytes_read == 0)

  /* Клиент разорвал соединение, не успев отправить данные.

     Ничего не предпринимаем */

  ;

 else

  /* Операция чтения завершилась ошибкой. */

  system_error("read");

}

void server_run(struct in_addr local_address, uint16_t port) {

 struct sockaddr_in socket_address;

 int rval;

 struct sigaction sigchld_action;

 int server_socket;

 /* Устанавливаем обработчик сигнала SIGCHLD, который будет

    удалять завершившееся дочерние процессы. */

 memset(&sigchld_action, 0, sizeof(sigchld_action));

 sigchld_action.sa_handler = &clean_up_child_process;

 sigaction(SIGCHLD, &sigchld_action, NULL);

 /* Создание TCP-сокета */

 server_socket = socket(PF_INET, SOCK_STREAM, 0);

 if (server_socket == -1) system_error("socket");

 /* Создание адресной структуры, определяющей адрес

    для приема запросов. */

 memset(&socket_address, 0, sizeof(socket_address));

 socket_address.sin_family = AF_INET;

 socket_address.sin_port = port;

 socket_address.sin_addr = local_address;

 /* Привязка сокета к этому адресу. */

 rval =

  bind(server_socket, &socket_address,

  sizeof(socket_address));

 if (rval != 0)

  system_error("bind");

 /* Перевод сокета в режим приема запросов. */

 rval = listen(server_socket, 10);

 if (rval != 0)

  system_error("listen");

 if (verbose) {

  /* В режиме развернутых сообщений отображаем адрес и порт,

     с которыми работает сервер. */

  socklen_t address_length;

  /* Нахождение адреса сокета. */

  address_length = sizeof(socket_address);

  rval =

   getsockname(server_socket, &socket_address, &address_length);

  assert(rval == 0);

  /* Вывод сообщения. Номер порта должен быть преобразован