diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2017-03-02 11:53:16 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2017-03-10 20:00:11 +0300 |
commit | 9174eb844bb2a6a23e4fd18c78c5b9ca84a0072c (patch) | |
tree | bab816ed9a3f811792272b513e1e7f877c192982 | |
parent | 26b63fcb861aaab53c5a16fe43e8830ab3a61a19 (diff) | |
download | libmicrohttpd-9174eb844bb2a6a23e4fd18c78c5b9ca84a0072c.tar.gz libmicrohttpd-9174eb844bb2a6a23e4fd18c78c5b9ca84a0072c.zip |
process_urh(): process all recv() before all send() to overcome limitations on some platforms
-rw-r--r-- | src/microhttpd/daemon.c | 140 |
1 files changed, 79 insertions, 61 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 0049b562..f25ccd4d 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -1201,7 +1201,16 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1201 | connection->tls_read_ready = false; | 1201 | connection->tls_read_ready = false; |
1202 | } | 1202 | } |
1203 | 1203 | ||
1204 | /* handle reading from TLS client and writing to application */ | 1204 | /* Some platforms (W32, possibly Darwin) may discard data in system buffers |
1205 | * received by system but unread by recv() if remote side was disconnected | ||
1206 | * and failed send() attempted (send() will always fail after remote disconnect | ||
1207 | * was detected). | ||
1208 | * So, before trying send() on any socket, recv() must be performed at first | ||
1209 | * otherwise last part of incoming data may be lost. */ | ||
1210 | |||
1211 | /* | ||
1212 | * handle reading from remote TLS client | ||
1213 | */ | ||
1205 | if ( ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) || | 1214 | if ( ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) || |
1206 | (connection->tls_read_ready) ) && | 1215 | (connection->tls_read_ready) ) && |
1207 | (urh->in_buffer_used < urh->in_buffer_size) ) | 1216 | (urh->in_buffer_used < urh->in_buffer_size) ) |
@@ -1236,67 +1245,10 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1236 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | 1245 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; |
1237 | } | 1246 | } |
1238 | } | 1247 | } |
1239 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | ||
1240 | (urh->in_buffer_used > 0) ) | ||
1241 | { | ||
1242 | ssize_t res; | ||
1243 | size_t data_size; | ||
1244 | |||
1245 | data_size = urh->in_buffer_used; | ||
1246 | if (data_size > MHD_SCKT_SEND_MAX_SIZE_) | ||
1247 | data_size = MHD_SCKT_SEND_MAX_SIZE_; | ||
1248 | |||
1249 | res = MHD_send_ (urh->mhd.socket, | ||
1250 | urh->in_buffer, | ||
1251 | data_size); | ||
1252 | if (0 > res) | ||
1253 | { | ||
1254 | int err = MHD_socket_get_error_ (); | ||
1255 | |||
1256 | if (MHD_SCKT_ERR_IS_EAGAIN_ (err)) | ||
1257 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
1258 | else if ( (! MHD_SCKT_ERR_IS_EINTR_ (err)) && | ||
1259 | (! MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)) ) | ||
1260 | { | ||
1261 | /* persistent / unrecoverable error, treat as | ||
1262 | if connection was shut down. */ | ||
1263 | #ifdef HAVE_MESSAGES | ||
1264 | MHD_DLOG (daemon, | ||
1265 | _("Failed to forward to application " MHD_UNSIGNED_LONG_LONG_PRINTF \ | ||
1266 | " bytes of data received from remote side: %s\n"), | ||
1267 | (MHD_UNSIGNED_LONG_LONG) urh->in_buffer_used, | ||
1268 | MHD_socket_strerr_ (err)); | ||
1269 | #endif | ||
1270 | /* Discard any data received form remote. */ | ||
1271 | urh->in_buffer_used = 0; | ||
1272 | /* Do not try to push data to application. */ | ||
1273 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
1274 | /* Reading from remote client is not required anymore. */ | ||
1275 | urh->in_buffer_size = 0; | ||
1276 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1277 | connection->tls_read_ready = false; | ||
1278 | } | ||
1279 | } | ||
1280 | else | ||
1281 | { | ||
1282 | if (urh->in_buffer_used != res) | ||
1283 | { | ||
1284 | memmove (urh->in_buffer, | ||
1285 | &urh->in_buffer[res], | ||
1286 | urh->in_buffer_used - res); | ||
1287 | urh->in_buffer_used -= res; | ||
1288 | if (data_size > (size_t)res) | ||
1289 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
1290 | } | ||
1291 | else | ||
1292 | { | ||
1293 | urh->in_buffer_used = 0; | ||
1294 | } | ||
1295 | } | ||
1296 | } | ||
1297 | |||
1298 | /* handle reading from application and writing to HTTPS client */ | ||
1299 | 1248 | ||
1249 | /* | ||
1250 | * handle reading from application | ||
1251 | */ | ||
1300 | /* If application signaled MHD about socket closure then | 1252 | /* If application signaled MHD about socket closure then |
1301 | * check for any pending data even if socket is not marked | 1253 | * check for any pending data even if socket is not marked |
1302 | * as 'ready' (signal may arrive after poll()/select()). | 1254 | * as 'ready' (signal may arrive after poll()/select()). |
@@ -1356,6 +1308,10 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1356 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | 1308 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; |
1357 | } | 1309 | } |
1358 | } | 1310 | } |
1311 | |||
1312 | /* | ||
1313 | * handle writing to remote HTTPS client | ||
1314 | */ | ||
1359 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && | 1315 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && |
1360 | (urh->out_buffer_used > 0) ) | 1316 | (urh->out_buffer_used > 0) ) |
1361 | { | 1317 | { |
@@ -1410,6 +1366,68 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
1410 | } | 1366 | } |
1411 | } | 1367 | } |
1412 | 1368 | ||
1369 | /* | ||
1370 | * handle writing to application | ||
1371 | */ | ||
1372 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | ||
1373 | (urh->in_buffer_used > 0) ) | ||
1374 | { | ||
1375 | ssize_t res; | ||
1376 | size_t data_size; | ||
1377 | |||
1378 | data_size = urh->in_buffer_used; | ||
1379 | if (data_size > MHD_SCKT_SEND_MAX_SIZE_) | ||
1380 | data_size = MHD_SCKT_SEND_MAX_SIZE_; | ||
1381 | |||
1382 | res = MHD_send_ (urh->mhd.socket, | ||
1383 | urh->in_buffer, | ||
1384 | data_size); | ||
1385 | if (0 > res) | ||
1386 | { | ||
1387 | int err = MHD_socket_get_error_ (); | ||
1388 | |||
1389 | if (MHD_SCKT_ERR_IS_EAGAIN_ (err)) | ||
1390 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
1391 | else if ( (! MHD_SCKT_ERR_IS_EINTR_ (err)) && | ||
1392 | (! MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)) ) | ||
1393 | { | ||
1394 | /* persistent / unrecoverable error, treat as | ||
1395 | if connection was shut down. */ | ||
1396 | #ifdef HAVE_MESSAGES | ||
1397 | MHD_DLOG (daemon, | ||
1398 | _("Failed to forward to application " MHD_UNSIGNED_LONG_LONG_PRINTF \ | ||
1399 | " bytes of data received from remote side: %s\n"), | ||
1400 | (MHD_UNSIGNED_LONG_LONG) urh->in_buffer_used, | ||
1401 | MHD_socket_strerr_ (err)); | ||
1402 | #endif | ||
1403 | /* Discard any data received form remote. */ | ||
1404 | urh->in_buffer_used = 0; | ||
1405 | /* Do not try to push data to application. */ | ||
1406 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
1407 | /* Reading from remote client is not required anymore. */ | ||
1408 | urh->in_buffer_size = 0; | ||
1409 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
1410 | connection->tls_read_ready = false; | ||
1411 | } | ||
1412 | } | ||
1413 | else | ||
1414 | { | ||
1415 | if (urh->in_buffer_used != res) | ||
1416 | { | ||
1417 | memmove (urh->in_buffer, | ||
1418 | &urh->in_buffer[res], | ||
1419 | urh->in_buffer_used - res); | ||
1420 | urh->in_buffer_used -= res; | ||
1421 | if (data_size > (size_t)res) | ||
1422 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
1423 | } | ||
1424 | else | ||
1425 | { | ||
1426 | urh->in_buffer_used = 0; | ||
1427 | } | ||
1428 | } | ||
1429 | } | ||
1430 | |||
1413 | /* Check whether data is present in TLS buffers | 1431 | /* Check whether data is present in TLS buffers |
1414 | * and incoming forward buffer have some space. */ | 1432 | * and incoming forward buffer have some space. */ |
1415 | if ( (connection->tls_read_ready) && | 1433 | if ( (connection->tls_read_ready) && |