Sending html file with HTTP protocol via tcp and browser shows error

I am writing an HTTP webserver, when I send a text file with the equivalent HTML file content to the browser, the browser shows it correctly, but when I send the HTML file browser itself, it renders the HTML page to the second and then the "connection has been reset" message appears.

I noticed that the text file is larger than the HTML file, but I have no idea why

text size = 286 bytes

HTML size = 142 bytes

and this is the HTML code:

<!DOCTYPE html>
<html>
<body>

<p>This is a paragraph.</p>
<p>This is a paragraph.</p>
<p>This is a paragraph.</p>

</body>
</html>

      

this is my code:

char sendBuffer[500];

FILE *sendFile = fopen("foo.html", "r");
fseek(sendFile, 0L, SEEK_END);
int sz = ftell(sendFile);
fseek(sendFile, 0L, SEEK_SET);

string s1;
s1="HTTP/1.1 200 OK\nContent-length: " + to_string(sz) + "\n";
std::vector<char> writable(s1.begin(), s1.end());
writable.push_back('\0');

strcpy(sendBuffer,(const char *)&writable[0]);
int c=send(connected,(const char*)&sendBuffer,strlen(&writable[0]),0);
printf("\nSent : %s\n",sendBuffer);
strcpy(sendBuffer,"Content-Type: text/html\n\n");
c=send(connected,(const char*)&sendBuffer,strlen("Content-Type: text/html\n\n"),0);
printf("\nSent : %s\n",sendBuffer);

char send_buffer[300];

while( !feof(sendFile) )
{
    int numread = fread(send_buffer, sizeof(unsigned char), 300, sendFile);
    if( numread < 1 ) break; // EOF or error

    char *send_buffer_ptr = send_buffer;
    do {
        int numsent = send(connected, send_buffer_ptr, numread, 0);
        if( numsent < 1 ) // 0 if disconnected, otherwise error
         {
            if( numsent < 0 ) {
                if( WSAGetLastError() == WSAEWOULDBLOCK )
                {
                    fd_set wfd;
                    FD_ZERO(&wfd);
                    FD_SET(connected, &wfd);

                    timeval tm;
                    tm.tv_sec = 10;
                    tm.tv_usec = 0;

                    if( select(0, NULL, &wfd, NULL, &tm) > 0 )
                        continue;
               }
           }

        break; // timeout or error
    }

    send_buffer_ptr += numsent;
    numread -= numsent;
}
while( numread > 0 );
}

      

Here's another piece of code that's used just before the code above:

int sock, connected, bytes_recieved , _true = 1 , portNumber;
char send_data [1024] , recv_data[1024];      
struct sockaddr_in server_addr,client_addr;   
int sin_size;

time_t t = time(NULL);
struct tm tm = *localtime(&t);
char date[50];

if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
    perror("Unable to create the Socket");
    exit(1);
}

if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(const char*)&_true,sizeof(int)) == -1) {
    perror("Unable to Setsockopt");
    exit(1);
}
char *server_address="127.1.1.1";
portNumber=8080;
server_addr.sin_family = AF_INET; 
server_addr.sin_port = htons(portNumber);
server_addr.sin_addr.s_addr = inet_addr("127.1.1.1");//inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr);//INADDR_ANY;

string host=server_address+':'+to_string(portNumber);


memset(&(server_addr.sin_zero),0,8);//sockaddr_in zero padding is needed
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))==-1) //bind the socket to a local address
{
    perror("Unable to bind");
    exit(1);
}

if (listen(sock, 5) == -1) //listen to the socket with the specified waiting queue size
{
    perror(" Listen");
    exit(1);
}

cout << "MyHTTPServer waiting on port 8080" << endl;
fflush(stdout);

sin_size = sizeof(struct sockaddr_in);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);

cout<< "I got a connection from (" << inet_ntoa(client_addr.sin_addr) << "," << ntohs(client_addr.sin_port) << ')' << endl;

      

+3


source to share


2 answers


You have two important problems that I see

  • The gaps are send

    wrong, this line (very important)

    int c=send(connected,(const char*)&sendBuffer,strlen(&writable[0]),0);
    
          

    it should be

    int c=send(connected,(const char*) sendBuffer,strlen(&writable[0]),0);
    /*                                ^ 
     *                                No ampersand
     */
    
          

    since the array sendBuffer

    decays to a pointer and you don't need that.

  • You are also passing the first parameter select

    from the manual

    nfds - highest file descriptor number in any of the three sets, plus 1

    so in your case it should be

    if (select(connected + 1, NULL, &wfd, NULL, &tm) > 0)
    
          

    and you use it after the call send

    , you have to call it before to see if it can be written to the file descriptor.



Your code is a little more complex for the task it developed, so I propose the following solution with fixed issues and improvement on some others

string       text;
stringstream stream;

FILE *sendFile = fopen("foo.html", "r");
if (sendFile == NULL) /* check it the file was opened */
    return;

fseek(sendFile, 0L, SEEK_END);
/* you can use a stringstream, it cleaner */
stream << "HTTP/1.1 200 OK\nContent-length: " << ftell(sendFile) << "\n";
fseek(sendFile, 0L, SEEK_SET);

text = stream.str();
/* you don't need a vector and strcpy to a char array, just call the .c_str() member
 * of the string class and the .length() member for it length
 */
send(connected, text.c_str(), text.length(), 0);

std::cout << "Sent : " <<  text << std::endl;

text = "Content-Type: text/html\n\n";
send(connected, text.c_str(), text.length(), 0);

std::cout << "Sent : %s" << text << std::endl;
while (feof(sendFile) == 0)
{
    int  numread;
    char sendBuffer[500];

    numread = fread(sendBuffer, sizeof(unsigned char), 300, sendFile);
    if (numread > 0)
    {
        char *sendBuffer_ptr;

        sendBuffer_ptr = sendBuffer;
        do {
            fd_set  wfd;
            timeval tm;

            FD_ZERO(&wfd);
            FD_SET(connected, &wfd);

            tm.tv_sec  = 10;
            tm.tv_usec = 0;
            /* first call select, and if the descriptor is writeable, call send */
            if (select(1 + connected, NULL, &wfd, NULL, &tm) > 0)
            {
                int numsent;

                numsent = send(connected, sendBuffer_ptr, numread, 0);
                if (numsent == -1)
                    return;
                sendBuffer_ptr += numsent;
                numread        -= numsent;
            }
        } while (numread > 0);
    }
}
/* don't forget to close the file. */
fclose(sendFile);

      

+1


source


Half answer. First, even if "Usage \n

works", it violates the standard. You need to use CRLF. Use CRLF. Period.

For the rest of the code. I doubt this will change many things, but I would restructure the code a bit. This is important for the send function.

Separated the data transfer to its own function. You might also consider splitting the dispatch header into its own function - if you can find a good way to structure it. When you expand to send text or html or such Etc. Etc. Etc., you have to finalize the title for your own function. Doing this early would be helpful.



Only means a rough start.

int send_data(int soc, const char *buf, size_t len)
{
    ssize_t sent;

    do {

        /* Use iharob code or similar here */
        /* Return something <> 0 on error. */

        sent = send(soc, buf, len, 0);

        buf += sent;
        len -= sent;
    } while (len > 0);

    return 0;
}

int send_file(int soc, const char *fn)
{
    char buf[500];
    FILE *fh;
    long sz;
    size_t len;
    int err = 0;

    if (!(fh = fopen(fn, "r"))) {
        perror("fopen");
        return 1;
    }
    fseek(fh, 0L, SEEK_END);
    sz = ftell(fh);
    fseek(fh, 0L, SEEK_SET);

    /* Consider adding Date + Server here. */
    len = sprintf(buf,
            "HTTP/1.1 200 OK\r\n"
            "Content-length: %ld\r\n"
            "Content-Type: text/html\r\n"
            "Server: FooBar/0.0.1\r\n"
            "\r\n", sz
    );
    if (len < 0) {
        err = 3;
        fprintf(stderr, "Error writing header.\n");
        goto fine;
    }

    /* Debug print. */
    fprintf(stderr, "Header[%d]:\n'%s'\n", len, buf);

    if ((err = send_data(soc, buf, len)) != 0) {
        fprintf(stderr, "Error sending header.\n");
        goto fine;
    }

    while (!feof(fh)) {
        len = fread(buf, sizeof(char), 500, fh);
        if (len < 1)
            break;
        if ((err = send_data(soc, buf, len))) {
            fprintf(stderr, "Error sending file.\n");
            goto fine;
        }
    }
    if ((err = ferror(fh))) {
        fprintf(stderr, "Error reading file.\n");
        perror("fread");
    }
fine:
    fclose(fh);
    return err;
}

      

+1


source







All Articles