HTTP Connections
This tutorial will show you the basics of HTTP connections in MoSync. You will see how easy it is to write applications which can access HTTP-based information. You will also see how easy it is to stream information over HTTP. This example is written from a Moblet template.
Initializing
#include <mautil/connection.h>
#include <mastdlib.h>
#include <conprint.h>
#define CONNECTION_BUFFER_SIZE 1024
connection.h is included to provide the basic connection functionallity.
mastlib.h is included to add the atoi function which converts the contents of an array to an int.
conprint.h adds the printf function which writes text to the screen as a simple console.
CONNECTION_BUFFER_SIZE defines the size of the buffer in which data is collected.
class MyMoblet : public MAUtil::Moblet, private MAUtil::HttpConnectionListener
To provide the functionallity we inherit function declarations from the HttpConnectionListener class.
void httpFinished(MAUtil::HttpConnection *conn, int result);
void connRecvFinished(MAUtil::Connection *conn, int result);
void connReadFinished(MAUtil::Connection *conn, int result);
The httpFinished function is a callback which is called whenever a http connection is initiated and we can recieve a response. When we use the recv function for the http connection connRecvFinished is called everytime a new chunk of data is recieved. If we use the read function instead, the connReadFinished function will be called when the read is done. More about these functions later in this tutorial.
char mBuffer[CONNECTION_BUFFER_SIZE];
MAUtil::HttpConnection mHttp;
mHttp is a MAUtil::HttpConnection object which represents the actual connection. Each one of these may only handle one connection at the time so to enable multiple connections we need to define multiple HttpConnection objects. Always make sure that a connection is closed before connecting to it again.
MyMoblet::MyMoblet() : mHttp(this)
The constructor sets itself as the listener for the HttpConnection object so that the callbacks declared in MyMoblet will be used.
InitConsole();
gConsoleLogging = 1;
In our entry point, MAMain we initialize the console and enable logging. This means that everything that everything that we send to the console is also logged in a log file. If you handle large amount of data and would want to output information to verify behaviours of your application this will help you. This file is located in the Output folder of your project and is called log.txt.
Connections and Responses
Too initiate an http connection we call the create function of the HttpConnection object. All you need to provide is the url and if you need to use GET or POST. In this example we send a POST request to a server.
int res = mHttp.create(url, HTTP_POST);
if(res < 0) {
printf("unable to connect - %i\n", res);
} else {
mHttp.finish();
mIsConnected = true;
}
If the create function returns a value below zero this means that it have failed for some reason. Please check the API references for all the possible return values. It's only possible to have one active connection on each HttpConnection object. Due to this we must make sure that we don't try to reconnect an active connection. If the create call was successful we can now set request headers. Since we don't need it we can call the finish function directly.
When we have a connection with the server the callback function httpFinished will be called.
MAUtil::String contentLengthStr;
int responseBytes = mHttp.getResponseHeader("content-length", &contentLengthStr);
int contentLength = 0;
if(responseBytes == CONNERR_NOHEADER)
printf("no content-length response header\n");
else {
printf("content-length : %s\n", contentLengthStr.c_str());
contentLength = atoi(contentLengthStr.c_str());
}
First we check for the "content-length" response header, if it's not found we will recieve an CONNERR_NOHEADER response. If it's found we recieves the actual content length as an char array of numbers. It's then converted it to an int using the atoi function.
if(contentLength >= CONNECTION_BUFFER_SIZE || contentLength == 0) {
printf("Receive in chunks..\n");
mHttp.recv(mBuffer, CONNECTION_BUFFER_SIZE);
} else {
mBuffer[contentLength] = 0;
mHttp.read(mBuffer, contentLength);
}
If we don't have any content length or it's larger then our recieving buffer we can't just read all the data. We have to read multiple times until we reaches the end. This is done by calling the recv function of the HttpConnection object.
If we know the content length and the recieving data fits inside the buffer we can read it all directly. This is done by using the read function in HttpConnection.
The difference between the two is that recv specifies the total amount of bytes which it can recieve while read specifies the number of bytes it shall read. Each of these methods has its own callback functions. Depending on the function you use connRecvFinished or connReadFinished callback functions will be called.
if(result >= 0)
printf("connReadFinished %i\n", result);
else
printf("connection error %i\n", result);
mHttp.close();
The connReadFinished callback function first check if the result is not negative. A negative result means an error might have happened. Check the return value against the API documentation. Positive results means that data was received. The connection shall be closed manually now since no more data will be received on this connection.
if(result >= 0) {
printf("connRecvFinished %i\n", result);
mHttp.recv(mBuffer, CONNECTION_BUFFER_SIZE);
return;
}
else if(result == CONNERR_CLOSED) {
printf("Receive finished!\n");
} else {
printf("connection error %i\n", result);
}
mHttp.close();
The connRecvFinished callback function works a little bit different. If the result is positive we have received that amount of bytes. If so we can't close the connection since more data will be received. If it's negative we must check if it's CONNERR_CLOSED. CONNERR_CLOSED doesn't need to be an error. Usually it means that the sending server has sent its data and closed the connection to verify the receiver about it. When a negative value is returned the connection shall be closed.
In this tutorial we have had a look at how easy it is to access HTTP information and also stream such information to your application. With this basic knowledge you will easily build your applications which will use web based information.
For further information also read the sockets tutorial and the tutorial concerning the downloader.
Example Source Code
#include <MAUtil/Moblet.h>
#include <mautil/connection.h>
#include <mastdlib.h>
#include <conprint.h>
#define CONNECTION_BUFFER_SIZE 1024
class MyMoblet : public MAUtil::Moblet, private MAUtil::HttpConnectionListener
{
public:
MyMoblet();
void httpFinished(MAUtil::HttpConnection *conn, int result);
void connRecvFinished(MAUtil::Connection *conn, int result);
void connReadFinished(MAUtil::Connection *conn, int result);
void keyPressEvent(int keyCode);
private:
void initiateConnection(const char* url);
char mBuffer[CONNECTION_BUFFER_SIZE];
MAUtil::HttpConnection mHttp;
bool mIsConnected;
};
MyMoblet::MyMoblet() : mHttp(this)
, mIsConnected(false)
{
printf("http connection tutorial.\n");
printf("press softkeys to send http requests.\n");
printf("press 0 to exit\n");
}
// connect to the given url if not other connection is active
void MyMoblet::initiateConnection(const char* url) {
if(mIsConnected) {
printf("already connected\n..");
return;
}
printf("\nconnecting to %s", url);
int res = mHttp.create(url, HTTP_POST);
if(res < 0) {
printf("unable to connect - %i\n", res);
} else {
mHttp.finish();
mIsConnected = true;
}
}
void MyMoblet::httpFinished(MAUtil::HttpConnection* http, int result) {
printf("HTTP %i\n", result);
MAUtil::String contentLengthStr;
int responseBytes = mHttp.getResponseHeader("content-length", &contentLengthStr);
int contentLength = 0;
if(responseBytes == CONNERR_NOHEADER)
printf("no content-length response header\n");
else {
printf("content-length : %s\n", contentLengthStr.c_str());
contentLength = atoi(contentLengthStr.c_str());
}
if(contentLength >= CONNECTION_BUFFER_SIZE || contentLength == 0) {
printf("Receive in chunks..\n");
mHttp.recv(mBuffer, CONNECTION_BUFFER_SIZE);
} else {
mBuffer[contentLength] = 0;
mHttp.read(mBuffer, contentLength);
}
}
void MyMoblet::connReadFinished(MAUtil::Connection* conn, int result) {
if(result >= 0)
printf("connReadFinished %i\n", result);
else
printf("connection error %i\n", result);
mHttp.close();
mIsConnected = false;
}
void MyMoblet::connRecvFinished(MAUtil::Connection * conn, int result){
if(result >= 0) {
printf("connRecvFinished %i\n", result);
mHttp.recv(mBuffer, CONNECTION_BUFFER_SIZE);
return;
}
else if(result == CONNERR_CLOSED) {
printf("Receive finished!\n");
} else {
printf("connection error %i\n", result);
}
mHttp.close();
mIsConnected = false;
}
// Press 0 to exit. Soft left and soft right will initiate new connections
void MyMoblet::keyPressEvent(int keyCode) {
switch(keyCode) {
case MAK_0:
maExit(0);
break;
case MAK_SOFTLEFT:
initiateConnection("http://www.example.com/");
break;
case MAK_SOFTRIGHT:
initiateConnection("http://www.mosync.com/");
break;
}
}
extern "C" int MAMain() {
InitConsole();
gConsoleLogging = 1;
MAUtil::Moblet::run(new MyMoblet());
}
- Printer-friendly version
- Login or register to post comments
Share on Facebook