-1

I'm trying to get more familiar with C by writing a web server, and I managed to get a method to create HTTP headers for html files yesterday but I have been unable to get images within that html file to load.

Right now I generate my header by opening the html file, and creating a file stream to write the start of the header, the size of it, and then I loop through the file to send each character to the stream. I them send that stream as a char pointer back to the main method which sends it as a response over the socket.

I'm imagining that there is some more work I need to do here, but I haven't been able to find a good solution or anything too helpful to point me in the right direction of how exactly to get it to display. I appreciate any responses/insight.

test.html

<!DOCTYPE html>
<html>
<head>
    <title>Nick's test website</title>
</head>
<body>

<h1>Welcome to my website programmed from scratch in C</h1>
<p>I'm doing this project to practice C</p>

<table>
    <tr>
        <td>test1</td>
        <td>test2</td>
        <td>test2</td>
    </tr>
</table>

<img src="pic.jpg"/>

</body>
</html>

headermaker.c

char * headermaker(char * file_name){
    char ch;
    FILE * fp;
    fp = fopen(file_name, "r");


    if(fp == NULL){
        perror("Error while opening file.\n");
        exit(-1);
    }

    //print/save size of file
    fseek(fp, 0, SEEK_END);
    int size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    printf("File size is %d\n", size);


   //create filestream
    FILE * stream;
    char * buf;
    size_t len;
    stream = open_memstream(&buf, &len);

    //start header
    fprintf(stream, "HTTP/1.1 200 OK\\nDate: Sun, 28 Aug 2022 01:07:00 GMT\\nServer: Apache/2.2.14 (Win32)\\nLast-Modified: Sun, 28 Aug 2022 19:15:56 GMT\\nContent-Length: ");
    fprintf(stream, "%d\n", size);
    fprintf(stream, "Content-Type: text/html\n\n");


    //loop through each character
    while((ch = fgetc(fp)) != EOF)
        fprintf(stream, "%c", ch);

    fclose(stream);

    fclose(fp);
    return buf;
}
  • The server will get a separate request for each image in the html document. Related: [Image in HTTP Response using C?](https://stackoverflow.com/questions/53570156/image-in-http-response-using-c) and and [Send image through http in C](https://stackoverflow.com/questions/58859315/send-image-through-http-in-c). – Weather Vane Sep 18 '22 at 14:50
  • I've updated to try to get it to send an image, but I'm still having the same issue. Generally, it's just different as I have a different Content-Type: image/jpg instead of text/html. Is there more I need to do different? One of those suggests using inline base64 but I don't want to do it that way, I'd like to also be able to send just image files if desired. – Nicholas Vincent Sep 18 '22 at 15:25
  • [`int ch;`](https://stackoverflow.com/a/35356684/918959) – Antti Haapala -- Слава Україні Sep 18 '22 at 17:35
  • Also, you're not speaking HTTP/1.1. You'd have to say **`Connection: close`**. – Antti Haapala -- Слава Україні Sep 18 '22 at 17:36

1 Answers1

0

Using a modified version of provided code to setup a web server using netcat and needed to see explanation of how to send jpeg using netcat

./one | nc -l 45231 ; { ./two && cat pic.jpeg; }  | nc -l 45231;

Chrome browser can open http://localhost:45231 and will show the web page with an image. Also, can observe the network request - response sequence using "View->Developer->Developer Tools".

The code was built like this:

gcc -DONE -o one main.c && gcc -DTWO -o two main.c

The modified code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char * headermaker(char * file_name, char * content_type ){
    char ch;
    FILE * fp;
    fp = fopen(file_name, "r");


    if(fp == NULL){
        perror("Error while opening file.\n");
        exit(-1);
    }

    //print/save size of file
    fseek(fp, 0, SEEK_END);
    int size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    //printf("File size is %d\n", size);


   //create filestream
    FILE * stream;
    char * buf;
    size_t len;
    stream = open_memstream(&buf, &len);

    //start header
    fprintf(stream, "HTTP/1.1 200 OK\n");
    fprintf(stream, "Server: netcat!\n");
    fprintf(stream, "Content-Type: %s\n",content_type);
    fprintf(stream, "Content-Length: %d\n", size);
    fprintf(stream, "\n");


    //loop through each character
#ifdef ONE
    while((ch = fgetc(fp)) != EOF)
        fprintf(stream, "%c", ch);
#endif //#ifdef ONE

    fclose(stream);

    fclose(fp);
    return buf;
}

int main( )
{
  #ifdef ONE
  char *buf = headermaker( "test.html", "text/html" );
  printf( "%s", buf );
  free(buf);
  #endif //#ifdef ONE

  #ifdef TWO
  char *buf = headermaker( "pic.jpeg", "image/jpeg" );
  printf( "%s", buf );
  free(buf);
  #endif //#ifdef TWO

  return 0;
}

Another helpful debug tool was curl:

curl -vvv localhost:45231 > page.html
curl -vvv localhost:45231 > image.jpeg
atl
  • 575
  • 3
  • 6
  • Wouldn't this not send anything to the stream for an image? It would just output the header data itself but not the image data? This is certainly covering some things nicer than I am, but as I understand it because there is no spot for TWO to be defined in the headermaker method wouldn't it just not send data? – Nicholas Vincent Sep 19 '22 at 19:21
  • Agree, review is correct. The sequence demonstrates to render the html and image requires 2 requests from the client. Request one gets response one (the original header function is correct for that). Request 2 for the JPEG image will not work because the content type is wrong and fgetc wont send the binary image data. Request one arrives using "nc" and then response "one" is sent (header and html), this causes client to send request two to the second "nc" command and response two sends the header and cat image.jpeg sends the image data. – atl Sep 21 '22 at 04:20
  • Ok I didn't see the cat image.jpeg before. I am seeing the fact that fgetc won't get the binary data but isn't there a way to do that in C? I'm not using netcat, I'm using a hand written Server.C file which just really opens the socket and then another one called test.c accepts the socket and writes to the socket. So I'd like to find a way to do it all within the program. – Nicholas Vincent Sep 21 '22 at 18:09
  • I managed to read and get it to the stream by adding the following below the //start header section of code. ```if(strcmp(content_type, "image/jpeg") == 0){ printf("IMAGE TYPE DETECTED. LETS GET THOSE BITS\n"); char * file_data = (char *)malloc((size+1)*sizeof(char)); rewind(fp); fread(file_data, size, 1, fp); for(int i = 0; i < size; i++) { fprintf(stream, "%u", file_data[i]); printf("%u", file_data[i]); } }``` which results in the output on firefox of "The image "http://xxx.xxx.x.x/pic.jpeg" contains errors. – Nicholas Vincent Sep 21 '22 at 18:20
  • Ended up getting it to work (though clunky right now) by following this link: https://stackoverflow.com/questions/53570156/image-in-http-response-using-c and using the send() method after sending the rest of the header. Thank you for the help! – Nicholas Vincent Sep 21 '22 at 18:35