Coder Social home page Coder Social logo

qhttp's Introduction

QHttp

Table of contents

About

TOC

QHttp is a lightweight, asynchronous and fast HTTP library in c++14 / Qt5, containing both server and client side classes for managing connections, parsing and building HTTP requests and responses.

  • the objective of QHttp is being light weight with a simple API for Qt developers to implement RESTful web services in private (internal) zones. more
  • by using std::function and c++14 generic lambda, the API is intentionally similar to the Node.js' http module. Asynchronous and non-blocking HTTP programming is quite easy with QHttp. have a look at sample codes.
  • the fantastic nodejs/http-parser (which is a single pair of *.h/*.c files) is the only dependency of the QHttp.

attention: c++14 is the minimum requirement for version 3.0+ please see releases

This project was inspired by nikhilm/qhttpserver effort to implement a Qt HTTP server. QHttp pushes the idea further by implementing client side classes, better memory management, a lot more Node.js-like API, ...

Sample codes

TOC

a HelloWorld HTTP server by QHttp looks like:

int main(int argc, char** argv) {
    QCoreApplication app(argc, argv);

    using namespace qhttp::server;
    QHttpServer server(&app);
    server.listen( // listening on 0.0.0.0:8080
        QHostAddress::Any, 8080,
        [](QHttpRequest* req, QHttpResponse* res) {
            // http status 200
            res->setStatusCode(qhttp::ESTATUS_OK);
            // the response body data
            res->end("Hello World!\n");
            // automatic memory management for req/res
    });

    if ( !server.isListening() ) {
        qDebug("failed to listen");
        return -1;
    }

    return app.exec();
}

to request weather information by HTTP client:

int main(int argc, char** argv) {
    QCoreApplication app(argc, argv);

    using namespace qhttp::client;
    QHttpClient client(&app);
    QUrl        weatherUrl("http://wttr.in/tehran");

    client.request(qhttp::EHTTP_GET, weatherUrl, [](QHttpResponse* res) {
        // response handler, called when the incoming HTTP headers are ready

        // gather HTTP response data (HTTP body)
        res->collectData();

        // when all data in HTTP response have been read:
        res->onEnd([&]() {
            writeTo("weather.html", res->collectedData());

            // done! now quit the application
            qApp->quit();
        });

        // just for fun! print incoming headers:
        qDebug("\n[Headers:]");
        res->headers().forEach([](auto cit) {
            qDebug("%s : %s", cit.key().constData(), cit.value().constData());
        });
    });

    // set a timeout for the http connection
    client.setConnectingTimeOut(10000, []{
        qDebug("connecting to HTTP server timed out!");
        qApp->quit();
    });

    return app.exec();
}

Features

TOC

  • the only dependencies are: Qt5, c++14 and the http-parser
  • both TCP and UNIX (local) sockets are supported as backend.
  • separate namespaces for server and client classes.
  • HTTP server classes: QHttpServer, QHttpConnection, QHttpRequest and QHttpResponse.
  • optional HTTP client classes: QHttpClient, QHttpRequest and QHttpResponse. the client classes can be disabled at build time by commenting QHTTP_HAS_CLIENT in common.dir
  • automatic memory management of objects. Instances of connections, requests and replies will be deleted automatically when socket drops or disconnected.
  • PIMPL (Private implementaion) to achieve better ABI compatibility and cleaner API and faster compile time.
  • Asynchronous and non-blocking. You can handle thousands of concurrent HTTP connections efficiently by a single thread, although a multi-threaded HTTP server is easy to implement.
  • high throughput, I have tried the QHttp and gason++ to implement a REST/Json web service on an Ubuntu VPS (dual core + 512MB ram) with more than 5800 connections per second (stress test). On a MacBook Pro (i5 4258U, 8GB ram), QHttp easily reaches to more than 11700 connections / second. Generally QHttp is 1.5x ~ 3x faster than Node.js depending on your machine / OS.
  • Easily portable where ever Qt5 / c++14 works. Tested under:
    • Linux Ubuntu 12.04 ~ 16.04 LTS, g++ 5.3+
    • OS X 10.9+, clang 3.7+
    • Windows 7/8.1, msvs2015 / mingw (g++ 6.1)

Setup

TOC

instructions:

# first clone this repository:
$> git clone https://github.com/azadkuh/qhttp.git
$> cd qhttp

# prepare dependencies:
$qhttp/> ./update-dependencies.sh

# now build the library and the examples
$qhttp/> qmake -r qhttp.pro
$qhttp/> make -j 8

Multi-threading

TOC

As QHttp is asynchronous and non-blocking, your app can handle thousands of concurrent HTTP connections by a single thread.

in some rare scenarios you may want to use multiple handler threads (although it's not always the best solution):

  • there are some blocking APIs (QSql, system calls, ...) in your connection handler (adopting asynchronous layer over the blocking API is a better approach).
  • the hardware has lots of free cores and the measurement shows that the load on the main QHttp thread is close to highest limit. There you can spawn some other handler threads.

Source tree

TOC

  • src/: holds the source code of QHttp. server classes are prefixed by qhttpserver* and client classes by qhttpclient*.
    • private/: Private classes of the library.
  • 3rdparty/: will contain http-parser source tree as the only dependency. this directory is created by setup. see also: setup.
  • example/: contains some sample applications representing the QHttp usage:
    • helloworld/: the HelloWorld example of QHttp, both server + client are represented. see: README@helloworld
    • basic-server/: a basic HTTP server shows how to collect the request body, and respond to the clients. see: README@basic-server
    • keep-alive: shows how to keep an http connection open and transmitting many requests/responses. see: README@keep-alive
    • post-collector: another server example shows how to collect large data by POST requests. see: README@post-collector
  • tmp/: a temporary directory which is created while makeing the library and holds all the .o, moc files, etc.
  • xbin/: all the executable and libraries will be placed on this folder by build system.

Disclaimer

TOC

  • Implementing a lightweight and simple HTTP server/client in Qt with Node.js like API, is the main purpose of QHttp.
  • There are lots of features in a full blown HTTP server which are out of scope of this small library, although those can be added on top of QHttp.
  • The client classes are by no mean designed as a QNetworkAccessManager replacement. QHttpClient is simpler and lighter, for serious scenarios just use QNetworkAccessManager which supports proxy, redirections, authentication, cookie jar, ssl, ...
  • I'm a busy person.

If you have any ideas, critiques, suggestions or whatever you want to call it, please open an issue. I'll be happy to hear different ideas, will think about them, and I try to add those that make sense.

License

TOC

Distributed under the MIT license. Copyright (c) 2014, Amir Zamani.

qhttp's People

Contributors

azadkuh avatar ivanbelyakoff avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

qhttp's Issues

Document collectData()

Hi!

I'm struggling with implementing a server. I started out with keep-alive example but for some reason the json body received always appears to be 0 bytes long (it is in fact not, I tested with other non-qhttp servers (php and netcat) and they receive the 84 bytes of json data just fine).

I think the bug in my software is caused by my lack of understasnding of the collectData() call. What is the integer parameter it accepts? Can I omit the call to collectData() and still get request body? What are other possible causes of receiving empty body in request? How should I go about debugging this?

Thanks!

PS: Big fan of your work!

QHttpResponse::allBytesWritten stops emiting when writing

The "QHttpResponse::allBytesWritten" signal is emited only a few times when manually writing data to the client. This leads to incomplete downloads.

`req->onEnd(this, req, res {

QFile* f = new QFile(filename); // a file of some MB size
if (f->open(QFile::ReadOnly))
{
	res->addHeader("content-length", QString::number(f->size()).toLatin1());
	res->addHeader("content-type", "application/octet-stream");
	res->addHeader("content-disposition", QStringLiteral("attachment; filename=\"%1\"").arg(info.fileName()).toLatin1());
	//res->addHeader("connection", "Keep-Alive");
	//res->addHeader("keep-alive", "timeout=600, max=100");
	res->setStatusCode(qhttp::ESTATUS_OK);
	connect(res, &QHttpResponse::allBytesWritten, this, [this, f, res] {
		qDebug() << "Write more... " << f->pos(); // called only a few times
		QByteArray data = f->read(50000);
		if (data.length() == 0)
		{
			qDebug() << "END"; // never called
			res->end();
			f->close();
			f->deleteLater();
		}
		else
		{
			res->write(data); // called a few times
		}
	});

	QByteArray data = f->read(50000);
	if (data.length() > 0)
	{
		res->write(data);
		return;
	}
	else
	{
		f->close();
	}
}
f->deleteLater();

});`

server connection time-out of 2minutes

While using the library in a server application our client application wants to re-use a single connection to the server.

Although we have this working we are finding that the server appears to be closing the connection ~2minutes after processing the last request.
For the client application there is a dialog whereby this timeout can be exceeded pending user input.

The QHttpServer::setTimeOut() method sets the time-out to close the connection Xms after receiving the initial connection so changing this doesn't solve our issue.

I haven't been able to identify where in the library this 2minute time-out is set - Is there an available method to change/extend this timeout?

Any help would be greatly appreciated.

Crash on disconnect of empty connections

I believe this is a bug:

Whenever a connection is closed, onDispatchRequest() will be called.

In onDispatchRequest(), you try to access ilastRequest. The problem is that if no requests were sent, ilastRequest is NULL, and this causes a crash.

I find that such empty connections are made by browsers, and this bug crashes the server every time I request resource from a browser (only tested on Chrome on Mac).

To reproduce, I just run the hello world example: ./xbin/helloworld -p 8080 server
..and send an empty connection: echo "" | telnet localhost 8080

Consider moving back to C++11

Motivation

C++14 is still not widely supported by Linux baselines. Furthermore, the v3.0 release is FAR superior to the v2.1 release, yet the requirement for C++14 largely has nothing to do with that superiority.

We are looking to integrate qhttp into KeePassXC but we cannot move to C++14 due to backwards compatibility.

Details

There are only two places in the code that require the use of C++14:

httpparser.hxx#L98
which can easily be fixed by changing the auto to TImpl* since you are static casting it anyway.

httpwriter.hxx#L87
This loop block was rewritten in C++14 syntax for no obvious gain. It can be easily reverted back to the C++11 equivalent:

        for ( auto cit = TBase::iheaders.constBegin(); cit != TBase::iheaders.constEnd(); cit++ ) {
            const QByteArray& field = cit.key();
            const QByteArray& value = cit.value();

            writeHeader(field, value);
        }

Qt Warning

main.cpp:94:16: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 4 has type ‘std::chrono::duration<long int, std::ratio<1l, 1000l> >::rep {aka long int}’ [-Wformat=]
);

Multithreading strategy

Hi,
writing my server application i've found that long operations can easily cause the application to become irresponsive until the completion.

Since the tests i've done i don't see the need to enable the multithreading support of QHttp since the overhead of the lib is really really low (well done), so possibly i'd use a single threaded listener for connections but i have the need to move to some workers threads the execution of the ops related to each specific request.

Is this the right approach? Can you suggest me the 'best' way to do such thing with QHttp?

I have the feeling that i'm gonna encounter such affinity problems with the QNetworkAccessManager this way but i'm not sure of this (expecially to transmit back the reply).

Thank you!
Please, keep doing this great job.

Do NOT change the case of HTTP (header) tags values.

Hi,

IMO, the change of HTTP tags for comparison is fine but the values should remain intact.
For example, in case of custom headers the value may be a JSON object with strings in it.
I suggest that for all known headers it is okay to change the case (I can't think of a scenario where is should not) but for unknown headers it should NOT change the case.

Thanks!

~ AZEEM ~

Base64 Error

Base64 value in header field in lowercase will lead to parsing error in QByteArray::fromBase64(...). Try to create base server authentication mechanism

in file qhttpserverconnection.cpp

string 105

itempHeaderValue.toLower() -> itempHeaderValue

Can't start the QHttpServer outside of main ?

I've been playing with this for too long.
Why can't I start the QHttpServer outside the main? Such as in a class?
I've tried passing in the app variable to the class too and no go.

int main(int argc, char *argv[])
{
  QCoreApplication app(argc, argv);
  MyClass *pClass = new MyClass();
  pClass->startHttpServer(&app);
...
}

What is happening here?

Proxy support

Have you had a chance to use Qhttp with a network proxy, or have any idea what it would take to make it work with one? This looks very interesting.

data() signal also sends HTML data from multipart/form-data

Hi. I use QHTTP to implement an HTTP server supporting POST requests with multipart/form-data MIME. I've noticed that the QHttpRequest::data() signal transmits extra HTML headers plus the posted file itself.

I post a video file like that:

> curl.exe "http://127.0.0.1:5000/video.mp4" -F "file=@H:\video.mp4"
* About to connect() to 127.0.0.1 port 5000 (#0)
*   Trying 127.0.0.1...
* Adding handle: conn: 0x68a8d0
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x68a8d0) send_pipe: 1, recv_pipe: 0
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> POST /video.mp4 HTTP/1.1
> User-Agent: curl/7.32.0
> Host: 127.0.0.1:5000
> Accept: */*
> Content-Length: 129241953
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------39033ffa6ae3f23f
>
* Done waiting for 100-continue
< HTTP/1.1 200 OK
< connection: close
< date: Mon, 09 Jan 2017 20:27:44 GMT
<
* Closing connection 0

In data() signal I write all the incoming data into a file. After that in the file I see

--------------------------39033ffa6ae3f23f
Content-Disposition: form-data; name="file"; filename="video.mp4"
Content-Type: application/octet-stream

binary video data....

qhttp seems to work just fine on Windows

Hello,

FYI, I am using qhttp both on Linux and Windows 7 (32 and 64bits with a MingGW build), and it seems to work just fine on Windows.

Related to

Tested under Linux (Ubuntu 12.04 LTS, 14.04 LTS, g++) and OS X (10.9/10.10, clang) and Windows7 (msvc 2013). Easily portable where ever Qt 5 works. I have no Windows machine (nor time, nor interest), but this lib should work just fine under Windows, although I've not tested it by myself.

QT_VERSION check fails

qhttp does not build out-of-the-box for me on Qt 5.3.2 / G++. The QT version check in qhttpabstracts.cpp seems backwards to me; am I missing something here? I reversed the comparison and got it to compile.

error executing binaries after compiling into xbin

eric@eric-laptop ~/D/G/q/xbin> ls
basic-server*  helloworld*  libqhttp.so@    libqhttp.so.1.0@    nodejs-like*
benchmark*     keep-alive*  libqhttp.so.1@  libqhttp.so.1.0.0*
eric@eric-laptop ~/D/G/q/xbin> ./benchmark 
./benchmark: error while loading shared libraries: libqhttp.so.1: cannot open shared object file: No such file or directory

QHttpServer listening on path NOT working

The server works fine when listening on a port e.g. 1234. But, for a URI such as http://localhost:1234/example, it doesn't work.

Code snippet:

QHttpServer server { qApp };
server.listen ( "http://localhost:1234/example", ... );

Any suggestions?

Howto react on socket disconnection

Hi,
my application is using a pointer to a serverresponse to serve data coming from various sources but when the clients disconnects the object gets deleted causing a segfault.
How can i intercept the object deletion? Is there any signal emitted before the definitive delete?

Thanks

Crash when fooling around after response->end()

Hi, here's a crash I have found: When in a request handler I do stuff after calling end() on the response, e.g. have an event loop run for a second, qhttp crashes on me. I have tried both the master and dev branch.

I think it is because end() calls the done() signal, which closes the socket. Afterwards, it still receives a readyRead(), and then it crashes in QSocket::bytesAvailable(), because itcpSocket is a dangling pointer containing garbage.

I attach a minimal example. Can you reproduce the issue?
TestQhttp.zip

Here is the stack trace:
> TestQhttp.exe!qhttp::details::QSocket::bytesAvailable() Line 100 C++ TestQhttp.exe!qhttp::server::QHttpConnectionPrivate::onReadyRead() Line 81 C++ TestQhttp.exe!qhttp::server::QHttpConnectionPrivate::initTcpSocket::__l3::<lambda>() Line 118 C++ TestQhttp.exe!QtPrivate::FunctorCall<QtPrivate::IndexesList<>,QtPrivate::List<>,void,void <lambda>(void) >::call(qhttp::server::QHttpConnectionPrivate::initTcpSocket::__l3::void <lambda>(void) f, void * * arg) Line 495 C++ TestQhttp.exe!QtPrivate::Functor<void <lambda>(void),0>::call<QtPrivate::List<>,void>(qhttp::server::QHttpConnectionPrivate::initTcpSocket::__l3::void <lambda>(void) & f, void * __formal, void * * arg) Line 553 C++ TestQhttp.exe!QtPrivate::QFunctorSlotObject<void <lambda>(void),0,QtPrivate::List<>,void>::impl(int which, QtPrivate::QSlotObjectBase * this_, QObject * r, void * * a, bool * ret) Line 193 C++ Qt5Cored.dll!QtPrivate::QSlotObjectBase::call(QObject * r, void * * a) Line 124 C++ Qt5Cored.dll!QMetaObject::activate(QObject * sender, int signalOffset, int local_signal_index, void * * argv) Line 3720 C++ Qt5Cored.dll!QMetaObject::activate(QObject * sender, const QMetaObject * m, int local_signal_index, void * * argv) Line 3596 C++ Qt5Cored.dll!QIODevice::readyRead() Line 160 C++ Qt5Networkd.dll!QAbstractSocketPrivate::canReadNotification() Line 737 C++ Qt5Networkd.dll!QAbstractSocketPrivate::readNotification() Line 69 C++ Qt5Networkd.dll!QAbstractSocketEngine::readNotification() Line 153 C++ Qt5Networkd.dll!QReadNotifier::event(QEvent * e) Line 1202 C++ Qt5Cored.dll!QCoreApplicationPrivate::notify_helper(QObject * receiver, QEvent * event) Line 1150 C++ Qt5Cored.dll!doNotify(QObject * receiver, QEvent * event) Line 1090 C++ Qt5Cored.dll!QCoreApplication::notify(QObject * receiver, QEvent * event) Line 1077 C++ Qt5Cored.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1015 C++ Qt5Cored.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 227 C++ Qt5Cored.dll!qt_internal_proc(HWND__ * hwnd, unsigned int message, unsigned __int64 wp, __int64 lp) Line 399 C++ user32.dll!0000000077289c11() Unknown user32.dll!000000007728992a() Unknown Qt5Cored.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 829 C++ Qt5Cored.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 129 C++ Qt5Cored.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 204 C++ Qt5Cored.dll!QCoreApplication::exec() Line 1285 C++ TestQhttp.exe!main(int argc, char * * argv) Line 11 C++ TestQhttp.exe!__tmainCRTStartup() Line 626 C TestQhttp.exe!mainCRTStartup() Line 466 C kernel32.dll!00000000773859bd() Unknown ntdll.dll!00000000774ba2e1() Unknown

QObject: Cannot create children for a parent that is in a different thread.

I've got this error for all the examples. Even for my own code for starting a simple server issued this warning. Couldn't find any issue here.

Release mode is fine but debug mode wouldn't let you run it.
Debugger shows a chain of exceptions generated here.

Assembly by the debugger:

0x77713540                   cc  int3
0x77713541  <+0x0001>        c3  ret
0x77713542  <+0x0002>        90  nop
0x77713543  <+0x0003>        90  nop
0x77713544  <+0x0004>        90  nop
0x77713545  <+0x0005>        90  nop
0x77713546  <+0x0006>        90  nop
0x77713547  <+0x0007>        90  nop

I may be wrong but it's a serious bug. I'd appreciate if you could elaborate on this.

Thanks!

QHTTP modifies POST boundary

Hi. I use a great QHTTP library as a HTTP server implementation. When I receive a POST multipart/form-data request I get its boundary from the "content-type" header. However I noticed, that the HTTP header value is altered and is modified to be in a lower case (HTTP standard violation?). Because of that I cannot find the received boundary in a POSTed data.

Installation on unix systems

It was surprising generated makefiles does not install library/headers into system. Instead it creates some xbin and install there.

Please make proper installation

  1. Executables into /usr/bin by default
  2. Libraries into /usr/lib by default
  3. Headers into /usr/include

Where /usr prefix may be redefined and full path to lib directory may be redefined as well.

So project file should use PREFIX and LIBDIR variables passed to qmake and use some default values is not passed.

"Saved Reply" is not working

Basically for server side events and other notification to the browser I'm using "infinite timeout ajax request s" but unfortunately with qhttp its not working.
I am storing qhttp::server::QHttpResponse * in a suitable data structure but end() function is called on it aka the socket is getting closed the server is not accepting other requests.
Only when a particular QHttpConnection is getting deleted then only the next one is getting created!
But I need to store them and write response data only when I have some notification to send to client.

Socket is not released when HTTP parsing fails

If the incoming HTTP header is invalid, which can be as trivial as providing the HTTP method in lowercase instead of uppercase, the socket is never released and it just hangs the entire connection infinitely.

The reason for this is that there are no checks whether the http_parser_execute function actually succeeded or not.

A quick fix for this is to add a simple check in method onReadyRead in qhttpserverconnection_private.hpp:

void onReadyRead() {
    while ( isocket.bytesAvailable() > 0 ) {
        char buffer[4097] = {0};
        size_t readLength = (size_t) isocket.readRaw(buffer, 4096);

        parse(buffer, readLength);
        if (iparser.http_errno != 0) {
            release(); // release the socket if parsing failed
            return;
        }
    }
}

or even write a hardcoded 400 Bad Request back to the socket, but it probably should be done in a more proper fashion.

Support multiple Set-Cookie headers as described in RFC 6265

Hi,

from RFC-6265 3. Overview:

  1. Overview

[...] An origin server can include multiple
Set-Cookie header fields in a single response. [...]

Origin servers SHOULD NOT fold multiple Set-Cookie header fields into
a single header field. The usual mechanism for folding HTTP headers
fields (i.e., as defined in [RFC2616]) might change the semantics of
the Set-Cookie header field because the %x2C (",") character is used
by Set-Cookie in a way that conflicts with such folding.

It looks like the current THeaderHash implementation cannot cope with multiple Set-Cookie headers at the moment.

Sebastian

Exmaple for onData handler instead of collectData

I am having trouble implementing this example but by using onData() handler instead of collectData():

https://github.com/azadkuh/qhttp/tree/master/example/postcollector

Would you be so kind as to give us some pointers?

In short, my naive approach looks like this:

req->onData([=](QByteArray data) {
		qDebug()<<"DATA RECEIVED: "<<data.size()<<": "<<data;
	});

	req->onEnd([=]() {
		qDebug()<<"DATA ENDED: ";
		res->setStatusCode(qhttp::ESTATUS_OK);

		QByteArray body="<html><body><form method=\"post\" action=\"./\"><input type=\"file\" name=\"file\"><input type=\"submit\" value=\"send\"></form></body></html>";
		res->addHeader("content-type","text/html");
		res->addHeader("connection", "keep-alive");
		res->addHeaderValue("content-length", body.length());
		res->end(body);
	});

When I send data to it, onData() never gets called, or gets called with 12 byte string unrelated to what I actually sent. onEnd() gets called every time.

Thanks!

More flexible project files and options

It would be nice to have *.pri with al the logic inside which could just be included into upper level project to compile and link everything with upper level project.
The same *.pri file could be used by qhttp.pro or src.pro to compile shared library.
So all compilation logic in *.pri file and all project/installation logic in *.pro file.

Then it would be good to have some option to switch static/shared library compilation.

QHttpRequest returns isSuccessful() == true even if the sending part has been interrupted

Hi. I'd like to implement a HTTP server supporting modern POST multipart/form-data requests. I am lucky and QHTTP supports such requests. However if use curl to send a file to my server like that:

curl "http://127.0.0.1:5000/video.mp4" -F "file=@H:\video.mp4" -v

and then immediately Ctrl+C, I'll get an end() signal:

connect(m_request, &qhttp::server::QHttpRequest::end, this, &Connection::end, Qt::QueuedConnection);
....
void Connection::end()
{
    qDebug("Transfer finished successfully: %s", m_request->isSuccessful() ? "yes" : "no");
}

Is there a way to determine that the POST request has been interrupted?

Error on compiling

Hello, i encountered this issue when i was trying to compile qhttp on my machine .

private/httpwriter.hxx:87:55: note: qhttp::details::HttpWriter<TBase, TImpl>::writeHeaders(bool) [with TBase = qhttp::details::HttpResponseBase; TImpl = qhttp::server::QHttpResponsePrivate]::__lambda0
TBase::iheaders.forEach([this](const auto& cit) {
^
private/httpwriter.hxx:87:55: note: candidate expects 0 arguments, 1 provided
make[1]: *** [../tmp/unix/qhttp/qhttpserverresponse.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make[1]: *** [../tmp/unix/qhttp/qhttpserverconnection.o] Error 1
make[1]: Leaving directory `/home/william/Desktop/BUS_BUDDY_DESKTOP/qhttp/src'
make: *** [sub-src-make_first] Error 2

Any help in resolving this issue would be greatly appreciated .

The basic-server example and others are not handling post requests with large data.

It may be due to my lack of knowledge but i think i've found a bug.

When receiving post requests that have around 30kb+ data the server is randomly reading from 20-100% of them before going into onEnd(). The isSuccessful() is also false in onEnd() if it has not read the full packet.

So basicly if you:
Run the keep-alive or basic-server.
Send a post request with a large body
Print out the data server side

Then it randomly prints out 20-100% of the request at onEnd()

SSL support

Have you considered adding support for SSL in the http server?

I'm considering using this for pull information out of a native app, initiated from a website. Websites should always be loaded over SSL and browsers tend to disallow mixed http/https content.

Handle host inaccessability

Hi,

When it tries to connect to the host that is unreachable, the app hangs.

For instance, if there is no web server running on localhost

client.request(qhttp::EHTTP_GET, QUrl("http://localhost"), 
    [](QHttpResponse* res) {
        res->collectData(128);
        res->onEnd([res]() {
            puts(res->collectedData().constData());
            puts("\n\n");
        });
    });

neither request handler or response handler are being called.

How should I handle the case when there is no server running on http://localhost:80 or when localhost is unreachable?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.