@@ -526,10 +526,13 @@ struct rpc_state {
unsigned write_line_lengths : 1;
/*
- * rpc_out uses this to keep track of whether it should continue
- * reading to populate the current request. Initialize to 0.
+ * Used by rpc_out; initialize to 0. This is true if a flush has been
+ * read, but the corresponding line length (if write_line_lengths is
+ * true) and EOF have not been sent to libcurl. Since each flush marks
+ * the end of a request, each flush must be completely sent before any
+ * further reading occurs.
*/
- unsigned stop_reading : 1;
+ unsigned flush_read_but_not_sent : 1;
};
/*
@@ -600,26 +603,34 @@ static size_t rpc_out(void *ptr, size_t eltsize,
rpc->initial_buffer = 0;
rpc->len = 0;
rpc->pos = 0;
- if (!rpc->stop_reading) {
+ if (!rpc->flush_read_but_not_sent) {
if (!rpc_read_from_out(rpc, 0, &avail, &status))
BUG("The entire rpc->buf should be larger than LARGE_PACKET_MAX");
if (status == PACKET_READ_FLUSH)
- /*
- * We are done reading for this request, but we
- * still need to send this line out (if
- * rpc->write_line_lengths is true) so do not
- * return yet.
- */
- rpc->stop_reading = 1;
+ rpc->flush_read_but_not_sent = 1;
}
+ /*
+ * If flush_read_but_not_sent is true, we have already read one
+ * full request but have not fully sent it + EOF, which is why
+ * we need to refrain from reading.
+ */
}
- if (!avail && rpc->stop_reading) {
+ if (rpc->flush_read_but_not_sent) {
+ if (!avail) {
+ /*
+ * The line length either does not need to be sent at
+ * all or has already been completely sent. Now we can
+ * return 0, indicating EOF, meaning that the flush has
+ * been fully sent.
+ */
+ rpc->flush_read_but_not_sent = 0;
+ return 0;
+ }
/*
- * "return 0" will notify Curl that this RPC request is done,
- * so reset stop_reading back to 0 for the next request.
+ * If avail is non-zerp, the line length for the flush still
+ * hasn't been fully sent. Proceed with sending the line
+ * length.
*/
- rpc->stop_reading = 0;
- return 0;
}
if (max < avail)
@@ -1290,7 +1301,7 @@ static int stateless_connect(const char *service_name)
rpc.gzip_request = 1;
rpc.initial_buffer = 0;
rpc.write_line_lengths = 1;
- rpc.stop_reading = 0;
+ rpc.flush_read_but_not_sent = 0;
/*
* Dump the capability listing that we got from the server earlier
@@ -552,10 +552,17 @@ test_expect_success 'clone big repository with http:// using protocol v2' '
git init "$HTTPD_DOCUMENT_ROOT_PATH/big" &&
# Ensure that the list of wants is greater than http.postbuffer below
- for i in $(seq 1 1500)
+ for i in $(test_seq 1 1500)
do
- test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/big" "commit$i"
- done &&
+ # do not use here-doc, because it requires a process
+ # per loop iteration
+ echo "commit refs/heads/too-many-refs-$i" &&
+ echo "committer git <git@example.com> $i +0000" &&
+ echo "data 0" &&
+ echo "M 644 inline bla.txt" &&
+ echo "data 4" &&
+ echo "bla"
+ done | git -C "$HTTPD_DOCUMENT_ROOT_PATH/big" fast-import &&
GIT_TRACE_PACKET="$(pwd)/log" GIT_TRACE_CURL="$(pwd)/log" git \
-c protocol.version=2 -c http.postbuffer=65536 \