Skip to content

Commit f6f29bb

Browse files
committed
http: fix streaming with header buffering
1 parent b38ca0d commit f6f29bb

File tree

2 files changed

+132
-84
lines changed

2 files changed

+132
-84
lines changed

fio-stl.h

Lines changed: 66 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -46919,61 +46919,85 @@ FIO_SFUNC void fio___http_controller_http1_write_body(
4691946919
return;
4692046920

4692146921
stream_chunk:
46922-
if (args.len) { /* print chunk header */
46923-
if (c->state.http.buf.len) {
46924-
fio_io_write2(c->io,
46925-
.buf = (void *)c->state.http.buf.buf,
46926-
.len = c->state.http.buf.len,
46927-
.dealloc = FIO_STRING_FREE);
46928-
fio_string_write2(&c->state.http.buf,
46929-
FIO_STRING_REALLOC,
46930-
FIO_STRING_WRITE_HEX(args.len),
46931-
FIO_STRING_WRITE_STR2("\r\n", 2));
46922+
if (args.len && args.buf) { /* String */
46923+
if (args.copy || args.len < (1 << 16)) {
46924+
fio_string_write2(
46925+
&c->state.http.buf,
46926+
FIO_STRING_REALLOC,
46927+
FIO_STRING_WRITE_HEX(args.len), /* chunk header - length */
46928+
FIO_STRING_WRITE_STR2("\r\n", 2), /* chunk header - EOL */
46929+
FIO_STRING_WRITE_STR2((char *)args.buf, args.buf ? args.len : 0),
46930+
FIO_STRING_WRITE_STR2("\r\n", 2)); /* chunk trailer - EOL */
4693246931
fio_io_write2(c->io,
4693346932
.buf = (void *)c->state.http.buf.buf,
4693446933
.len = c->state.http.buf.len,
4693546934
.dealloc = FIO_STRING_FREE);
4693646935
c->state.http.buf = FIO_STR_INFO0;
46937-
} else {
46938-
char buf[24];
46939-
fio_str_info_s i = FIO_STR_INFO3(buf, 0, 24);
46940-
fio_string_write_hex(&i, NULL, args.len);
46941-
fio_string_write(&i, NULL, "\r\n", 2);
46942-
fio_io_write2(c->io, .buf = (void *)i.buf, .len = i.len, .copy = 1);
46943-
}
46944-
} else {
46945-
if (c->state.http.buf.len) {
46946-
fio_io_write2(c->io,
46947-
.buf = (void *)c->state.http.buf.buf,
46948-
.len = c->state.http.buf.len,
46949-
.dealloc = FIO_STRING_FREE);
46936+
if (args.dealloc)
46937+
args.dealloc((void *)args.buf);
46938+
return;
46939+
} else { /* avoid copying the incoming data if possible */
46940+
FIO_STR_INFO_TMP_VAR(buf, 32);
46941+
if (c->state.http.buf.buf)
46942+
buf = c->state.http.buf;
4695046943
c->state.http.buf = FIO_STR_INFO0;
46944+
fio_string_write2(
46945+
&buf,
46946+
NULL,
46947+
FIO_STRING_WRITE_HEX(args.len), /* chunk header - length */
46948+
FIO_STRING_WRITE_STR2("\r\n", 2)); /* chunk header - EOL */
46949+
fio_io_write2(c->io,
46950+
.buf = buf.buf,
46951+
.len = buf.len,
46952+
.copy = !FIO_STR_INFO_TMP_IS_REALLOCATED(buf),
46953+
.dealloc = FIO_STR_INFO_TMP_IS_REALLOCATED(buf)
46954+
? FIO_STRING_FREE
46955+
: NULL);
46956+
fio_io_write2(c->io,
46957+
.buf = (void *)args.buf,
46958+
.len = args.len,
46959+
.dealloc = args.dealloc);
46960+
/* chunk trailer - EOL */
46961+
fio_io_write2(c->io, .buf = (void *)"\r\n", .len = 2);
46962+
return;
4695146963
}
46952-
if (args.buf || (uint32_t)(args.fd + 1) > 0U)
46953-
FIO_LOG_ERROR("HTTP1 streaming requires a correctly pre-determined "
46954-
"length per chunk.");
46955-
else
46956-
goto no_write_err;
46957-
}
46958-
fio_io_write2(c->io,
46959-
.buf = (void *)args.buf,
46960-
.fd = args.fd,
46961-
.len = args.len,
46962-
.offset = args.offset,
46963-
.dealloc = args.dealloc,
46964-
.copy = (uint8_t)args.copy);
46965-
/* print chunk trailer */
46966-
{
46967-
fio_buf_info_s trailer = FIO_BUF_INFO2((char *)"\r\n", 2);
46968-
fio_io_write2(c->io, .buf = trailer.buf, .len = trailer.len, .copy = 1);
46964+
} else if ((uint32_t)(args.fd + 1) > 1U) { /* File? */
46965+
if (!args.len) { /* TODO: collect remaining file length */
46966+
goto no_length_err;
46967+
}
46968+
FIO_STR_INFO_TMP_VAR(buf, 32);
46969+
if (c->state.http.buf.buf)
46970+
buf = c->state.http.buf;
46971+
c->state.http.buf = FIO_STR_INFO0;
46972+
fio_string_write2(
46973+
&buf,
46974+
NULL,
46975+
FIO_STRING_WRITE_HEX(args.len), /* chunk header - length */
46976+
FIO_STRING_WRITE_STR2("\r\n", 2)); /* chunk header - EOL */
46977+
fio_io_write2(c->io,
46978+
.buf = buf.buf,
46979+
.len = buf.len,
46980+
.copy = !FIO_STR_INFO_TMP_IS_REALLOCATED(buf),
46981+
.dealloc = FIO_STR_INFO_TMP_IS_REALLOCATED(buf)
46982+
? FIO_STRING_FREE
46983+
: NULL);
46984+
fio_io_write2(c->io,
46985+
.fd = args.fd,
46986+
.len = args.len,
46987+
.copy = (bool)args.copy,
46988+
.dealloc = args.dealloc);
46989+
/* chunk trailer - EOL */
46990+
fio_io_write2(c->io, .buf = (void *)"\r\n", .len = 2);
4696946991
}
4697046992
return;
46971-
46993+
no_length_err:
46994+
FIO_LOG_ERROR("HTTP1 streaming requires a correctly pre-determined "
46995+
"length per chunk.");
4697246996
no_write_err:
4697346997
if (args.buf) {
4697446998
if (args.dealloc)
4697546999
args.dealloc((void *)args.buf);
46976-
} else if (args.fd != -1) {
47000+
} else if ((uint32_t)(args.fd + 1) > 1U) {
4697747001
close(args.fd);
4697847002
}
4697947003
}

fio-stl/439 http.h

Lines changed: 66 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,61 +1457,85 @@ FIO_SFUNC void fio___http_controller_http1_write_body(
14571457
return;
14581458

14591459
stream_chunk:
1460-
if (args.len) { /* print chunk header */
1461-
if (c->state.http.buf.len) {
1462-
fio_io_write2(c->io,
1463-
.buf = (void *)c->state.http.buf.buf,
1464-
.len = c->state.http.buf.len,
1465-
.dealloc = FIO_STRING_FREE);
1466-
fio_string_write2(&c->state.http.buf,
1467-
FIO_STRING_REALLOC,
1468-
FIO_STRING_WRITE_HEX(args.len),
1469-
FIO_STRING_WRITE_STR2("\r\n", 2));
1460+
if (args.len && args.buf) { /* String */
1461+
if (args.copy || args.len < (1 << 16)) {
1462+
fio_string_write2(
1463+
&c->state.http.buf,
1464+
FIO_STRING_REALLOC,
1465+
FIO_STRING_WRITE_HEX(args.len), /* chunk header - length */
1466+
FIO_STRING_WRITE_STR2("\r\n", 2), /* chunk header - EOL */
1467+
FIO_STRING_WRITE_STR2((char *)args.buf, args.buf ? args.len : 0),
1468+
FIO_STRING_WRITE_STR2("\r\n", 2)); /* chunk trailer - EOL */
14701469
fio_io_write2(c->io,
14711470
.buf = (void *)c->state.http.buf.buf,
14721471
.len = c->state.http.buf.len,
14731472
.dealloc = FIO_STRING_FREE);
14741473
c->state.http.buf = FIO_STR_INFO0;
1475-
} else {
1476-
char buf[24];
1477-
fio_str_info_s i = FIO_STR_INFO3(buf, 0, 24);
1478-
fio_string_write_hex(&i, NULL, args.len);
1479-
fio_string_write(&i, NULL, "\r\n", 2);
1480-
fio_io_write2(c->io, .buf = (void *)i.buf, .len = i.len, .copy = 1);
1481-
}
1482-
} else {
1483-
if (c->state.http.buf.len) {
1484-
fio_io_write2(c->io,
1485-
.buf = (void *)c->state.http.buf.buf,
1486-
.len = c->state.http.buf.len,
1487-
.dealloc = FIO_STRING_FREE);
1474+
if (args.dealloc)
1475+
args.dealloc((void *)args.buf);
1476+
return;
1477+
} else { /* avoid copying the incoming data if possible */
1478+
FIO_STR_INFO_TMP_VAR(buf, 32);
1479+
if (c->state.http.buf.buf)
1480+
buf = c->state.http.buf;
14881481
c->state.http.buf = FIO_STR_INFO0;
1482+
fio_string_write2(
1483+
&buf,
1484+
NULL,
1485+
FIO_STRING_WRITE_HEX(args.len), /* chunk header - length */
1486+
FIO_STRING_WRITE_STR2("\r\n", 2)); /* chunk header - EOL */
1487+
fio_io_write2(c->io,
1488+
.buf = buf.buf,
1489+
.len = buf.len,
1490+
.copy = !FIO_STR_INFO_TMP_IS_REALLOCATED(buf),
1491+
.dealloc = FIO_STR_INFO_TMP_IS_REALLOCATED(buf)
1492+
? FIO_STRING_FREE
1493+
: NULL);
1494+
fio_io_write2(c->io,
1495+
.buf = (void *)args.buf,
1496+
.len = args.len,
1497+
.dealloc = args.dealloc);
1498+
/* chunk trailer - EOL */
1499+
fio_io_write2(c->io, .buf = (void *)"\r\n", .len = 2);
1500+
return;
14891501
}
1490-
if (args.buf || (uint32_t)(args.fd + 1) > 0U)
1491-
FIO_LOG_ERROR("HTTP1 streaming requires a correctly pre-determined "
1492-
"length per chunk.");
1493-
else
1494-
goto no_write_err;
1495-
}
1496-
fio_io_write2(c->io,
1497-
.buf = (void *)args.buf,
1498-
.fd = args.fd,
1499-
.len = args.len,
1500-
.offset = args.offset,
1501-
.dealloc = args.dealloc,
1502-
.copy = (uint8_t)args.copy);
1503-
/* print chunk trailer */
1504-
{
1505-
fio_buf_info_s trailer = FIO_BUF_INFO2((char *)"\r\n", 2);
1506-
fio_io_write2(c->io, .buf = trailer.buf, .len = trailer.len, .copy = 1);
1502+
} else if ((uint32_t)(args.fd + 1) > 1U) { /* File? */
1503+
if (!args.len) { /* TODO: collect remaining file length */
1504+
goto no_length_err;
1505+
}
1506+
FIO_STR_INFO_TMP_VAR(buf, 32);
1507+
if (c->state.http.buf.buf)
1508+
buf = c->state.http.buf;
1509+
c->state.http.buf = FIO_STR_INFO0;
1510+
fio_string_write2(
1511+
&buf,
1512+
NULL,
1513+
FIO_STRING_WRITE_HEX(args.len), /* chunk header - length */
1514+
FIO_STRING_WRITE_STR2("\r\n", 2)); /* chunk header - EOL */
1515+
fio_io_write2(c->io,
1516+
.buf = buf.buf,
1517+
.len = buf.len,
1518+
.copy = !FIO_STR_INFO_TMP_IS_REALLOCATED(buf),
1519+
.dealloc = FIO_STR_INFO_TMP_IS_REALLOCATED(buf)
1520+
? FIO_STRING_FREE
1521+
: NULL);
1522+
fio_io_write2(c->io,
1523+
.fd = args.fd,
1524+
.len = args.len,
1525+
.copy = (bool)args.copy,
1526+
.dealloc = args.dealloc);
1527+
/* chunk trailer - EOL */
1528+
fio_io_write2(c->io, .buf = (void *)"\r\n", .len = 2);
15071529
}
15081530
return;
1509-
1531+
no_length_err:
1532+
FIO_LOG_ERROR("HTTP1 streaming requires a correctly pre-determined "
1533+
"length per chunk.");
15101534
no_write_err:
15111535
if (args.buf) {
15121536
if (args.dealloc)
15131537
args.dealloc((void *)args.buf);
1514-
} else if (args.fd != -1) {
1538+
} else if ((uint32_t)(args.fd + 1) > 1U) {
15151539
close(args.fd);
15161540
}
15171541
}

0 commit comments

Comments
 (0)