Reputation: 398
I trying make one simple HTTP server in C, but i need get the browser requests to see platform, cookies, ... To do that, i'm trying read the sock file with the fgets function, but it returns to me an infinite loop.
See my code.
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <dirent.h>
#include <pthread.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdbool.h>
#define SERVER "TestServer4" //Servername
#define PROTOCOL "HTTP/1.1" //Protocol used
#define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT" //Date format of returns
#define PORT 7777 //Socket port
#define NUM_THREADS 5 //Threads clusters numbers
int sock; //Stores the socket
void send_headers(FILE *f, int status, char *title, char *extra, char *mime, int length, time_t date) {
time_t now;
char timebuf[128];
fprintf(f, "%s %d %s\r\n", PROTOCOL, status, title);
fprintf(f, "Server: %s\r\n", SERVER);
now = time(NULL);
strftime(timebuf, sizeof (timebuf), RFC1123FMT, gmtime(&now));
fprintf(f, "Date: %s\r\n", timebuf);
if (extra) fprintf(f, "%s\r\n", extra);
if (mime) fprintf(f, "Content-Type: %s\r\n", mime);
if (length >= 0) fprintf(f, "Content-Length: %d\r\n", length);
if (date != -1) {
strftime(timebuf, sizeof (timebuf), RFC1123FMT, gmtime(&date));
fprintf(f, "Last-Modified: %s\r\n", timebuf);
}
fprintf(f, "Connection: close\r\n");
fprintf(f, "\r\n");
}
void send_error(FILE *f, int status, char *title, char *extra, char *text) {
send_headers(f, status, title, extra, "text/html", -1, -1);
fprintf(f, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
fprintf(f, "<BODY><H4>%d %s</H4>\r\n", status, title);
fprintf(f, "%s\r\n", text);
fprintf(f, "</BODY></HTML>\r\n");
}
void get_request(FILE *f) {
char buf[4096];
while (fgets(buf, sizeof(buf), f) != NULL) {
fgets(buf, sizeof(buf), f);
printf("%s", buf);
}
}
int process(FILE *f, long tid) {
char buf[4096];
char *method;
char *path;
char *protocol;
struct stat statbuf;
if (!fgets(buf, sizeof(buf), f)) return -1;
get_request(f);
method = strtok(buf, " ");
path = strtok(NULL, " ");
protocol = strtok(NULL, "\r");
if (!method || !path || !protocol) return -1;
fseek(f, 0, SEEK_CUR); // Force change of stream direction
if (strcasecmp(method, "GET") != 0) {
send_error(f, 501, "Not supported", NULL, "Method is not supported.");
} else {
send_headers(f, 200, "OK", NULL, "text/html", -1, statbuf.st_mtime);
bool page = !strcmp(path, "/photos.json");
if (page) {
fprintf(f, "<b> yeah, photos stream :) </b>");
} else {
fprintf(f, "<HTML><HEAD><TITLE>Yeah</TITLE></HEAD>\r\n<BODY>");
fprintf(f, "<H4>server (%s) </H4>\r\n<PRE>\n", path);
}
}
printf("Im running in thread #%ld!\n", tid);
fclose(f);
return 0;
}
void accept_conn(void *threadid) {
long tid;
tid = (long) threadid;
while (1) {
int s;
FILE *f;
s = accept(sock, NULL, NULL);
if (s < 0) {
break;
} else {
f = fdopen(s, "a+");
process(f, tid);
};
}
}
int main(int argc, char *argv[]) {
struct sockaddr_in sin;
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(PORT);
bind(sock, (struct sockaddr *) &sin, sizeof (sin));
listen(sock, 5);
printf("HTTP server listening on port %d\n", PORT);
pthread_t threads[NUM_THREADS];
int rc;
long t;
for (t = 0; t < NUM_THREADS; t++) {
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, accept_conn, (void *) t);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
close(sock);
return 0;
}
The problem is in the get_request function.
Upvotes: 2
Views: 1730
Reputation: 1572
What is happening is that fgets
blocks after it has finished reading the end of the http request, i.e. "\r\n"
. You are reading from a socket, not a file.
What you need to do is something like this. Also, the buffer and its length has to be passed in so that you can do something with the buffer later.
void
get_request(FILE *f, char *buf, int len)
{
int n;
char *p = buf;
while (1) {
fgets(p, len, f);
if (strcmp(p, "\r\n") == 0) {
break;
}
n = strlen(p);
p += n;
len -= n;
}
printf("req = %s\n", buf);
}
Upvotes: 1