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;
}