From ec5c5aec6d5373e47936891c6b8111716d16f3e6 Mon Sep 17 00:00:00 2001
From: Nick Mathewson <nickm@torproject.org>
Date: Tue, 23 Nov 2010 20:31:28 -0500
Subject: [PATCH] Handle evhttp PUT/POST requests with an empty body

When we call evhttp_get_bodylen() [when transfer-encoding isn't set],
having req->ntoread == -1 means that we have no content-length.  But a
request with no content-length has no body!  We were treating the
absent content-length as meaning "read till closed", which only holds
for replies, not requests.

This patch also allows PATCH requests to have a body.
---
 http.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/http.c b/http.c
index b08e04c5..4464bbeb 100644
--- a/http.c
+++ b/http.c
@@ -1734,6 +1734,28 @@ evhttp_get_body_length(struct evhttp_request *req)
 	return (0);
 }
 
+static int
+evhttp_method_may_have_body(enum evhttp_cmd_type type)
+{
+	switch (type) {
+	case EVHTTP_REQ_POST:
+	case EVHTTP_REQ_PUT:
+	case EVHTTP_REQ_PATCH:
+		return 1;
+	case EVHTTP_REQ_TRACE:
+		return 0;
+	/* XXX May any of the below methods have a body? */
+	case EVHTTP_REQ_GET:
+	case EVHTTP_REQ_HEAD:
+	case EVHTTP_REQ_DELETE:
+	case EVHTTP_REQ_OPTIONS:
+	case EVHTTP_REQ_CONNECT:
+		return 0;
+	default:
+		return 0;
+	}
+}
+
 static void
 evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
 {
@@ -1741,7 +1763,7 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
 
 	/* If this is a request without a body, then we are done */
 	if (req->kind == EVHTTP_REQUEST &&
-	    (req->type != EVHTTP_REQ_POST && req->type != EVHTTP_REQ_PUT)) {
+	    !evhttp_method_may_have_body(req->type)) {
 		evhttp_connection_done(evcon);
 		return;
 	}
@@ -1756,6 +1778,12 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
 			    EVCON_HTTP_INVALID_HEADER);
 			return;
 		}
+		if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
+			/* An incoming request with no content-length and no
+			 * transfer-encoding has no body. */
+			evhttp_connection_done(evcon);
+			return;
+		}
 	}
 	evhttp_read_body(evcon, req);
 	/* note the request may have been freed in evhttp_read_body */
-- 
2.40.0