jump to navigation

HTTP Server API – Need feedback June 21, 2010

Posted by Vitor Boschi in vitor-planetkde.
trackback

I’m rewriting my HTTP server as a shared lib, but there are some problems:

  1. I’d never wrote a lib before
  2. I’m not so experienced with the KDE libs

So, I’m putting a draft of what I have till the moment, and I hope you help me designing a proper API, by commenting on it about features you wish, class/methods naming and so on, in order to make it as KDEish as possible. Also, is there a better place for this discussion/brainstorm? I think a wiki would be better suited for people to contribute, but I’m not sure the TechBase is the right place for this.

So, here are the two main classes (the complete code can be found here http://websvn.kde.org/trunk/playground/utils/kpws/httpd/):
class KHttpDaemon : public QObject {
Q_OBJECT
public:
KHttpDaemon(QObject *parent=0);
~KHttpDaemon();
void setPort(quint16 port); /* defaults to 8080 */
void setListeningAddress(const QHostAddress &address); /* defaults to 127.0.0.1 */
bool isListening() const;
int addContent(const QString &url, AbstractContent *content);
AbstractContent* getContent(const QString &url) const;
int removeContent(const QString &url);

public slots:
void startListening(); /* this operation may fail because of lack of permissions (port number < 1024) or port already in use. */
void stopListening();

signals:
void clientConnected(const Client &client);
void clientDisconnected(const Client &client);
void contentRequested();
}

class AbstractContent {
public:
typedef enum {
AT_ONCE, /* all the content will be fetched at once. User can ignore start and len parameters */
CHUNKED /* content will be retrieved as a sequence of chunks. Useful for large content */
} ServingMode;

virtual ~AbstractContent() {};
virtual HttpResponseHeader responseHeader(HttpRequest &request) = 0;
virtual ServingMode mode() const = 0;

virtual int getChunk(QByteArray* buffer, qint64 start, int len, const HttpRequest &request) = 0;
}

All the content is made by subclassing AbstractContent (or by using one of the provided, like StaticContent). The idea is that you just need to instantiate KHttpDaemon,  add some content, and start it. Here is a Hello World example:

#include <KApplication>
#include <KAboutData>
#include <KCmdLineArgs>
#include <KLocale>
#include <QLabel>

#include “khttpdaemon.h”
#include “staticcontent.h”

/* Sample use case for the KHttpDaemon */
int main (int argc, char *argv[])
{
KAboutData aboutData( “httpd_sample”, 0,
ki18n(“KHttpDaemon sample”), “1.0″,
ki18n(“A simple text area”),
KAboutData::License_GPL,
ki18n(“Copyright (c) 2010 Vitor Boschi da Silva”) );
KCmdLineArgs::init( argc, argv, &aboutData );
KApplication app;
QLabel *l;

KHttpDaemon *daemon;
daemon = new KHttpDaemon();
daemon->addContent(“index.html”, new StaticContent(QString(“<html><body><h1>Hello world!</h1></body></html”)));
daemon->startListening();
l = new QLabel(“Server up and running!”);
l->show();

return app.exec();
}

There are a lot of code to write yet, but I’d like to get some advices about it. Thanks in advance.

About these ads

Comments»

1. Diederik van der Boor - June 21, 2010

A few suggestions for your API:
* Rename the server class to KHttpServer. A ‘daemon’ refers to the whole process, not the server socket class.
* I think the AbstractContent can be replaced with a KHttpResponse object, which gives access to the response headers + a QIODevice to read the response.
* Same for sending, this can be overloaded method, which accepts either a QString or QIODevice.

2. Diederik van der Boor - June 21, 2010

Other than that, the idea of a HTTP server code is pretty cool.

Just figured, these kind of things are also better discussed on the kde-devel mailing list. You’ll find high quality responses there from other KDE developers!

3. Frank - June 21, 2010

1) You say startListening() may fail, but there is no API to find out about the error. add an error() signal, and/or a QString errorString() const.

2) KHttpDaemon(QObject *parent=0);

-> explicit KHttpDaemon( QObject* parent=0)

3) enum ServingMode {
AtOnce,
Chunked
};

would be more Qt-ish.

4. Sandro Andrade - June 21, 2010
5. Chris - June 21, 2010

I’m still wondering why you are trying to reinvent the wheel instead of e.g. reusing libmicrohttpd (which is quite well tested and used by many projects) by writing an easier to use wrapper around it for KDE?

Vitor Boschi - June 21, 2010

Mostly because libmicrohttpd may not be supported on all Qt/KDE supported platforms, but also ’cause it doesn’t look to support bandwidth throttling, which is a very important featuro IMHO, and it would make harder to eventually add support for WebDAV.

6. Darkstar - June 21, 2010

Support for dynamic content/parameters. I.e. you “define” something like “index.html” but don’t want a static site but some dynamic processing that takes place if you for example request “index.html?name=foo&param=23″ so that you can do something in your app (e.g. reconfigure an option) and/or provide a custom response html to the user

Vitor Boschi - June 21, 2010

This is already supported by the API and it’s partially implemented. I will create some samples showing how to serve a big file and how to create dynamic content.

7. Vitor Boschi - June 21, 2010

Thanks for all your help so far. I’ll be working on it through this week, and hope to have a usable solution very soon.

8. Kevin Krammer - June 21, 2010

Depending on whether addContent() can do that already, but you might want to be able to register some content handler for a base URL that gets asked for all subpaths as well.

E.e. registering for /files and being called for /files/file1.txt /files/file2.png, etc.

since this could mean more than one request for the same object, the object will probably have to be cloned, e.g. registering a prototype, requests handled by individual instances

9. Richard Moore - June 21, 2010

1) Missing d pointers

2) int addContent(const QString &url, AbstractContent *content);

What is the int returned? Looks like it should probably be an enum of why this can fail.

3) void startListening();

If this can fail then it should return an error code (eg. a bool)
and there should be corresponding methods to report the issue. Making this a slot seems rather odd.

4) void stopListening();

Why is this a slot?

5) typedef enum {
AT_ONCE, /* all the content will be fetched at once. User can ignore start and len parameters */
CHUNKED /* content will be retrieved as a sequence of chunks. Useful for large content */
} ServingMode;

Unlike C, you don’t need the typedef in C++. The enum names don’t follow the KDE or Qt coding conventions – consider names like ServeAtOnce. Instead.

You should go back to the QTcpServer docs and try to follow the naming scheme used there for consistency. I think you might need to spend a bit of time setting out the intended uses of this class in order to get a good API.

10. Templating HTML Applications with Grantlee « Steveire's Blog - February 6, 2011

[...] HTML Applications with Grantlee By steveire A lot of people are talking about using web technologies with Qt [...]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: