Question

now I started studying the sockets. But it's not working properly with my hands. I have cool method for logging in:

int LogIn(const string &name, const string &password)
{
char Buffer[1024];
string data = "login=" + name + "&password=" + password;
sprintf(Buffer, "POST /Test/login_cl.php HTTP/1.1\r
"\nContent-Length: %d\r"
"\nConnection: Keep-Alive\r"
"\nAccept-Encoding: gzip\r"
"\nAccept-Language: ru-RU,en,*\r"
"\nUser-Agent: Mozilla/5.0\r"
"\nHost: 127.0.0.1\r"
"\nContent-Type: application/x-www-form-urlencoded\r\n\r\n"    
"login=%s&"
"password=%s&", data.length(), name.c_str(), password.c_str());
int BytesSent = send(MySocket, Buffer, sizeof(Buffer), 0);
string test;
char ans;
while (recv(MySocket, &ans, 1, 0))
test.push_back(ans);
cout << test << endl;

return 0;
}

And problem is that i can call this method only once. Other calls or calls for logout methods are not working, for example:

int result = LogIn(logn, paswd);
int result = LogIn(logn, paswd);

is not working, I receive only one answer (second is empty and recv is returning -1)

Please help, thanks.

Was it helpful?

Solution

int BytesSent = send(MySocket, Buffer, sizeof(Buffer), 0);

This sends too many bytes of data, leaving the other side with a whole bunch of junk at the end of the request that it thinks is part of the next request.

string data = "login=" + name + "&password=" + password;

This has the query with no & on the end.

"password=%s&", data.length(), name.c_str(), password.c_str());

This puts an & on the end of the query. Well, which is it?

You need to fix two things:

  1. Be consistent about the & on the end of the query. (Why do you compose the query string twice anyway?)

  2. Use strlen(Buffer) instead of sizeof(Buffer).

Really though, you should use an implementation of the actual protocol specification rather than code like this. For example, what happens if there's an & in the password? What happens if the server decides to use chunked encoding in the reply? You don't actually implement HTTP 1.1, yet you claim that you do. That will lead to lots and lots of pain, sooner or later.

OTHER TIPS

You are sending too many bytes, you are not formatting the body of the POST message correctly, and you are not reading the response correctly at all.

If you are going to use C++ for some of your string handling then you should use C++ for all of your string handling, avoid mixing C string handling if you can.

Try something more like this instead:

const string SafeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789*-._";

string Urlencode(const string &str)
{
    if (str.length() == 0)
        return string();

    ostringstream buffer;

    for (int I = 0; I < ASrc.length(); ++I)
    {
        char ch = ASrc[I];

        if (ch == ' ')
            buffer << '+';
        else if (SafeChars.find(ch) != string::npos)
            buffer << ch;
        else
            buffer << '%' << setw(2) << fillchar('0') << hex << ch;
    }

    return buffer.str();
}

int LogIn(const string &name, const string &password)
{
    string data = "login=" + Urlencode(name) + "&password=" + Urlencode(password);
    ostringstream buffer;
    buffer << "POST /Test/login_cl.php HTTP/1.1\r\n"
        << "Content-Length: " << data.length() << "\r\n"
        << "Connection: Keep-Alive\r\n"
        << "Accept-Encoding: gzip\r\n"
        << "Accept-Language: ru-RU,en,*\r\n"
        << "User-Agent: Mozilla/5.0\r\n"
        << "Host: 127.0.0.1\r\n"
        << "Content-Type: application/x-www-form-urlencoded\r\n"
        << "\r\n"    
        << data;

    string request = buffer.str(); 
    const char *req = request.c_str();
    int reqlen = request.length();

    do
    {
        int BytesSent = send(MySocket, request.c_str(), request.length(), 0);
        if (BytesSent <= 0)
            return -1;
        req += BytesSent;
        reqlen -= BytesSent;
    }
    while (reqlen > 0);

    // you REALLY need to flesh out this reading logic!
    // See RFC 2616 Section 4.4 for details
    string response;
    char ch;
    while (recv(MySocket, &ch, 1, 0) > 0)
        response += ch;
    cout << response << endl;

    return 0;
}

I will leave it as an exercise for you to learn the correct way to read an HTTP response (HINT: it is a LOT harder then you think - especially since you are including Accept-Encoding: gzip and Connection: Keep-Alive headers, which have big impacts on response handling. Read RFC 2616 Section 4.4 for details how to determine the response length and format).

With that said, HTTP is not a trivial protocol to implement by hand, so you really should use a premade HTTP library, such as libcurl, or use Microsoft's own WinInet or WinHTTP APIs.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top