From 300b9e9217ee1ed8d845ed2370c5ccf5c87afb36 Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Fri, 24 Feb 2017 10:40:43 +0100 Subject: tcurl: add support for ssl and raw output At first, this patch separates curl_easy handle from the multi-handle processing and makes it encapsulated in custom tcurl_request structure. This allows us to separate protocol initialization from its asynchonous logic which gives us the ability to set different options for each request without over-extending the parameter list. In this patch we implement options for peer verification for TLS-enabled protocols and to return response with body and headers together. Reviewed-by: Simo Sorce Reviewed-by: Jakub Hrozek --- src/util/tev_curl.h | 172 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 153 insertions(+), 19 deletions(-) (limited to 'src/util/tev_curl.h') diff --git a/src/util/tev_curl.h b/src/util/tev_curl.h index 444eb286e..933abcb9b 100644 --- a/src/util/tev_curl.h +++ b/src/util/tev_curl.h @@ -27,14 +27,16 @@ #include "util/sss_iobuf.h" +struct tcurl_request; + /** - * @brief Supported HTTP requests + * @brief Supported HTTP methods */ -enum tcurl_http_request { +enum tcurl_http_method { TCURL_HTTP_GET, TCURL_HTTP_PUT, - TCURL_HTTP_DELETE, TCURL_HTTP_POST, + TCURL_HTTP_DELETE, }; /** @@ -45,17 +47,96 @@ enum tcurl_http_request { struct tcurl_ctx *tcurl_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev); +/** + * @brief Run a single asynchronous TCURL request. + * + * If the libcurl processing succeeds but we obtain a protocol error we still + * mark the tevent request as successful. The protocol error is return from + * @tcurl_request_recv as an output parameter. + * + * @param[in] mem_ctx The talloc context that owns the request + * @param[in] ev Event loop context + * @param[in] tctx Use tcurl_init to get this context + * @param[in] tcurl_req TCURL request + * @param[in] timeout The request timeout in seconds. Use 0 if you want + * to use the default libcurl timeout. + * + * @returns A tevent request or NULL on allocation error. On other errors, we + * try to set the errno as event error code and run it to completion so that + * the programmer can use tcurl_request_recv to read the error code. + * + * @see tcurl_init + * @see tcurl_http + * @see tcurl_request_recv + */ +struct tevent_req * +tcurl_request_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tcurl_ctx *tcurl_ctx, + struct tcurl_request *tcurl_req, + long int timeout); + +/** + * @brief Receive a result of a single asynchronous TCURL request. + * + * @param[in] mem_ctx The talloc context that owns the response + * @param[in] req The request previously obtained with tcurl_request_send + * @param[out] _response Response to the request + * @param[out] _response_code Protocol response code (may indicate a protocl error) + * + * @returns The error code of the curl request (not the HTTP code!) + */ +errno_t tcurl_request_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct sss_iobuf **_response, + int *_response_code); + +/** + * @brief Create a HTTP request. + * + * Use this if you need better control over the request options. + * + * Headers are a NULL-terminated array of strings such as: + * static const char *headers[] = { + * "Content-type: application/octet-stream", + * NULL, + * }; + * + * @param[in] mem_ctx The talloc context that owns the tcurl_request + * @param[in] method TCURL HTTP method + * @param[in] socket_path The path to the UNIX socket to forward the + * request to, may be NULL. + * @param[in] url The request URL, cannot be NULL. + * @param[in] headers A NULL-terminated array of strings to use + * as additional HTTP headers. Pass NULL if you + * don't need any additional headers. + * @param[in] body The HTTP request input data. For some request + * types like DELETE, this is OK to leave as NULL. + * + * @returns A tcurl_request that can be later started with tcurl_request_send + * or NULL on error. + * + * @see tcurl_init + * @see tcurl_request_send + * @see tcurl_request_recv + */ +struct tcurl_request *tcurl_http(TALLOC_CTX *mem_ctx, + enum tcurl_http_method method, + const char *socket_path, + const char *url, + const char **headers, + struct sss_iobuf *body); + /** * @brief Run a single asynchronous HTTP request. * - * Currently only UNIX sockets at socket_path are supported. + * Use this if you do not need control over additional request options. * * If the request runs into completion, but reports a failure with HTTP return * code, the request will be marked as done. Only if the request cannot run at * all (if e.g. the socket is unreachable), the request will fail completely. * - * Headers are a NULL-terminated - * array of strings such as: + * Headers are a NULL-terminated array of strings such as: * static const char *headers[] = { * "Content-type: application/octet-stream", * NULL, @@ -63,15 +144,15 @@ struct tcurl_ctx *tcurl_init(TALLOC_CTX *mem_ctx, * * @param[in] mem_ctx The talloc context that owns the iobuf * @param[in] ev Event loop context - * @param[in] tctx Use tcurl_init to get this context - * @param[in] req_type The request type + * @param[in] tcurl_ctx Use tcurl_init to get this context + * @param[in] method HTTP method * @param[in] socket_path The path to the UNIX socket to forward the - * request to - * @param[in] url The request URL + * request to, may be NULL. + * @param[in] url The request URL, cannot be NULL. * @param[in] headers A NULL-terminated array of strings to use * as additional HTTP headers. Pass NULL if you * don't need any additional headers. - * @param[in] req_data The HTTP request input data. For some request + * @param[in] body The HTTP request input data. For some request * types like DELETE, this is OK to leave as NULL. * @param[in] timeout The request timeout in seconds. Use 0 if you want * to use the default libcurl timeout. @@ -85,12 +166,12 @@ struct tcurl_ctx *tcurl_init(TALLOC_CTX *mem_ctx, */ struct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct tcurl_ctx *tctx, - enum tcurl_http_request req_type, + struct tcurl_ctx *tcurl_ctx, + enum tcurl_http_method method, const char *socket_path, const char *url, - const char *headers[], - struct sss_iobuf *req_data, + const char **headers, + struct sss_iobuf *body, int timeout); /** @@ -104,9 +185,62 @@ struct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx, * * @returns The error code of the curl request (not the HTTP code!) */ -int tcurl_http_recv(TALLOC_CTX *mem_ctx, - struct tevent_req *req, - int *_http_code, - struct sss_iobuf **_outbuf); +errno_t tcurl_http_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + int *_http_code, + struct sss_iobuf **_response); + +/** + * @brief We are usually interested only in the reply body without protocol + * headers. Call this function on tcurl_request, if you want to include + * complete protocol response in the output buffer. + * + * @param[in] tcurl_request + * + * @returns errno code + * + * @see tcurl_http + */ +errno_t tcurl_req_enable_rawoutput(struct tcurl_request *tcurl_req); + +/** + * @brief TLS is enabled automatically by providing an URL that points to + * TLS-enabled protocol such as https. If you want to provide different + * path to CA directory or disable peer/hostname check explicitly, use + * this function on tcurl_request. + * + * @param[in] tcurl_request + * @param[in] capath Path to directory containing installed CA certificates. + * If not set, libcurl default is used. + * @param[ing cacert CA certificate. If NULL it is found in @capath. + * @param[in] verify_peer If false, the peer certificate is not verified. + * @param[in] verify_host If false, the host name provided in remote + * certificate may differ from the actual host name. + * + * @returns errno code + * + * @see tcurl_http + */ +errno_t tcurl_req_verify_peer(struct tcurl_request *tcurl_req, + const char *capath, + const char *cacert, + bool verify_peer, + bool verify_host); +/** + * @brief Some server require client verification during TLS setup. You can + * provide path to client's certificate file. If this file does not contain + * private key, you can specify a different file the holds the private key. + * + * @param[in] tcurl_request + * @param[in] cert Path to client's certificate. + * @param[in] key Path to client's private key. + * + * @returns errno code + * + * @see tcurl_http + */ +errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req, + const char *cert, + const char *key); #endif /* __TEV_CURL_H */ -- cgit