0

I am attempting to send an HTML page over a WebSocket using C++

EDIT: I've updated the response header to **not** specify 
how many characters are being sent via char response[] = "..."; 
I've added to the header the Content-Type and Content-Length headers
with length value being 1024. The result is still the same. 
The server sends the response to the web page client and the 
web page prints the header information instead of using the HTML tags.

I'm aware C++ isn't exactly a preferred language for this, but it's the language I have to use.

I have already managed to "establish?" a connection with a client webpage in google chrome. The server is getting the initial request from the client and is able to send back a response that the client is accepting. It's just displaying the wrong part.

Request Header:

  • Host: hostinfo.com:8xxx
  • Connection: keep-alive
  • Upgrade-Insecure-Request: 1
  • DNT: 1
  • User-Agent: Mozilla/5.0 (chrome etc...)
  • Accept: (encrypted message)

Server Response:

  • HTTP/1.1 200 OK
  • Upgrade-Insecure-Request: 1
  • Connection: keep-alive
  • Content-Length: 1024
  • Content-Type: text/html
  • (space for separation of header and HTML info using \r\n\r\n (space after n))
  • test
  • (and the end page response \r\n\r\n (space after n)

However, when the webpage connects, instead of displaying "test" it's displaying the entire set of characters in the header including "HTTP/1.1 200 OK... etc"

I'm new to HTTP protocols and handshakes, I've gotten to this point in just a few days using articles like this, and this, and reading the RFC indexes but there doesn't seem to be any answers for this specific problem. I could understand handshake errors that resulted in a failure to send data between the server and client but sending the header instead of the HTML code is beyond me. Thanks for any help/insight.

TLDR: Why would the client be displaying the header information rather than using the HTML code to display an HTML page?

Client-Side HTML:

<form action="http://xxxxxxx.com:8xxx" method="POST">
<div>
 <input>
</div>
<div>
 <button>Test Connection</button>
</div>
</form>

Server-Side C++ Code: Header File

#pragma once
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")

class html_connection
{
public:
    static int client_handler_thread(int index);
    static int server();
};

Server-Side C++ Code: Class File

#include "pch.h"
#include "html_connection.h"
#pragma warning(disable : 4996)

SOCKET Connections[100]; // client threads (up to 100)
int ConnectionCounter = 0;

int html_connection::server()
{
    WSADATA ws;
    WORD dllV = MAKEWORD(2, 1);
    if (WSAStartup(dllV, &ws) != 0)
    {
        MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
    }

    SOCKADDR_IN addr; // create an address
    int addrSize = sizeof(addr); //length of address
    addr.sin_addr.s_addr = inet_addr("xxx.x.x.xx"); //Broadcast IP
    addr.sin_port = htons(8000); //Port
    addr.sin_family = AF_INET; // IPv4 socket

    SOCKET s = socket(AF_INET, SOCK_STREAM, NULL); // listener socket
    bind(s, (SOCKADDR*)&addr, sizeof(addr)); // binds address to socket
    listen(s, SOMAXCONN); // max possible listeners

    SOCKET newC; // client socket
    for (int i = 0; i < 100; i++) // ensures limited number of clients can connect
    {
        newC = accept(s, (SOCKADDR*)&addr, &addrSize); // connect

        if (newC == 0) // if client con failed
        {
            std::cout << "connect failed" << std::endl;
        }
        else // connected
        {

            Connections[i] = newC; // store new connection in array of connections
            ConnectionCounter += 1;
            CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)client_handler_thread, (LPVOID)(i), NULL, NULL);
        }
    }
    return 0;
}

int  html_connection::client_handler_thread(int index)
{
    // buffer for the client request
    char clientInput[256];

    // Response to the client
    char response[] = "HTTP/1.1 200 OK \r\n Connection: keep-alive \r\n Content-Length:1024 \r\n Upgrade-Insecure-Requests: 1 \r\n Content-Type: text/html \r\n \r\n\r\n <html> </html> \r\n\r\n ";

    while (true)
    {
        // gets the request from the client and prints it to the console
        recv(Connections[index], clientInput, sizeof(clientInput), 0);
        std::cout << clientInput << std::endl;
        // send server response
        send(Connections[index], response, sizeof(response), 0);
    }

    closesocket(Connections[index]);
}

Output: Client - Webpage (initial page - pre-request) enter image description here

Output: Client - Webpage (post-request) enter image description here

Output: Server - Console output (single client connection) enter image description here

Allie Marie
  • 27
  • 1
  • 8
  • When you `recv` you get get what's available. That may or may not be all that you wanted. It can also be more than you wanted because there's nothing to prevent two messages from being packed together. The only way to tell how much the program got from `recv` is the return value. The return value of `recv` is all important and was ignored. We can't know what exactly is `clientInput`. It could be empty. It certainly looks like it's not being null terminated. – user4581301 Dec 10 '18 at 05:12
  • I'm not getting anything from the client right now except the initiation of the connection to the server. I know that normally if the client were to send something through a GET method it would be on top of the header file like "GET /?name=value HTTP/1.1" where /?name=value" is the form info and then I could parse it and use it to get specific information from a database. But that's not my question. I want to know more about the send() method and why when it responds to the handshake it displays the server headers in the webpage and not the HTML code. – Allie Marie Dec 10 '18 at 05:38
  • The server output image shows the output of the recv() method, everything from POST / HTTP/1.1 to User-Agent: Mozilla/5.0... is what I'm getting from recv(). – Allie Marie Dec 10 '18 at 05:40
  • It's printing out the headers etc... because C++'s default output routines don't have the slightest idea what HTTP is. They just print what you give them, headers and all.Once you have received the whole document you'll need to run it through a parser to extract the contents of the message and print that. Have you considered using a library like cURL to manage all of the nitty-gritty protocol stuff for you? – user4581301 Dec 10 '18 at 05:45
  • I'm not talking about the headers being printed server-side, I mean the second output image under "Output: Client - Webpage (post-request) " That is what is coming out on the client-side webpage after the handshake. – Allie Marie Dec 10 '18 at 06:03
  • I have but since I already was able to send information back to a webpage client I was hoping I could send it over this way. I just need to send one HTML line over and have it display on their web page without the header info. – Allie Marie Dec 10 '18 at 06:05
  • What happens if you change `char response[1000] = "...";` into `char response[] = "...";`? – user4581301 Dec 10 '18 at 06:27
  • Same thing happens when I change the size. I read your post about using string buffer cin >> buffer but I can't get that working either. I tried increasing the size of the client buff too but it didn't have more to send. This is a gif of what is happening when I click the button on the webpage. Prob makes more sense than just saying what happens: https://media.giphy.com/media/7YDcdyTrHnwyAJYIjN/giphy.gif – Allie Marie Dec 10 '18 at 06:34
  • Does cURL require a MinGW compiler? Because I was having a lot of trouble linking my include files and libraries for MySQL when using code::blocks because it was compiling with MinGW. After switching to Visual Studio and using the MSVC compiler I no longer had errors connecting my database. I'm hesitant to switch back to that. – Allie Marie Dec 10 '18 at 07:14
  • The way you are populating `char response[]` is wrong (too much whitespace in it), and incomplete (it is missing `Content-Type` and more importantly `Content-Length` headers). This is not a good way to implement an HTTP server in general – Remy Lebeau Dec 10 '18 at 10:04
  • @Remy Ok, I'll add those, should I make the response all one line or should I just tab it up closer to the left? Going to do one line for now and see how that works. – Allie Marie Dec 10 '18 at 14:37
  • Be a good idea to place the [correct value in content-length.](https://tools.ietf.org/html/rfc7230#section-3.3.2) – user4581301 Dec 10 '18 at 16:14
  • 1
    @AllieMarie I think you need to read RFCs 2616 and 7230-7235 for the HTTP 1.1 spec more carefully, to learn the proper rules for handling and formatting HTTP messages. Your response is still malformed, from HTTP's perspective – Remy Lebeau Dec 10 '18 at 17:22
  • I'm still pulling up information from it such as the correct value link ^ Meanwhile, is there an example of this done anywhere without using predefined libraries? I have seen examples of c++ servers connecting over sockets to c++ clients but none of c++ servers connecting to a webpage and sending HTML code over a socket. – Allie Marie Dec 11 '18 at 05:56

0 Answers0