• Advertisement
Sign in to follow this  

Using libcurl to login to fetch sql table data

This topic is 3856 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So, yeah, like the subject says, I want to allow my server programs to take a user name and password, login to a core stats site (for instance), and modify or read mysql table data. So right now I'm trying to get the first part working, logging in. Using libcurl, I'm attempting to login using a form in a php-nuke site that looks like this:
<br>
<table width="100%" border="0" cellspacing="1" cellpadding="0" bgcolor="#0026FD"><tr><td>
<table width="100%" border="0" cellspacing="1" cellpadding="8" background="themes/Solaris/forums/images/bg_space_one_layer.jpg"><tr><td>
<form action="modules.php?name=Your_Account" method="post">
<b>User Login</b><br><br>
<table border="0"><tr><td>
Nickname:</td><td><input type="text" name="username" size="15" maxlength="25"></td></tr>
<tr><td>Password:</td><td><input type="password" name="user_password" size="15" maxlength="20"></td></tr>
</table><input type="hidden" name="redirect" value=>
<input type="hidden" name="mode" value=>
<input type="hidden" name="f" value=>
<input type="hidden" name="t" value=>
<input type="hidden" name="op" value="login">
<input type="submit" value="Login"></form><br>

So to test this out, for my curl post string I use this: curl -d "username=MyUserName&user_password=MyUserPassword" http://www.MySite.com/modules.php?name=Your_Account username and user_password are pretty obvious, but I'm not quite sure how to submit the form. I've tried a number of things without any luck. Using that string for the return value I get the "unknown user/password" page, which means something is wrong here, but I can't spot what (other than the submit). When I try to submit the form with op=Login, I get no result at all. Can anyone tell me what I'm missing here? Also, as far as retrieving and modifying the table data, is this really the best way to go about doing this. In the end what I want to have is a number of servers that sporadically update the central database with user statistics (think Battlefield 2). Does anyone have any experience on something like this that would be willing to share some advice? Thanks for any insights!

Share this post


Link to post
Share on other sites
Advertisement
Change the form method to GET and pass the user name/password as part of the URL. I don't think your -d data is properly formatted as a form post document.

Share this post


Link to post
Share on other sites
No, I definitely want to use POST. If you read here you'll see what I mean: http://curl.haxx.se/docs/httpscripting.html.

Specifically this part:
Quote:

4.2 POST

The GET method makes all input field names get displayed in the URL field of
your browser. That's generally a good thing when you want to be able to
bookmark that page with your given data, but it is an obvious disadvantage
if you entered secret information in one of the fields or if there are a
large amount of fields creating a very long and unreadable URL.

The HTTP protocol then offers the POST method. This way the client sends the
data separated from the URL and thus you won't see any of it in the URL
address field.

The form would look very similar to the previous one:

<form method="POST" action="junk.cgi">
<input type=text name="birthyear">
<input type=submit name=press value=" OK ">
</form>

And to use curl to post this form with the same data filled in as before, we
could do it like:

curl -d "birthyear=1905&press=%20OK%20" www.hotmail.com/when/junk.cgi

This kind of POST will use the Content-Type
application/x-www-form-urlencoded and is the most widely used POST kind.

The data you send to the server MUST already be properly encoded, curl will
not do that for you. For example, if you want the data to contain a space,
you need to replace that space with %20 etc. Failing to comply with this
will most likely cause your data to be received wrongly and messed up.


I think you're right though, my post is definitely not formatted properly, but I'm not sure why. Anyone?

Share this post


Link to post
Share on other sites
Okay, its 3.20am here in NZ, and I was up watching america's cup, what does this have to do you with you? nothing, appart from me not having the concentration to look at your problem in detail.

Hope this helps (it's MFC but should be easy to translate):


struct HttpRequestObj
{
CURL *sessionHandle;

std::vector<char> tempWriteBuffer;
size_t numBytesWritten;

HttpRequestObj() : sessionHandle(NULL), numBytesWritten(0)
{}

void resetWriteBuffer()
{
tempWriteBuffer.resize(0);
numBytesWritten = 0;
}

static size_t writeDataCB(void *buffer, size_t size, size_t nmemb, void *userp)
{
if( userp == NULL )
return 0;

HttpRequestObj *self = static_cast<HttpRequestObj*> (userp);
size_t oldSize = self->tempWriteBuffer.size();
char *p = NULL;

self->tempWriteBuffer.resize( self->tempWriteBuffer.size() + (size * nmemb) );
p = &self->tempWriteBuffer[0] + oldSize;
memcpy( p, buffer, (size * nmemb) );

self->numBytesWritten += (size * nmemb);

return size * nmemb;
}

} httpReq;

void HttpRequestInit()
{
if( curl_global_init( CURL_GLOBAL_ALL ) != 0 )
{
AfxMessageBox("Error initializing HTTP library", MB_ICONERROR|MB_OK);
return;
}
}

CString HttpRequestPost(CString url, CString pd, CStatusDlg& st)
{
if( httpReq.sessionHandle == NULL )
{
httpReq.sessionHandle = curl_easy_init();
if( httpReq.sessionHandle == NULL )
{
AfxMessageBox("Error initializing HTTP session handle", MB_ICONERROR|MB_OK);
return "";
}
}

curl_slist *headers = NULL;
headers = curl_slist_append( headers, "Content-Type: application/x-www-form-urlencoded");

int len = pd.GetLength();

curl_easy_setopt( httpReq.sessionHandle, CURLOPT_POSTFIELDS, pd );
curl_easy_setopt( httpReq.sessionHandle, CURLOPT_HTTPHEADER, headers );
curl_easy_setopt( httpReq.sessionHandle, CURLOPT_URL, url );
curl_easy_setopt( httpReq.sessionHandle, CURLOPT_WRITEFUNCTION, httpReq.writeDataCB );
curl_easy_setopt( httpReq.sessionHandle, CURLOPT_WRITEDATA, (void*) &httpReq );

httpReq.resetWriteBuffer();
CURLcode r = curl_easy_perform( httpReq.sessionHandle );

curl_slist_free_all( headers );

if( r != 0 )
{
CString msg;
msg.Format("Error performing HTTP request: Code %i", (int)r );
AfxMessageBox( msg, MB_ICONERROR|MB_OK );
return "";
}


CString response( (LPCSTR) &httpReq.tempWriteBuffer[0] );
return response;
}





where pd is a string like "msg=hello%20world&blah=bleh"

FYI > it definitely works, but it probably won't compile.

Share this post


Link to post
Share on other sites
Quote:
it is an obvious disadvantage if you entered secret information


While that may be true for browsers that store previous URL lines, I believe libcurl doesn't integrate with your browser history (and if it does, it should be re-educated :-)

On the wire, there is no security difference between GET and POST. However, if the destination requires POST, and you can't change the destination, then that's a good reason to want to POST.

Share this post


Link to post
Share on other sites
Quote:
Original post by hplus0603
Change the form method to GET and pass the user name/password as part of the URL. I don't think your -d data is properly formatted as a form post document.


Big no-no, if I understand the intentions of the OP right.

GET is designated for idempotent operations. It must never mutate the state, or very weird things can happen (see thedailywtf.com for examples). While it may work for the login itself, it really shouldn't be used for updating the stats.

Random link:
http://www.cs.tut.fi/~jkorpela/forms/methods.html

Note that as always, YMMV, but I feel that problems associated with this method are dangerous enough to be worth mentioning.

Share this post


Link to post
Share on other sites
Quote:
GET is designated for idempotent operations. It must never mutate the state


The result of a GET is the login data, in this case. That doesn't mutate the state -- the state mutates of itself. Or are you saying that if I have a web page that displays the time when the page was generated, or the number of page views, cannot be served by a GET request? After all, the page view counter goes up by each GET request.

In practice, there are some web caches that will cache GET requests (but you cannot cache POST requests) -- however, with the appropriate cache validators (or de-validators) in the headers, GET is fine for this purpose. Again, assuming the target application will actually accept a GET.

Share this post


Link to post
Share on other sites
Quote:
Original post by hplus0603
Quote:
GET is designated for idempotent operations. It must never mutate the state


The result of a GET is the login data, in this case. That doesn't mutate the state -- the state mutates of itself. Or are you saying that if I have a web page that displays the time when the page was generated, or the number of page views, cannot be served by a GET request? After all, the page view counter goes up by each GET request.

In practice, there are some web caches that will cache GET requests (but you cannot cache POST requests) -- however, with the appropriate cache validators (or de-validators) in the headers, GET is fine for this purpose. Again, assuming the target application will actually accept a GET.


The most dangerous situation comes from bots, who may, by following links, affect the internal state.

The idempotent here refers to the server's internal state, not the generated page. The counter itself is prone to abuse due to not following the rule - hence some counters restrict itself to unique IPs when determining the visitors.

The basic guideline is, that issuing a GET once or one million times should have no ill-effect on the server (it would however taint the counter). Not so in the case of updating a database using POST, where it's expected for some internal state to be affected by design.

This example isn't directly limited to GET vs. POST (involves cookies), but it does demonstrate the dangers of allowing GET requests to mutate the state:
http://worsethanfailure.com/Comments/The_Spider_of_Doom.aspx

Share this post


Link to post
Share on other sites
silvermace: That code works great, and I definitely get a response back from the server, but it's still not the one I'm expecting.

Can anyone tell me how I can actually submit the form data. '&op=Login' doesn't work, and a field name for the 'submit' element doesn't exist, only the 'Login' value. How do you submit to a form with an anonymous submit element. If this is more of an html question I apologize, but I figure someone around here must know.

BTW, thanks everyone for your feedback, I appreciate it.

Share this post


Link to post
Share on other sites
Quote:
Spider of Doom


Right. Don't build a site that's broken. I think we all agree on that :-)

Quote:
How do you submit to a form with an anonymous submit element.


The anonymous submit element is not by itself a problem.

Try this form in your browser, and see what the URL comes out as. Yes, it uses GET, just so you can easily see the URL!

<html><head><title>Test Form</title></head>
<body><form method='get'>
<input type='text' name='foo'/>
<input type='submit' value='Button'/>
</form>
</body>
</html>


(And, no, I didn't run it through the validator, and it doesn't have a doctype, etc -- it's just an illustration, that will happen to work)

Share this post


Link to post
Share on other sites
hplus0603: Perfect! I changed the form type to get instead of post, submitted the form and grabbed the resulting url output and it works great.

Thanks everyone!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement