C language http-server [Return a File section]

I’m stuck on Stage #(Return a File section ], ex. #JM3).

I’ve tried … ( using the normal ./your_server.sh --directory=/tmp/ , which works fine for all edge cases , but not during test) .

Here are my logs:

kali_37 ~/Documents/prg_lang/C_programming/http-server/codecrafters-http-server-c (master)$ codecrafters test
Initiating test run...

⚡ This is a turbo test run. https://codecrafters.io/turbo

Running tests. Logs should appear shortly...

[compile] Compilation successful.

Debug = true

[tester::#AP6] Running tests for Stage #AP6 (Return a file)
[tester::#AP6] Running program
[tester::#AP6] $ ./your_server.sh --directory /tmp/data/codecrafters.io/http-server-tester/
[tester::#AP6] Testing existing file
[tester::#AP6] Creating file grape_apple_pear_blueberry in /tmp/data/codecrafters.io/http-server-tester/
[tester::#AP6] File Content: "strawberry pear apple pineapple blueberry apple raspberry grape"
[tester::#AP6] Failed to create connection: dial tcp [::1]:4221: connect: connection refused
[tester::#AP6] Test failed
[tester::#AP6] Terminating program
[tester::#AP6] Program terminated successfully

And here’s a snippet of my code:

#include <arpa/inet.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BUFFER_SIZE 1024
static char File_Directory[20];

void *handle_client(void *arg) {
  int client_fd = *(int *)arg;
  char buffer[BUFFER_SIZE];
  char buffercpy[BUFFER_SIZE];

  if (client_fd < 0) {
    printf("Accept Failed: %s\n", strerror(errno));
  }
  printf("Accepting the connection\n");
  memset(buffer, 0, BUFFER_SIZE);
  read(client_fd, buffer, BUFFER_SIZE);
  strcpy(buffercpy, buffer);

  printf("Message from client : %s \n", buffer);

  /* TOKENIZERS */
  char *first_method = strtok(buffer, "/");
  char *second_str = strtok(NULL, "/");

  /* RESPONSE TYPES */
  char normal_response[35] = "HTTP/1.1 200 OK\r\n\r\n ";
  char notfound[35] = "HTTP/1.1 404 Not Found\r\n\r\n ";
  char echo_string_type[BUFFER_SIZE];
  char error_response[40] = "ERROR RESPONSE FROM SERVER";
  char content[50] = {0};

  if (first_method && second_str && strcmp(first_method, "GET ") == 0) {
    if (strcmp(second_str, "/") == 0) {
      send(client_fd, normal_response, sizeof(normal_response), 0);
    } else if (strcmp(second_str, "echo") == 0) {
      char *specific_str = strtok(NULL, "/ ");
      sprintf(echo_string_type,
              "HTTP/1.1 200 OK\r\nContent-Type: "
              "text/plain\r\nContent-Length: %lu\r\n\r\n%s",
              strlen(specific_str), specific_str);
      send(client_fd, echo_string_type, BUFFER_SIZE, 0);
    } else if (strcmp(second_str, "file") == 0) {
      char *specific_str = strtok(NULL, "/ ");
      char file_directory[200] = {0};
      snprintf(file_directory, sizeof(file_directory), "%s%s", File_Directory,
               specific_str);
      printf("File directory :[[ %s  , %s]] \n", file_directory, specific_str);
      if (access(file_directory, F_OK) < 0) {
        send(client_fd, notfound, sizeof(notfound), 0);
        return 0;
      }
      FILE *fp;
      fp = fopen(file_directory, "rb");
      int content_length = 0;
      char content_pointer[200];
      while (fgets(content_pointer, 50, fp) != NULL) {
        printf("... %c", *content_pointer);
        strcat(content, content_pointer);
        content_length += strlen(content);
      }
      fclose(fp);
      char response[BUFFER_SIZE] = {0};
      sprintf(response,
              "HTTP/1.1 200 OK\r\nContent-Type: "
              "application/octet-stream\r\nContent-Length: %d \r\n\r\n %s",
              content_length, content);
      send(client_fd, response, strlen(response), 0);

    } else if (strcmp(second_str, " HTTP") == 0) {
      send(client_fd, normal_response, 40, 0);
    } else if (strstr(buffercpy, "user-agent")) {
      char *user_agent = strstr(buffercpy, "User-Agent: ");
      user_agent += strlen("User-Agent: ");
      char *eof = strstr(user_agent, "\r\n");
      if (eof) {
        *eof = '\0';
      }
      sprintf(echo_string_type,
              "HTTP/1.1 200 OK\r\nContent-Type: "
              "text/plain\r\nContent-Length: %lu\r\n\r\n%s",
              strlen(user_agent), user_agent);
      send(client_fd, echo_string_type, BUFFER_SIZE, 0);
    } else {
      send(client_fd, notfound, sizeof(notfound), 0);
    }

  } else {
    printf("Response to client failed : %s", strerror(errno));
  }
  return NULL;
}
int main(int argc, char **argv) {
  setbuf(stdout, NULL);
  setbuf(stderr, NULL);
  pthread_t thread_id;
  strcpy(File_Directory, argv[1]);
  char *directory_name = strstr(File_Directory, "=/") + 1;
  strcpy(File_Directory, directory_name);
  int server_fd, *client_fd;
  struct sockaddr_in client_addr, serv_addr;
  socklen_t client_addr_len = sizeof(client_addr);
  char buffer[BUFFER_SIZE];

  server_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (server_fd == -1) {
    printf("Socket creation failed: %s...\n", strerror(errno));
    return 1;
  }

  int reuse = 1;
  if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) <
      0) {
    printf("SO_REUSEADDR failed: %s \n", strerror(errno));
    return 1;
  }

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(4221);
  serv_addr.sin_addr.s_addr = INADDR_ANY;

  if (bind(server_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
    printf("Bind failed: %s\n", strerror(errno));
    return 1;
  }

  if (listen(server_fd, 10) < 0) {
    printf("Listen failed: %s\n", strerror(errno));
    return 1;
  }

  printf("Server is listening on port 4221\n");

  while (1) {
    client_fd = malloc(sizeof(int));
    if ((*client_fd = accept(server_fd, (struct sockaddr *)&client_addr,
                             &client_addr_len)) < 0) {
      printf("Accept failed: %s\n", strerror(errno));
      free(client_fd);
      continue;
    }

    if (pthread_create(&thread_id, NULL, handle_client, client_fd) != 0) {
      printf("Thread creation failed: %s\n", strerror(errno));
      free(client_fd);
    } else {
      pthread_detach(thread_id);
    }
  }

  close(server_fd);
  return 0;
}

Hi @kali-37, could you upload your code to GitHub and share the link? It will be much easier to debug if I can run it directly.

You can copy paste this and compile man .

#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BUFFER_SIZE 1024
static char File_Directory[20];

void *handle_client(void *arg) {
  int client_fd = *(int *)arg;
  char buffer[BUFFER_SIZE];
  char buffercpy[BUFFER_SIZE];

  if (client_fd < 0) {
    printf("Accept Failed: %s\n", strerror(errno));
  }
  printf("Accepting the connection\n");
  memset(buffer, 0, BUFFER_SIZE);
  read(client_fd, buffer, BUFFER_SIZE);
  strcpy(buffercpy, buffer);

  printf("Message from client : %s \n", buffer);

  /* TOKENIZERS */
  char *first_method = strtok(buffer, "/");
  char *second_str = strtok(NULL, "/");

  /* RESPONSE TYPES */
  char normal_response[35] = "HTTP/1.1 200 OK\r\n\r\n ";
  char notfound[35] = "HTTP/1.1 404 Not Found\r\n\r\n ";
  char echo_string_type[BUFFER_SIZE];
  char error_response[40] = "ERROR RESPONSE FROM SERVER";
  char content[50] = {0};

  if (first_method && second_str && strcmp(first_method, "GET ") == 0) {
    if (strcmp(second_str, "/") == 0) {
      send(client_fd, normal_response, sizeof(normal_response), 0);
    } else if (strcmp(second_str, "echo") == 0) {
      char *specific_str = strtok(NULL, "/ ");
      sprintf(echo_string_type,
              "HTTP/1.1 200 OK\r\nContent-Type: "
              "text/plain\r\nContent-Length: %lu\r\n\r\n%s",
              strlen(specific_str), specific_str);
      send(client_fd, echo_string_type, BUFFER_SIZE, 0);
    } else if (strcmp(second_str, "file") == 0) {
      char *specific_str = strtok(NULL, "/ ");
      char file_directory[200] = {0};
      snprintf(file_directory, sizeof(file_directory), "%s%s", File_Directory,
               specific_str);
      printf("File directory :[[ %s  , %s]] \n", file_directory, specific_str);
      if (access(file_directory, F_OK) < 0) {
        send(client_fd, notfound, sizeof(notfound), 0);
        return 0;
      }
      FILE *fp;
      fp = fopen(file_directory, "rb");
      int content_length = 0;
      char content_pointer[200];
      while (fgets(content_pointer, 50, fp) != NULL) {
        printf("... %c", *content_pointer);
        strcat(content, content_pointer);
        content_length += strlen(content);
      }
      fclose(fp);
      char response[BUFFER_SIZE] = {0};
      sprintf(response,
              "HTTP/1.1 200 OK\r\nContent-Type: "
              "application/octet-stream\r\nContent-Length: %d \r\n\r\n %s",
              content_length, content);
      send(client_fd, response, strlen(response), 0);

    } else if (strcmp(second_str, " HTTP") == 0) {
      send(client_fd, normal_response, 40, 0);
    } else if (strstr(buffercpy, "user-agent")) {
      char *user_agent = strstr(buffercpy, "User-Agent: ");
      user_agent += strlen("User-Agent: ");
      char *eof = strstr(user_agent, "\r\n");
      if (eof) {
        *eof = '\0';
      }
      sprintf(echo_string_type,
              "HTTP/1.1 200 OK\r\nContent-Type: "
              "text/plain\r\nContent-Length: %lu\r\n\r\n%s",
              strlen(user_agent), user_agent);
      send(client_fd, echo_string_type, BUFFER_SIZE, 0);
    } else {
      send(client_fd, notfound, sizeof(notfound), 0);
    }

  } else {
    printf("Response to client failed : %s", strerror(errno));
  }
  return NULL;
}
int main(int argc, char **argv) {
  setbuf(stdout, NULL);
  setbuf(stderr, NULL);
  pthread_t thread_id;
  strcpy(File_Directory, argv[1]);
  char *directory_name = strstr(File_Directory, "=/") + 1;
  strcpy(File_Directory, directory_name);
  int server_fd, *client_fd;
  struct sockaddr_in client_addr, serv_addr;
  socklen_t client_addr_len = sizeof(client_addr);
  char buffer[BUFFER_SIZE];

  server_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (server_fd == -1) {
    printf("Socket creation failed: %s...\n", strerror(errno));
    return 1;
  }

  int reuse = 1;
  if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) <
      0) {
    printf("SO_REUSEADDR failed: %s \n", strerror(errno));
    return 1;
  }

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(4221);
  serv_addr.sin_addr.s_addr = INADDR_ANY;

  if (bind(server_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
    printf("Bind failed: %s\n", strerror(errno));
    return 1;
  }

  if (listen(server_fd, 10) < 0) {
    printf("Listen failed: %s\n", strerror(errno));
    return 1;
  }

  printf("Server is listening on port 4221\n");

  while (1) {
    client_fd = malloc(sizeof(int));
    if ((*client_fd = accept(server_fd, (struct sockaddr *)&client_addr,
                             &client_addr_len)) < 0) {
      printf("Accept failed: %s\n", strerror(errno));
      free(client_fd);
      continue;
    }

    if (pthread_create(&thread_id, NULL, handle_client, client_fd) != 0) {
      printf("Thread creation failed: %s\n", strerror(errno));
      free(client_fd);
    } else {
      pthread_detach(thread_id);
    }
  }

  close(server_fd);
  return 0;
}```

That works as well if there’s only one file. I’ll take a look and get back to you by the end of the week.

Thank you andy1li , But it worked now ,

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.