Go to file
Giuseppe D'Angelo 7a5e0c5712 QNAM: try to send headers and body together
For HTTP connections, QNAM defaults to opening its TCP socket in
unbuffered mode. This means that Qt will send the data written
into the socket right to the kernel, queueing only if the kernel
says it doesn't want more data for the moment being.

QNAM itself then uses separate write() calls to write the HTTP
headers and the body of the request (like POST or PUT). These 2+
writes result in headers and body being sent over different TCP
segments -- even if, in principle, a POST with a few bytes of data
(e.g. a HTML form, or a REST or SOAP request) could fit in the same
segment as the request.

Multiple writes like this interact extremely poorly with other
TCP features, e.g. delayed ACKs, Nagle's algorithm and the like.
In a typical scenario, the kernel will send a segment containing just
the headers, wait for the ACK (which may be delayed), and only then
send the body (it wasn't sent before because Nagle was blocking it).
The reply at this point is immediate (because the server can process
the request and starts replying), but the delayed ACK is typically
40-50ms, and documented up to 500ms (!). If one uses QNAM to access a
service, this introduces unacceptable latency.

These multiple writes to the OS should be avoided.

The first thing that comes into mind is to use buffered sockets.
Now, there are good reasons to keep the socket unbuffered, so we
don't want to change that. But the deal breaker is that even buffered
sockets won't help in general: for instance, on Windows, a buffered
write will immediately detect that the socket is ready for write and
flush the buffer right away (not 100% sure of why this is necessary;
basically, after populating the QTcpSocket write buffer, Qt enables
a write socket notifier on the socket -- notifier that fires
synchronously and immediately, without even returning to the event
loop, and that causes the write buffer flush).

Linux of course offers the perfect solution: corking the socket via
TCP_CORK, which tells the kernel not to send the data right away but
to buffer it up to a timeout (or when the option gets disabled
again, whichever comes first). It's explicitly designed to support
the case of sending headers followed by something like a
sendfile(2). Setting this socket option moves the problem to
the kernel and we could happily keep issuing multiple writes.

Ça va sans dire, no other OS supports that option or any other
similar option.

We have therefore to deal with this in userspace: don't write in the
socket multiple times, but try and coalesce the write of the headers
with the writing of the data. This patch implements that, by storing
the headers and sending them together with the very first chunk of
data. If the data is small enough, this sends the entire request
in one TCP segment.

Interestingly enough, QNAM has a call setting TCP_NODELAY
currently commented out because Qt doesn't combine "HTTP requests"
(whatever that means). The call comes all the way back
from pre-public history (before 2011) (!). This patch doesn't
touch it.

Fixes: QTBUG-41907
Change-Id: Id555d14e0702c9f75c3134b18277692eb3659afe
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2020-09-18 23:19:41 +02:00
.github/workflows GitHub Actions: Fix workflow file 2020-09-11 13:37:48 +02:00
bin CMake: Fix running qt-configure-module.bat without arguments 2020-09-11 17:11:02 +02:00
cmake CMake: Fix FindWrapRt 2020-09-18 20:25:58 +02:00
coin CMake: Use CMAKE_AUTOGEN_VERBOSE to see moc invocations 2020-07-24 17:33:17 +02:00
config.tests CMake: Skip regeneration of manual compile test project 2020-04-09 11:26:46 +02:00
dist Remove last remainings of Qt Quick 1 imports 2020-05-25 11:48:12 +02:00
doc Doc: Remove unused porting guide document 2020-09-16 18:32:05 +02:00
examples Deprecate implicit QPixmap conversion to QBitmap 2020-09-17 13:26:50 +02:00
lib Purge all fonts 2015-08-18 19:59:14 +00:00
mkspecs Android: bump default javac build versions to 8 2020-09-16 20:55:10 +03:00
qmake qmake: Support multiple /MERGE:from=to options in MSVC generator 2020-09-18 18:48:58 +00:00
src QNAM: try to send headers and body together 2020-09-18 23:19:41 +02:00
tests Say hello to PixelGadget 2020-09-18 16:07:20 +02:00
util CMake: build add flags for building QtAndroid.jar 2020-09-16 20:55:16 +03:00
.cmake.conf pro2cmake.py: Generate .cmake.conf files for versioning 2020-04-30 17:44:03 +00:00
.gitattributes Update the git-archive export options 2012-09-07 15:39:31 +02:00
.gitignore Remove the QPF2 font engine 2020-08-24 07:08:45 +02:00
.lgtm.yml Skip LGTM analysis for the bootstrap library and tools 2020-07-16 01:04:34 +02:00
.prev_qt_cmdline.cmake Remove the -no-compile-examples configure switch 2020-09-11 00:40:46 +02:00
.qmake.conf Bump version 2020-02-02 13:41:14 +01:00
.tag Update the git-archive export options 2012-09-07 15:39:31 +02:00
CMakeLists.txt CMake: Fix tst_moc to build when tests are built as part of Qt tree 2020-08-23 11:04:20 +02:00
config_help.txt Android: bump default javac build versions to 8 2020-09-16 20:55:10 +03:00
configure CMake: Fix configure -redo on Unix 2020-08-20 17:07:09 +02:00
configure.bat CMake: Fix top-level configure 2020-07-16 15:00:37 +02:00
configure.cmake CMake: Regenerate configure.cmake files 2020-09-15 15:55:47 +02:00
configure.json Android: allow setting javac build version from the configure script 2020-09-16 20:55:08 +03:00
configure.pri Android: allow setting javac build version from the configure script 2020-09-16 20:55:08 +03:00
dependencies.yaml Re-add dependencies.yaml so repos outside qt5 can be built with Coin 2019-09-19 17:07:36 +00:00
header.BSD Use placeholder for year in header.* files 2018-04-16 11:02:22 +00:00
header.COMM Use placeholder for year in header.* files 2018-04-16 11:02:22 +00:00
header.FDL Use placeholder for year in header.* files 2018-04-16 11:02:22 +00:00
header.GPL Use placeholder for year in header.* files 2018-04-16 11:02:22 +00:00
header.GPL-EXCEPT Use placeholder for year in header.* files 2018-04-16 11:02:22 +00:00
header.LGPL Use placeholder for year in header.* files 2018-04-16 11:02:22 +00:00
header.LGPL3 Use placeholder for year in header.* files 2018-04-16 11:02:22 +00:00
header.LGPL3-COMM Use placeholder for year in header.* files 2018-04-16 11:02:22 +00:00
header.LGPL-NOGPL2 Use placeholder for year in header.* files 2018-04-16 11:02:22 +00:00
header.LGPL-ONLY Use placeholder for year in header.* files 2018-04-16 11:02:22 +00:00
header.MIT qsimd: add support for new x86 CPU features 2018-05-05 06:20:07 +00:00
INSTALL INSTALL: Remove outdated reference to Windows CE 2019-02-13 13:01:57 +00:00
LICENSE.FDL Initial import from the monolithic Qt. 2011-04-27 12:05:43 +02:00
LICENSE.GPL2 Add new license header templates and license files 2016-01-14 20:43:46 +00:00
LICENSE.GPL3 Add new license header templates and license files 2016-01-14 20:43:46 +00:00
LICENSE.GPL3-EXCEPT Add new license header templates and license files 2016-01-14 20:43:46 +00:00
LICENSE.LGPL3 Add new license header templates and license files 2016-01-14 20:43:46 +00:00
LICENSE.LGPLv3 Remove LICENSE.GPLv3, LICENSE.LGPLv21, LGPL_EXCEPTION.txt 2018-04-16 11:02:14 +00:00
LICENSE.QT-LICENSE-AGREEMENT Update enterprise license agreement v4.2.1 2019-12-18 13:07:19 +02:00
qt_cmdline.cmake CMake: build add flags for building QtAndroid.jar 2020-09-16 20:55:16 +03:00
qtbase.pro Update qmake before building src 2020-08-19 18:25:51 +02:00
sync.profile Remove last remaining bits of QtPlatformHeaders 2020-08-04 07:12:32 +02:00