Received "" HTTP-SERVER C- stage Respond to body

I’m stuck on Stage #CN2.

i have extracted the url given by the tester and also i have seperated the data from the URL, and sent back the data to the client using send() in C. it is working perfectly fine in my terminal. but idk why it doesn’t return anything in the turbo test run for codecrafters git push. help will be appreciated

this was the response i got when i run my server. i will attach my server code too for review

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

char* pathdata(char *str){
	char *vpth = "GET /echo/";int space=0;
	if(strncmp(str,vpth,strlen(vpth))==0){
		for(int i=strlen(vpth);i<strlen(str);i++){
			if(str[i]==' '){
				space=i;break;
			}
		}
	}
	else{return "HTTP/1.1 404 Not Found\r\n\r\n";}
	str+=strlen(vpth);
	space-=strlen(vpth);
	// printf("spce: %d\n",space);
	// printf("STR: %s\n",str);
	char data[space];
	// str
	// str[strlen(str)]='\0';
	strncpy(data,str,space);
	data[space]='\0';
	// printf("data: %s\n",data);
	// printf("----\n");
	char *re="HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %ld\r\n\r\n%s\n",*res;
	sprintf(res,re,strlen(data),data);
	// printf("res: %s\n",res);
	printf("-------done func-------\n");
	// char* f = res;
	return res;
}

int main() {
	// Disable output buffering
	setbuf(stdout, NULL);
 	setbuf(stderr, NULL);

	// You can use print statements as follows for debugging, they'll be visible when running tests.
	printf("Logs from your program will appear here!\n");

	// Uncomment this block to pass the first stage
	
	int server_fd, client_addr_len;
	struct sockaddr_in client_addr;
	
	server_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (server_fd == -1) {
		printf("Socket creation failed: %s...\n", strerror(errno));
		return 1;
	}
	
	// Since the tester restarts your program quite often, setting SO_REUSEADDR
	// ensures that we don't run into 'Address already in use' errors
	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;
	}
	
	struct sockaddr_in serv_addr = { .sin_family = AF_INET ,
									 .sin_port = htons(4221),
									 .sin_addr = htonl(INADDR_ANY) ,
									};
	
	if (bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) != 0) {
		printf("Bind failed: %s \n", strerror(errno));
		return 1;
	}
	
	int connection_backlog = 5;
	if (listen(server_fd, connection_backlog) != 0) {
		printf("Listen failed: %s \n", strerror(errno));
		return 1;
	}
	
	printf("Waiting for a client to connect...\n");
	client_addr_len = sizeof(client_addr);
	

	int cl_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_addr_len);

	// printf("g: %d\n",g);

	if(cl_fd==-1){
		printf("accept katham katham");
		exit(EXIT_FAILURE);
	}
	printf("Client connected\n");

	char re[100];
	int bytrd=read(cl_fd,re,99);

	// printf("bufsz: %d\n",bytrd);

	if(bytrd==-1){
		printf("Recv tata bye bye");
		exit(EXIT_FAILURE);
	}

	// printf("bufsz: %d\n",bytrd);
	// re[bytrd]='\0';

	// printf("%s\n",re);
	// printf("15:\n");
	// printf("%c\n ",re[16]);
	// if(re)
		char *res=pathdata(re);

		printf("%s\n",res);
		printf("strlen %ld\n",strlen(res));
		int sd = write(cl_fd,res,strlen(res));
		printf("sd: %d\n",sd);
		if(sd!=-1){printf("Send success");}
		else{printf("send failure!");}

		close(cl_fd);

		close(server_fd);

		return 0;
}

and the output of my code was

Logs from your program will appear here!
Waiting for a client to connect...
Client connected
-------done func-------
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 11

helpmee:sob

strlen 77
sd: 77

codecrafters response:

Plz help, i tried using write() and send(), but no use, even tried making the char pointer to char array and all possible things, even if segmentation fault occurs, program won’t terminate successfully right?

if anyone faced this before or if i made some mistake, pls help broskie

Your current implementation is sending 1 byte more than the expected length:


The read excess message from curl is representative of the same. Maybe that is causing the stage to fail?

2 Likes

I guess you should remove the trailing \n here.

Since you are allotting a buffer of length space, accessing the index space is technically out of bounds. It “may” work in most cases, but if the string is stack allocated, then it can lead to a buffer overflow, causing a segmentation fault and an empty error logged by the tester. Allocate a buffer of space + 1 to prevent this out of bounds access.

2 Likes

Thanks for replying!, sorry my bad, i didn’t notice the extra byte thing, actually the error wasn’t it, i cleared those all extra byte stuff, sorry my bad i didn’t notice it while i uploaded it. the actual error was that in codecrafters test my server isn’t returning anything.

so, i had no way and reached out to grok, it said it is due to the pathextract() function, the returning variable is getting destroyed during returning, but in my local PC, it’s working as the entire stuff are stored in Buffer in my program memory, so instead of accessing the garbage values, i get those HTTP reply by luck in my local PC.

so i created a tmp variable in my main() and send that too as the argument for that func, by storing the response in that variable and returning it to main, made the program to pass the cases. i will share the code here. if my intuition and understanding was wrong, feel free to correct me bro!

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#define HTTP200 "HTTP/1.1 200 OK\r\n"
#define HTTP404 "HTTP/1.1 404 Not Found\r\n"
#define CONTYPTP "Content-Type: text/plain\r\n"
#define CONLEN "Content-Length: %ld\r\n"
#define CRLF "\r\n"


char* pathdata(char *str,char* fk,size_t len){
	char *vpth = "GET /echo/";int space=0;
	char* usrag="GET /user-agent ";
	if(strncmp(str,vpth,strlen(vpth))==0){
		for(int i=strlen(vpth);i<strlen(str);i++){
			if(str[i]==' '){
				space=i;break;
			}
		}
		str+=strlen(vpth);
		space-=strlen(vpth);
		char* data=malloc(space+1);
		strncpy(data,str,space);
		data[space]='\0';
		printf("data: %s\n",data);
		printf("----\n");
		char *res = malloc(100);
		strcat(res,HTTP200);
		strcat(res,CONTYPTP);
		strcat(res,CONLEN);
		strcat(res,CRLF);
		strcat(res,data);
		printf("CON: %s\n",res);
		snprintf(fk,(unsigned long)len,res,strlen(data));
		printf("res:[func] %s\n",fk);
		printf("-------done func-------\n");
		return fk;
	}
	else if(strncmp(str,usrag,strlen(usrag))==0){
		char* usg="User-Agent: ";
		printf("first str: %s\n",str);
		size_t start=(strstr(str,usg)-str)+strlen(usg);
		str+=start;
		
		printf("start: %s\n",str);
		int end=strchr(str,'\n')-str;
		if(end<0){end=strlen(str);}
		printf("end: %d   str: %s\n",end,str);
		char* data=(char*)malloc(end+1);
		strncpy(data,str,end-1);
		data[end]='\0';
		printf("%s\n",data);
		printf("-----\n");
		char *res = malloc(200);
		strcat(res,HTTP200);
		strcat(res,CONTYPTP);
		strcat(res,CONLEN);
		strcat(res,CRLF);
		strcat(res,data);
		snprintf(fk,len,res,strlen(data));
		// printf("4\n");
		// printf("start: %d  end: %d\n",start,end);
		// printf("5\n");
		return fk;
	}
	else if(strncmp(str,"GET / ",strlen("GET / "))==0){
		// return "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 0\r\n\r\n";
		strcat(fk,HTTP200);
		strcat(fk,CRLF);
		return fk;
	}
	else{return HTTP404 CRLF;}
}

int main() {
	// Disable output buffering
	setbuf(stdout, NULL);
 	setbuf(stderr, NULL);

	// You can use print statements as follows for debugging, they'll be visible when running tests.
	printf("Logs from your program will appear here!\n");

	// Uncomment this block to pass the first stage
	
	int server_fd, client_addr_len;
	struct sockaddr_in client_addr;
	
	server_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (server_fd == -1) {
		printf("Socket creation failed: %s...\n", strerror(errno));
		return 1;
	}
	
	// Since the tester restarts your program quite often, setting SO_REUSEADDR
	// ensures that we don't run into 'Address already in use' errors
	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;
	}
	
	struct sockaddr_in serv_addr = { .sin_family = AF_INET ,
									 .sin_port = htons(4221),
									 .sin_addr = htonl(INADDR_ANY) ,
									};
	
	if (bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) != 0) {
		printf("Bind failed: %s \n", strerror(errno));
		return 1;
	}
	int conc=0;
	while(1){
		int connection_backlog = 5;
		if (listen(server_fd, connection_backlog) != 0) {
			printf("Listen failed: %s \n", strerror(errno));
			return 1;
		}
		
		printf("Waiting for a client to connect...\n");
		client_addr_len = sizeof(client_addr);
		

		int cl_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_addr_len);

		// printf("g: %d\n",g);

		if(cl_fd==-1){
			printf("accept katham katham");
			exit(EXIT_FAILURE);
		}
		printf("Client connected: %d\n", ++conc);

		char re[100];
		int bytrd=read(cl_fd,re,99);

		// printf("bufsz: %d\n",bytrd);

		if(bytrd==-1){
			printf("Recv tata bye bye");
			exit(EXIT_FAILURE);
		}
			char* fku=(char *)malloc(200);
			char* res=pathdata(re,fku,200);
			// char* usr=useragent(re);
			// char final[100];
			printf("res: %s\n",res);
			int sd = write(cl_fd,res,strlen(res));
			printf("sd: %d\n",sd);
			if(sd!=-1){printf("Send success\n");}
			else{printf("send failure!\n");}

			// printf("User-Agent: %s\n", usr);

			close(cl_fd);
	}

		close(server_fd);

		return 0;
}

this is the entire code. afaik and according to grok’s explanation, i understood this. but the one thing still puzzles me is that, i’m returning that variable right, it says while returning the function scope the returning variable will be destroyed it seems, so it happens like this :sneezing_face::sneezing_face:. i’m still puzzled. i hope i’m clear what i’m tryin to convey :sweat_smile::sweat_smile:

Hmm, interesting. I tried to read through the program, but couldn’t figure out any such problems. I even compiled the same with g++ with more restrictive checks, and got a number of warnings related to typecasting, but nothing related to this. Maybe a swing and a miss for Grok here?

Ye, kinda i think, it says due to uninitilaized memory in that pathdata() func for char* res. Now it asks to create a heap memory instead of just function stack memory that goes out of scope after execution

this thing i initialised as *res right… it points to a garbage value it seems, in my program memory it was pointing correctly it seems, but in codecrafters server, it didn’t, so the msg was empty during transit, so got that error.

Actually i won’t trust it completely, that’s why i was searching for other resources but unable to find.

So got it’s help and understood! it was the problem it says. asks me to allocate some space using malloc() so that the main() can get it properly..

as i said earlier, the variable becomes out of function scope if i just declare with char* res. if i use malloc() it will have a heap memory allocated to it, which can be returned to main() and can be free() at main().

This is what i have understood from it from the explanation of an LLM(grok)

Actually C’s memory management and stuffs are weird and interesting, no bound checking , i even accessed the entire program memory without knowing and printed it at last got segmentation fault! lol!

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