Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

Posting to an ASP website via Windows sockets in C

4.92/5 (8 votes)
13 Feb 2011CPOL2 min read 19.2K  
Posting data to an Internet server made easy with a slick C/C++ class wrapping a call to Windows sockets.

Introduction

Ever needed a quick way to get around to post text to a web server and get a response accordingly? Look no further. In this article, I give the reader a class with two methods for testing the availability of a connection and for posting information.

Background

I use this code to post major text files, line by line, of summaries on PocketPC (Windows Mobile) to a statistical web site via an ASP file.

Using the Code

While under Windows, you can send information on an open socket and read information from the same spot. This is nothing new, but using a socket to post to an internet server can be tricky, especially getting the 'post' syntax absolutely flawless.

As you can see on the header and body text below this paragraph, there is a macro SEND_RQ just for passing clear text values, so do not get misled by any strange char in the C/C++ strings.

C++
#define _DEBUG_PRINT(X)   /* X */
#include <iostream>
#include <string>
#include <stdlib.h>
#include <assert.h>
#include <Winsock2.h>
#define VERSION_MAJOR 1;
#define VERSION_MINOR 1;
#define CRLF "\r\n"    // carriage-return/line feed pair
#define SEND_RQ(MSG) send(sock,MSG, (int) strlen(MSG),0);
using namespace std;
class CHttp
{
public:
    WSADATA                WsaData;
    sockaddr_in            sin;
    size_t                 sock ;
    CHttp(void);
    ~CHttp(void);
    int TestConnectionToHostName (char* hostname);
    int Post (char* hostname, char* api, char* parameters, string& message);
};

#include "StdAfx.h"
#include "CHttp.h"

CHttp::CHttp(void)
{
}
CHttp::~CHttp(void)
{
}
int CHttp::TestConnectionToHostName (char* hostname)
{
    WSAStartup (0x0101, &WsaData);
        sock =  socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1) 
    {
        return -100;
    }
        sin.sin_family = AF_INET;
        sin.sin_port = htons( (unsigned short)80);
        struct hostent * host_addr = gethostbyname(hostname);
        if(host_addr==NULL) 
    {
        return -101;
        }
        sin.sin_addr.s_addr = *((int*)*host_addr->h_addr_list) ;
        if( connect (sock,(const struct sockaddr *)&sin, sizeof(sockaddr_in) ) == -1 ) 
    {
        return -102;
        }
    WSACleanup( );
    return 0;
}

int CHttp::Post (char* hostname, char* api, char* parameters, string& message)
{
    WSAStartup (0x0101, &WsaData);
        sock =  socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1) 
    {
        return -100;
    }
        sin.sin_family = AF_INET;
        sin.sin_port = htons( (unsigned short)80);
        struct hostent * host_addr = gethostbyname(hostname);
        if(host_addr==NULL) 
    {
        return -101;
        }
        sin.sin_addr.s_addr = *((int*)*host_addr->h_addr_list) ;

        if( connect (sock,(const struct sockaddr *)&sin, sizeof(sockaddr_in) ) == -1 ) 
    {
        return -102;
    }
    string send_str;
    char content_len[STRING_SIZE_256];
    sprintf(content_len,"Content-Length: %d\r\n",strlen(parameters));
    char host_api[STRING_SIZE_256];
    strcpy(host_api, "http://");
    strcat(host_api, hostname);
    strcat(host_api, api);
    SEND_RQ("POST "); SEND_RQ(host_api); SEND_RQ(" HTTP/1.0\r\n");
    SEND_RQ("From: any@sidegence.com\r\n");
    SEND_RQ("User-Agent: Mozilla/4.0\r\n");
    SEND_RQ("Content-Type: application/x-www-form-urlencoded\r\n");
    SEND_RQ(content_len);
    SEND_RQ("\r\n");
    SEND_RQ(parameters);
    SEND_RQ("\r\n");
    char c1[1];
    int l,line_length;
    bool loop = true;
    bool bHeader = false;
    while(loop) 
    {
        l = recv(sock, c1, 1, 0);
        if(l<0) 
            loop = false;
        if(c1[0]=='\n') 
        {
            if(line_length == 0) 
                loop = false;
            line_length = 0;
            if(message.find("200") != string::npos)
                bHeader = true;
        }
        else 
            if(c1[0]!='\r') 
                line_length++;
        message += c1[0];
    }

     message="";
     if(bHeader) 
     {
         char p[1024];
         while((l = recv(sock,p,1023,0)) > 0)  
            {
                 p[l] = '\0';
                 message += p;
             }
    } 
    else 
    {
        return -103;
    }
    
    int index = (int) message.find("E01");
    if (index>=0) return -104;
    WSACleanup( );
    return 0;
}

The testing method allows the class Client to perceive its readiness to post, that is, it evaluates the presence of a connection - this may be important if working with Windows Mobile, because you may want the application to post only while docking (via USB or whatever) to a connected machine - therefore saving money on internet calls.

If used on an always connected (typically a PC) machine, you may only want to post with a specific schedule, it's up to you.

Points of Interest

I tried many syntaxes for the HTTP POST, and after a careful W3C review, I found that this is the one that works:

C++
SEND_RQ("POST "); SEND_RQ(host_api); SEND_RQ(" HTTP/1.0\r\n");
SEND_RQ("From: any@sidegence.com\r\n");
SEND_RQ("User-Agent: Mozilla/4.0\r\n");
SEND_RQ("Content-Type: application/x-www-form-urlencoded\r\n");
SEND_RQ(content_len);
SEND_RQ("\r\n");
SEND_RQ(parameters);
SEND_RQ("\r\n");

Of course, you will understand the variables better after adding the class to a client project and doing a debug session if you want; the names are fairly descriptive.

After the POST is done, the ASP code is fairly simple; I mean you can just get the QueryString values and parse each variable that reaches the page, process it, and return on the Response object an acknowledgement code return value.

At the end of the method, you can see a 'message' return pattern matching for codes. I used 'E01', etc., to return coding information from the ASP side.

History

  • First version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)