From 07271dbd7c8f28a6aace48787040580973eb5a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Wed, 15 Mar 2017 15:15:08 +0100 Subject: [PATCH 88/90] secrets: always add Content-Length header If custodia server does not reply with Content-Length header, curl may wait for non-existing body of http reply if such body does not exist (for example during POST operation when creating a container). Reviewed-by: Simo Sorce Reviewed-by: Jakub Hrozek (cherry picked from commit 13d720de13e490850c1139eea865bcd5195a2630) --- src/responder/secrets/providers.c | 72 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c index 80a443d91135447ec8ce8d424b692a6d7e26a907..a27fb720b394e7c76d1b65f656146bcd00755449 100644 --- a/src/responder/secrets/providers.c +++ b/src/responder/secrets/providers.c @@ -388,20 +388,84 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, return EOK; } +static errno_t +sec_http_iobuf_split(struct sss_iobuf *response, + const char **headers, + const char **body) +{ + const char *data = (const char *)sss_iobuf_get_data(response); + char *delim; + + /* The last header ends with \r\n and then comes \r\n again as a separator + * of body from headers. We can use this to find this point. */ + delim = strstr(data, "\r\n\r\n"); + if (delim == NULL) { + return EINVAL; + } + + /* Skip to the body delimiter. */ + delim = delim + sizeof("\r\n") - 1; + + /* Replace \r\n with zeros turning data into: + * from HEADER\r\nBODY into HEADER\0\0BODY format. */ + delim[0] = '\0'; + delim[1] = '\0'; + + /* Split the buffer. */ + *headers = data; + *body = delim + 2; + + return 0; +} + +static const char * +sec_http_iobuf_add_content_length(TALLOC_CTX *mem_ctx, + const char *headers, + size_t body_len) +{ + /* If Content-Length is already present we do nothing. */ + if (strstr(headers, "Content-Length:") != NULL) { + return headers; + } + + return talloc_asprintf(mem_ctx, "%sContent-Length: %zu\r\n", + headers, body_len); +} + errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx, struct sec_data *reply, int response_code, struct sss_iobuf *response) { + const char *headers; + const char *body; + size_t body_len; + errno_t ret; + DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d\n", response_code); - reply->data = (char *)sss_iobuf_get_data(response); - reply->length = sss_iobuf_get_len(response); + ret = sec_http_iobuf_split(response, &headers, &body); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Unexpected HTTP reply, returning what we got from server\n"); + reply->data = (char *)sss_iobuf_get_data(response); + reply->length = sss_iobuf_get_len(response); - talloc_steal(mem_ctx, reply->data); + return EOK; + } + /* Add Content-Length header if not present so client does not await + * not-existing incoming data. */ + body_len = strlen(body); + headers = sec_http_iobuf_add_content_length(mem_ctx, headers, body_len); + if (headers == NULL) { + return ENOMEM; + } + + reply->length = strlen(headers) + sizeof("\r\n") - 1 + body_len; + reply->data = talloc_asprintf(mem_ctx, "%s\r\n%s", headers, body); if (reply->data == NULL) { - return EINVAL; + return ENOMEM; } return EOK; -- 2.9.3