0

I would like to download a PDF file with a socket. I receive a "400 Bad Request" error from the server, saying "The plain HTTP request was sent to HTTPS port", like shown in the image below (I open it as an HTML page):

image_bad_request_server

I change the port from 443 to 80, but I don't get a response from the server. I have nothing in file.pdf when I change the port to 80.

This is my console output:

Connected to server via socket 268

Bytes Sent: 109
Bytes received: 0

Received byte  = 100
Total data = 100Bytes received: 0

Received byte  = 100
Total data = 200Bytes received: 0

Received byte  = 100
Total data = 300Bytes received: 0

Received byte  = 100
Total data = 400Bytes received: 0

Received byte  = 30
Total data = 430Connection closed

Received byte  = 0
Total data = 430Reply received

This is my code. I open the socket and I connect to the server, but I'm not receiving the file:

WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
    wprintf(L"WSAStartup function failed with error: %d\n", iResult);
    return 1;
}

sockaddr_in Serv_Addr;

//intialisation
struct addrinfo* result = NULL;
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));

//socket configuration
SOCKET TcpClientSocket = -1;
int ret = 0;
TcpClientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (TcpClientSocket == INVALID_SOCKET) {
    wprintf(L"socket function failed with error: %ld\n", WSAGetLastError());
    WSACleanup();
    return 1;
}
Serv_Addr.sin_family = AF_INET;
Serv_Addr.sin_port = htons(443);
Serv_Addr.sin_addr.s_addr = inet_pton(AF_INET, "47.88.2.145", &Serv_Addr.sin_addr); //connect to www.axmag.com, link pdf file http://www.axmag.com/download/pdfurl-guide.pdf
printf("Connected to server via socket %u\n", TcpClientSocket);

//connection
iResult = -1;
iResult = connect(TcpClientSocket, (sockaddr*)& Serv_Addr, sizeof(Serv_Addr));
printf("%d", iResult);
if (iResult == SOCKET_ERROR) {
    wprintf(L"connect function failed with error: %ld\n", WSAGetLastError());
    iResult = closesocket(TcpClientSocket);
    if (iResult == SOCKET_ERROR)
        wprintf(L"closesocket function failed with error: %ld\n", WSAGetLastError());
    WSACleanup();
    return 1;
}

// send request
const char* message;
message = "GET /download/pdfurl-guide.pdf HTTP/1.1\r\nHost: www.axmag.com\r\n\r\n Connection: keep-alive\r\n\r\n Keep-Alive: 300\r\n";

// test send succeded

iResult = send(TcpClientSocket, message, strlen(message), 0);
if (iResult == SOCKET_ERROR)
{
    printf("send failed: %d\n", WSAGetLastError());
    closesocket(TcpClientSocket);
    WSACleanup();
    return 1;
}
printf("Bytes Sent: %ld\n", iResult);

// shutdown the connection for sending since no more data will be sent
// the client can still use the ConnectSocket for receiving data
iResult = shutdown(TcpClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
    printf("shutdown failed: %d\n", WSAGetLastError());
    closesocket(TcpClientSocket);
    WSACleanup();
    return 1;
}

FILE* stream;
fopen_s(&stream, "1.html", "w+");   
/////receive response from server
int totalData = 0, received_data = 0;
do
{
    char server_reply[100];
    received_data = recv(TcpClientSocket, server_reply, sizeof server_reply, 0);

    if (received_data > 0)
        printf("Bytes received: %d\n", iResult);
    else if (received_data == 0)
        printf("Connection closed\n");
    else
        printf("recv failed: %d\n", WSAGetLastError());

    totalData += received_data;

    fwrite(server_reply, received_data, 1, stream);

    printf("\nReceived byte  = %d\nTotal data = %d", received_data, totalData);

} while (received_data > 0);

printf("Reply received\n");
if (stream)
{
    if (fclose(stream))
    {
        printf("The file 'crt_fopen.c' was not closed\n");
    }
}
Zoe
  • 27,060
  • 21
  • 118
  • 148
Sandra
  • 1
  • 1
  • You have the extra blank line in the wrong place. It should be at the end of the headers. You also need `Content-length: 0`. And you should probably use `Connection: close`, otherwise you will get stalled for 300 pointless seconds at the end of the transfer. – user207421 Sep 11 '19 at 13:15
  • @user207421 I try your suggestion but i have the same problem. i replace message by as you said "message = "GET /download/pdfurl-guide.pdf HTTP/1.1\nHost: www.axmag.com\nConnection: keep-alive\nKeep-Alive: 300\nContent-length: 0\r\n\r\n\r\n"" – Sandra Sep 11 '19 at 14:28
  • 1
    @Sandra the 400 error is because you sent an unencrypted HTTP request to an encrypted HTTPS port (443). Your code is not implementing SSL/TLS at all, which is why you need to change the port to 80 instead, which is the standard unencrypted HTTP port. As for the request itself, you MUST use `\r\n` instead of `\n` for all of the line breaks, including the ones on the HTTP headers. Each header is terminated by 1 `\r\n`, and the message is terminated by an additional `\r\n`: `message = "GET /download/pdfurl-guide.pdf HTTP/1.1\r\nHost: www.axmag.com\r\nConnection: close\r\n\r\n";` – Remy Lebeau Sep 11 '19 at 20:08
  • 1
    @Sandra that being said, this code is still not even remotely close to being a viable HTTP client. Even if you send the request correctly (which you are not), you are not parsing the response at all to know if the request was even successful before you write any data to your local PDF file. You need to implement logic [more like this](https://stackoverflow.com/a/16247097/65863) instead. – Remy Lebeau Sep 11 '19 at 20:15
  • Why aren't you using the Http library for this? Saves all this mucking around. – user207421 Sep 11 '19 at 20:52
  • NB I didn't say anything about replacing `\r\n` with `\n`. Former is correct. – user207421 Sep 12 '19 at 01:56

1 Answers1

0

You need a TLS library so you can speek https to the server.

This is far too big to post an answer in C but since you are using Winsock you might as well use the builtin schannel.

Joshua
  • 40,822
  • 8
  • 72
  • 132